Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include "SkCodec_libbmp.h" | 8 #include "SkCodec_libbmp.h" |
| 9 #include "SkCodecPriv.h" | 9 #include "SkCodecPriv.h" |
| 10 #include "SkColorPriv.h" | 10 #include "SkColorPriv.h" |
| 11 #include "SkStream.h" | 11 #include "SkStream.h" |
| 12 | 12 |
| 13 /* | 13 /* |
| 14 * | 14 * |
| 15 * Checks if the conversion between the input image and the requested output | 15 * Checks if the conversion between the input image and the requested output |
| 16 * image has been implemented | 16 * image has been implemented |
| 17 * | 17 * |
| 18 */ | 18 */ |
| 19 static bool conversion_possible(const SkImageInfo& dst, | 19 static bool conversion_possible(const SkImageInfo& dst, |
| 20 const SkImageInfo& src) { | 20 const SkImageInfo& src) { |
| 21 // All of the swizzles convert to kN32 | 21 // Ensure that the profile type is unchanged |
| 22 // TODO: Update this when more swizzles are supported | 22 if (dst.profileType() != src.profileType()) { |
| 23 if (kN32_SkColorType != dst.colorType()) { | |
| 24 return false; | 23 return false; |
| 25 } | 24 } |
| 26 // Support the swizzle if the requested alpha type is the same as our guess | 25 |
| 27 // for the input alpha type | 26 // Check for supported color and alpha types |
| 28 if (src.alphaType() == dst.alphaType()) { | 27 switch (dst.colorType()) { |
| 29 return true; | 28 case kN32_SkColorType: |
| 29 return src.alphaType() == dst.alphaType() || | |
| 30 (kPremul_SkAlphaType == dst.alphaType() && | |
| 31 kUnpremul_SkAlphaType == src.alphaType()); | |
| 32 case kRGB_565_SkColorType: | |
| 33 return src.alphaType() == dst.alphaType() && | |
| 34 kOpaque_SkAlphaType == dst.alphaType(); | |
| 35 default: | |
| 36 return false; | |
| 30 } | 37 } |
| 31 // TODO: Support more swizzles, especially premul | |
| 32 return false; | |
| 33 } | 38 } |
| 34 | 39 |
| 35 /* | 40 /* |
| 36 * | 41 * |
| 37 * Defines the version and type of the second bitmap header | 42 * Defines the version and type of the second bitmap header |
| 38 * | 43 * |
| 39 */ | 44 */ |
| 40 enum BitmapHeaderType { | 45 enum BitmapHeaderType { |
| 41 kInfoV1_BitmapHeaderType, | 46 kInfoV1_BitmapHeaderType, |
| 42 kInfoV2_BitmapHeaderType, | 47 kInfoV2_BitmapHeaderType, |
| (...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 240 } | 245 } |
| 241 static const int kBmpMaxDim = 1 << 16; | 246 static const int kBmpMaxDim = 1 << 16; |
| 242 if (width < 0 || width >= kBmpMaxDim || height >= kBmpMaxDim) { | 247 if (width < 0 || width >= kBmpMaxDim || height >= kBmpMaxDim) { |
| 243 // TODO: Decide if we want to support really large bmps. | 248 // TODO: Decide if we want to support really large bmps. |
| 244 SkDebugf("Error: invalid bitmap dimensions.\n"); | 249 SkDebugf("Error: invalid bitmap dimensions.\n"); |
| 245 return NULL; | 250 return NULL; |
| 246 } | 251 } |
| 247 | 252 |
| 248 // Create mask struct | 253 // Create mask struct |
| 249 SkMasks::InputMasks inputMasks; | 254 SkMasks::InputMasks inputMasks; |
| 250 memset(&inputMasks, 0, 4*sizeof(uint32_t)); | 255 memset(&inputMasks, 0, sizeof(SkMasks::InputMasks)); |
| 251 | 256 |
| 252 // Determine the input compression format and set bit masks if necessary | 257 // Determine the input compression format and set bit masks if necessary |
| 253 uint32_t maskBytes = 0; | 258 uint32_t maskBytes = 0; |
| 254 BitmapInputFormat inputFormat = kUnknown_BitmapInputFormat; | 259 BitmapInputFormat inputFormat = kUnknown_BitmapInputFormat; |
| 255 switch (compression) { | 260 switch (compression) { |
| 256 case kNone_BitmapCompressionMethod: | 261 case kNone_BitmapCompressionMethod: |
| 257 inputFormat = kStandard_BitmapInputFormat; | 262 inputFormat = kStandard_BitmapInputFormat; |
| 258 break; | 263 break; |
| 259 case k8BitRLE_BitmapCompressionMethod: | 264 case k8BitRLE_BitmapCompressionMethod: |
| 260 if (bitsPerPixel != 8) { | 265 if (bitsPerPixel != 8) { |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 385 } | 390 } |
| 386 | 391 |
| 387 // Check that input bit masks are valid and create the masks object | 392 // Check that input bit masks are valid and create the masks object |
| 388 SkAutoTDelete<SkMasks> | 393 SkAutoTDelete<SkMasks> |
| 389 masks(SkMasks::CreateMasks(inputMasks, bitsPerPixel)); | 394 masks(SkMasks::CreateMasks(inputMasks, bitsPerPixel)); |
| 390 if (NULL == masks) { | 395 if (NULL == masks) { |
| 391 SkDebugf("Error: invalid input masks.\n"); | 396 SkDebugf("Error: invalid input masks.\n"); |
| 392 return NULL; | 397 return NULL; |
| 393 } | 398 } |
| 394 | 399 |
| 395 // Process the color table | 400 // Check for a valid number of total bytes when in RLE mode |
| 396 uint32_t colorBytes = 0; | 401 if (totalBytes <= offset && kRLE_BitmapInputFormat == inputFormat) { |
| 397 SkPMColor* colorTable = NULL; | 402 SkDebugf("Error: RLE requires valid input size.\n"); |
| 398 if (bitsPerPixel < 16) { | |
| 399 // Verify the number of colors for the color table | |
| 400 const uint32_t maxColors = 1 << bitsPerPixel; | |
| 401 // Zero is a default for maxColors | |
| 402 // Also set numColors to maxColors when input is too large | |
| 403 if (numColors <= 0 || numColors > maxColors) { | |
| 404 numColors = maxColors; | |
| 405 } | |
| 406 colorTable = SkNEW_ARRAY(SkPMColor, maxColors); | |
| 407 | |
| 408 // Construct the color table | |
| 409 colorBytes = numColors * bytesPerColor; | |
| 410 SkAutoTDeleteArray<uint8_t> cBuffer(SkNEW_ARRAY(uint8_t, colorBytes)); | |
| 411 if (stream->read(cBuffer.get(), colorBytes) != colorBytes) { | |
| 412 SkDebugf("Error: unable to read color table.\n"); | |
| 413 return NULL; | |
| 414 } | |
| 415 | |
| 416 // Fill in the color table (colors are stored unpremultiplied) | |
| 417 uint32_t i = 0; | |
| 418 for (; i < numColors; i++) { | |
| 419 uint8_t blue = get_byte(cBuffer.get(), i*bytesPerColor); | |
| 420 uint8_t green = get_byte(cBuffer.get(), i*bytesPerColor + 1); | |
| 421 uint8_t red = get_byte(cBuffer.get(), i*bytesPerColor + 2); | |
| 422 uint8_t alpha = 0xFF; | |
| 423 if (kOpaque_SkAlphaType != alphaType) { | |
| 424 alpha = (inputMasks.alpha >> 24) & | |
| 425 get_byte(cBuffer.get(), i*bytesPerColor + 3); | |
| 426 } | |
| 427 // Store the unpremultiplied color | |
| 428 colorTable[i] = SkPackARGB32NoCheck(alpha, red, green, blue); | |
| 429 } | |
| 430 | |
| 431 // To avoid segmentation faults on bad pixel data, fill the end of the | |
| 432 // color table with black. This is the same the behavior as the | |
| 433 // chromium decoder. | |
| 434 for (; i < maxColors; i++) { | |
| 435 colorTable[i] = SkPackARGB32NoCheck(0xFF, 0, 0, 0); | |
| 436 } | |
| 437 } | |
| 438 | |
| 439 // Ensure that the stream now points to the start of the pixel array | |
| 440 uint32_t bytesRead = kBmpHeaderBytes + infoBytes + maskBytes + colorBytes; | |
| 441 | |
| 442 // Check that we have not read past the pixel array offset | |
| 443 if(bytesRead > offset) { | |
| 444 // This may occur on OS 2.1 and other old versions where the color | |
| 445 // table defaults to max size, and the bmp tries to use a smaller color | |
| 446 // table. This is invalid, and our decision is to indicate an error, | |
| 447 // rather than try to guess the intended size of the color table and | |
| 448 // rewind the stream to display the image. | |
| 449 SkDebugf("Error: pixel data offset less than header size.\n"); | |
| 450 return NULL; | 403 return NULL; |
| 451 } | 404 } |
| 405 const size_t RLEBytes = totalBytes - offset; | |
| 452 | 406 |
| 453 // Skip to the start of the pixel array | 407 // Calculate the number of bytes read so far |
| 454 if (stream->skip(offset - bytesRead) != offset - bytesRead) { | 408 const uint32_t bytesRead = kBmpHeaderBytes + infoBytes + maskBytes; |
| 455 SkDebugf("Error: unable to skip to image data.\n"); | 409 if (offset < bytesRead) { |
| 456 return NULL; | 410 SkDebugf("Error: pixel data offset less than header size.\n"); |
| 457 } | |
| 458 | |
| 459 // Remaining bytes is only used for RLE | |
| 460 const int remainingBytes = totalBytes - offset; | |
| 461 if (remainingBytes <= 0 && kRLE_BitmapInputFormat == inputFormat) { | |
| 462 SkDebugf("Error: RLE requires valid input size.\n"); | |
| 463 return NULL; | 411 return NULL; |
| 464 } | 412 } |
| 465 | 413 |
| 466 // Return the codec | 414 // Return the codec |
| 467 // We will use ImageInfo to store width, height, and alpha type. We will | 415 // We will use ImageInfo to store width, height, and alpha type. We will |
| 468 // choose kN32_SkColorType as the input color type because that is the | 416 // set color type to kN32_SkColorType because that should be the default |
|
scroggo
2015/03/18 14:59:32
This doesn't need to be fixed in this CL, but I ta
msarett
2015/03/18 15:57:00
That's a good point, and something we should proba
| |
| 469 // expected choice for a destination color type. In reality, the input | 417 // output. |
| 470 // color type has many possible formats. | |
| 471 const SkImageInfo& imageInfo = SkImageInfo::Make(width, height, | 418 const SkImageInfo& imageInfo = SkImageInfo::Make(width, height, |
| 472 kN32_SkColorType, alphaType); | 419 kN32_SkColorType, alphaType); |
| 473 return SkNEW_ARGS(SkBmpCodec, (imageInfo, stream, bitsPerPixel, | 420 return SkNEW_ARGS(SkBmpCodec, (imageInfo, stream, bitsPerPixel, |
| 474 inputFormat, masks.detach(), colorTable, | 421 inputFormat, masks.detach(), numColors, |
| 475 rowOrder, remainingBytes)); | 422 bytesPerColor, offset - bytesRead, |
| 423 rowOrder, RLEBytes)); | |
| 476 } | 424 } |
| 477 | 425 |
| 478 /* | 426 /* |
| 479 * | 427 * |
| 480 * Creates an instance of the decoder | 428 * Creates an instance of the decoder |
| 481 * Called only by NewFromStream | 429 * Called only by NewFromStream |
| 482 * | 430 * |
| 483 */ | 431 */ |
| 484 SkBmpCodec::SkBmpCodec(const SkImageInfo& info, SkStream* stream, | 432 SkBmpCodec::SkBmpCodec(const SkImageInfo& info, SkStream* stream, |
| 485 uint16_t bitsPerPixel, BitmapInputFormat inputFormat, | 433 uint16_t bitsPerPixel, BitmapInputFormat inputFormat, |
| 486 SkMasks* masks, SkPMColor* colorTable, | 434 SkMasks* masks, uint32_t numColors, |
| 487 RowOrder rowOrder, | 435 uint32_t bytesPerColor, uint32_t offset, |
| 488 const uint32_t remainingBytes) | 436 RowOrder rowOrder, size_t RLEBytes) |
| 489 : INHERITED(info, stream) | 437 : INHERITED(info, stream) |
| 490 , fBitsPerPixel(bitsPerPixel) | 438 , fBitsPerPixel(bitsPerPixel) |
| 491 , fInputFormat(inputFormat) | 439 , fInputFormat(inputFormat) |
| 492 , fMasks(masks) | 440 , fMasks(masks) |
| 493 , fColorTable(colorTable) | 441 , fColorTable(NULL) |
| 442 , fNumColors(numColors) | |
| 443 , fBytesPerColor(bytesPerColor) | |
| 444 , fOffset(offset) | |
| 494 , fRowOrder(rowOrder) | 445 , fRowOrder(rowOrder) |
| 495 , fRemainingBytes(remainingBytes) | 446 , fRLEBytes(RLEBytes) |
| 496 {} | 447 {} |
| 497 | 448 |
| 498 /* | 449 /* |
| 499 * | 450 * |
| 500 * Initiates the bitmap decode | 451 * Initiates the bitmap decode |
| 501 * | 452 * |
| 502 */ | 453 */ |
| 503 SkCodec::Result SkBmpCodec::onGetPixels(const SkImageInfo& dstInfo, | 454 SkCodec::Result SkBmpCodec::onGetPixels(const SkImageInfo& dstInfo, |
| 504 void* dst, size_t dstRowBytes, | 455 void* dst, size_t dstRowBytes, |
| 505 const Options&, | 456 const Options&, |
| 506 SkPMColor*, int*) { | 457 SkPMColor*, int*) { |
| 458 // Check for proper input and output formats | |
| 507 if (!this->rewindIfNeeded()) { | 459 if (!this->rewindIfNeeded()) { |
| 508 return kCouldNotRewind; | 460 return kCouldNotRewind; |
| 509 } | 461 } |
| 510 if (dstInfo.dimensions() != this->getOriginalInfo().dimensions()) { | 462 if (dstInfo.dimensions() != this->getOriginalInfo().dimensions()) { |
| 511 SkDebugf("Error: scaling not supported.\n"); | 463 SkDebugf("Error: scaling not supported.\n"); |
| 512 return kInvalidScale; | 464 return kInvalidScale; |
| 513 } | 465 } |
| 514 if (!conversion_possible(dstInfo, this->getOriginalInfo())) { | 466 if (!conversion_possible(dstInfo, this->getOriginalInfo())) { |
| 515 SkDebugf("Error: cannot convert input type to output type.\n"); | 467 SkDebugf("Error: cannot convert input type to output type.\n"); |
| 516 return kInvalidConversion; | 468 return kInvalidConversion; |
| 517 } | 469 } |
| 518 | 470 |
| 471 // Create the color table if necessary and prepare the stream for decode | |
| 472 if (!createColorTable(dstInfo.alphaType())) { | |
| 473 SkDebugf("Error: could not create color table.\n"); | |
| 474 return kInvalidInput; | |
| 475 } | |
| 476 | |
| 477 // Perform the decode | |
| 519 switch (fInputFormat) { | 478 switch (fInputFormat) { |
| 520 case kBitMask_BitmapInputFormat: | 479 case kBitMask_BitmapInputFormat: |
| 521 return decodeMask(dstInfo, dst, dstRowBytes); | 480 return decodeMask(dstInfo, dst, dstRowBytes); |
| 522 case kRLE_BitmapInputFormat: | 481 case kRLE_BitmapInputFormat: |
| 523 return decodeRLE(dstInfo, dst, dstRowBytes); | 482 return decodeRLE(dstInfo, dst, dstRowBytes); |
| 524 case kStandard_BitmapInputFormat: | 483 case kStandard_BitmapInputFormat: |
| 525 return decode(dstInfo, dst, dstRowBytes); | 484 return decode(dstInfo, dst, dstRowBytes); |
| 526 default: | 485 default: |
| 527 SkASSERT(false); | 486 SkASSERT(false); |
| 528 return kInvalidInput; | 487 return kInvalidInput; |
| 529 } | 488 } |
| 530 } | 489 } |
| 531 | 490 |
| 532 /* | 491 /* |
| 533 * | 492 * |
| 493 * Process the color table for the bmp input | |
| 494 * | |
| 495 */ | |
| 496 bool SkBmpCodec::createColorTable(SkAlphaType alphaType) { | |
| 497 | |
| 498 // Allocate memory for color table | |
| 499 uint32_t colorBytes = 0; | |
| 500 uint32_t maxColors = fBitsPerPixel <= 8 ? 1 << fBitsPerPixel : 0; | |
|
scroggo
2015/03/18 14:59:32
nit: const
msarett
2015/03/18 15:57:00
Done.
| |
| 501 SkPMColor colorTable[maxColors]; | |
| 502 if (fBitsPerPixel <= 8) { | |
| 503 // Read the color table from the stream | |
| 504 colorBytes = fNumColors * fBytesPerColor; | |
|
scroggo
2015/03/18 14:59:32
Is it possible for fNumColors to be greater than m
msarett
2015/03/18 15:57:00
There was code that fixes this possibility that se
| |
| 505 SkAutoTDeleteArray<uint8_t> cBuffer(SkNEW_ARRAY(uint8_t, colorBytes)); | |
| 506 if (stream()->read(cBuffer.get(), colorBytes) != colorBytes) { | |
| 507 SkDebugf("Error: unable to read color table.\n"); | |
| 508 return NULL; | |
| 509 } | |
| 510 | |
| 511 // Fill in the color table | |
| 512 uint32_t i = 0; | |
| 513 for (; i < fNumColors; i++) { | |
| 514 uint8_t blue = get_byte(cBuffer.get(), i*fBytesPerColor); | |
| 515 uint8_t green = get_byte(cBuffer.get(), i*fBytesPerColor + 1); | |
| 516 uint8_t red = get_byte(cBuffer.get(), i*fBytesPerColor + 2); | |
| 517 uint8_t alpha; | |
| 518 switch (alphaType) { | |
| 519 case kOpaque_SkAlphaType: | |
| 520 colorTable[i] = SkPackARGB32NoCheck(0xFF, red, green, | |
| 521 blue); | |
| 522 break; | |
| 523 case kUnpremul_SkAlphaType: | |
| 524 alpha = (fMasks->getAlphaMask() >> 24) & | |
| 525 get_byte(cBuffer.get(), i*fBytesPerColor + 3); | |
| 526 colorTable[i] = SkPackARGB32NoCheck(alpha, red, green, | |
| 527 blue); | |
| 528 break; | |
| 529 case kPremul_SkAlphaType: | |
| 530 alpha = (fMasks->getAlphaMask() >> 24) & | |
| 531 get_byte(cBuffer.get(), i*fBytesPerColor + 3); | |
| 532 colorTable[i] = SkPreMultiplyARGB(alpha, red, green, | |
|
scroggo
2015/03/18 14:59:32
nit: We could handle both premul and unpremul with
msarett
2015/03/18 15:57:00
Maybe this is better?
| |
| 533 blue); | |
| 534 break; | |
| 535 default: | |
| 536 // This should not be reached because conversion possible | |
| 537 // should fail if the alpha type is not one of the above | |
| 538 // values. | |
| 539 SkASSERT(false); | |
| 540 break; | |
| 541 } | |
| 542 } | |
| 543 | |
| 544 // To avoid segmentation faults on bad pixel data, fill the end of the | |
| 545 // color table with black. This is the same the behavior as the | |
| 546 // chromium decoder. | |
| 547 for (; i < maxColors; i++) { | |
| 548 colorTable[i] = SkPackARGB32NoCheck(0xFF, 0, 0, 0); | |
| 549 } | |
| 550 } | |
| 551 | |
| 552 // Check that we have not read past the pixel array offset | |
| 553 if(fOffset < colorBytes) { | |
| 554 // This may occur on OS 2.1 and other old versions where the color | |
| 555 // table defaults to max size, and the bmp tries to use a smaller color | |
| 556 // table. This is invalid, and our decision is to indicate an error, | |
| 557 // rather than try to guess the intended size of the color table. | |
| 558 SkDebugf("Error: pixel data offset less than color table size.\n"); | |
| 559 return NULL; | |
| 560 } | |
| 561 | |
| 562 // After reading the color table, skip to the start of the pixel array | |
| 563 if (stream()->skip(fOffset - colorBytes) != fOffset - colorBytes) { | |
| 564 SkDebugf("Error: unable to skip to image data.\n"); | |
| 565 return false; | |
| 566 } | |
| 567 | |
| 568 // Set the color table and return true on success | |
| 569 fColorTable.reset(SkNEW_ARGS(SkColorTable, (colorTable, maxColors))); | |
| 570 return true; | |
| 571 } | |
| 572 | |
| 573 /* | |
| 574 * | |
| 534 * Performs the bitmap decoding for bit masks input format | 575 * Performs the bitmap decoding for bit masks input format |
| 535 * | 576 * |
| 536 */ | 577 */ |
| 537 SkCodec::Result SkBmpCodec::decodeMask(const SkImageInfo& dstInfo, | 578 SkCodec::Result SkBmpCodec::decodeMask(const SkImageInfo& dstInfo, |
| 538 void* dst, size_t dstRowBytes) { | 579 void* dst, size_t dstRowBytes) { |
| 539 // Set constant values | 580 // Set constant values |
| 540 const int width = dstInfo.width(); | 581 const int width = dstInfo.width(); |
| 541 const int height = dstInfo.height(); | 582 const int height = dstInfo.height(); |
| 542 const size_t rowBytes = SkAlign4(compute_row_bytes(width, fBitsPerPixel)); | 583 const size_t rowBytes = SkAlign4(compute_row_bytes(width, fBitsPerPixel)); |
| 543 | 584 |
| 544 // Allocate space for a row buffer and a source for the swizzler | 585 // Allocate a buffer large enough to hold the full input stream |
|
scroggo
2015/03/18 14:59:32
nit: this holds the whole image, not the whole str
msarett
2015/03/18 15:57:00
Done.
| |
| 545 SkAutoTDeleteArray<uint8_t> srcBuffer(SkNEW_ARRAY(uint8_t, rowBytes)); | 586 SkAutoTDeleteArray<uint8_t> |
| 587 srcBuffer(SkNEW_ARRAY(uint8_t, height*rowBytes)); | |
| 588 uint8_t* srcRow = srcBuffer.get(); | |
| 546 | 589 |
| 547 // Get the destination start row and delta | 590 // Get the destination start row and delta |
| 591 SkPMColor* dstStart; | |
| 548 SkPMColor* dstRow; | 592 SkPMColor* dstRow; |
| 549 int delta; | 593 int delta; |
| 550 if (kTopDown_RowOrder == fRowOrder) { | 594 if (kTopDown_RowOrder == fRowOrder) { |
| 551 dstRow = (SkPMColor*) dst; | 595 dstStart = (SkPMColor*) dst; |
| 596 dstRow = dstStart; | |
| 552 delta = (int) dstRowBytes; | 597 delta = (int) dstRowBytes; |
| 553 } else { | 598 } else { |
| 554 dstRow = (SkPMColor*) SkTAddOffset<void>(dst, (height-1) * dstRowBytes); | 599 dstStart = (SkPMColor*) SkTAddOffset<void>( |
| 600 dst, (height - 1) * dstRowBytes); | |
| 601 dstRow = dstStart; | |
| 555 delta = -((int) dstRowBytes); | 602 delta = -((int) dstRowBytes); |
| 556 } | 603 } |
| 557 | 604 |
| 558 // Create the swizzler | 605 // Create the swizzler |
| 559 SkMaskSwizzler* swizzler = SkMaskSwizzler::CreateMaskSwizzler( | 606 SkAutoTDelete<SkMaskSwizzler> maskSwizzler( |
| 560 dstInfo, fMasks, fBitsPerPixel); | 607 SkMaskSwizzler::CreateMaskSwizzler(dstInfo, fMasks, fBitsPerPixel)); |
| 561 | 608 |
| 562 // Iterate over rows of the image | 609 // Iterate over rows of the image |
| 563 bool transparent = true; | 610 bool transparent = true; |
| 564 for (int y = 0; y < height; y++) { | 611 for (int y = 0; y < height; y++) { |
| 565 // Read a row of the input | 612 // Read a row of the input |
| 566 if (stream()->read(srcBuffer.get(), rowBytes) != rowBytes) { | 613 if (stream()->read(srcRow, rowBytes) != rowBytes) { |
| 567 SkDebugf("Warning: incomplete input stream.\n"); | 614 SkDebugf("Warning: incomplete input stream.\n"); |
| 568 return kIncompleteInput; | 615 return kIncompleteInput; |
| 569 } | 616 } |
| 570 | 617 |
| 571 // Decode the row in destination format | 618 // Decode the row in destination format |
| 572 SkSwizzler::ResultAlpha r = swizzler->next(dstRow, srcBuffer.get()); | 619 SkSwizzler::ResultAlpha r = maskSwizzler->next(dstRow, srcRow); |
|
scroggo
2015/03/18 14:59:32
This is confusing. The second parameter for SkMask
msarett
2015/03/18 15:57:00
Yes I will unify. And I think this will fix the i
scroggo
2015/03/18 16:02:06
I know I told you that SkSwizzler::next() should t
msarett
2015/03/18 16:08:17
I would agree that src should always be the first
| |
| 573 transparent &= SkSwizzler::IsTransparent(r); | 620 transparent &= SkSwizzler::IsTransparent(r); |
| 574 | 621 |
| 575 // Move to the next row | 622 // Move to the next row |
| 576 dstRow = SkTAddOffset<SkPMColor>(dstRow, delta); | 623 dstRow = SkTAddOffset<SkPMColor>(dstRow, delta); |
|
scroggo
2015/03/18 14:59:32
This isn't new to this CL, but if delta is negativ
msarett
2015/03/18 15:57:00
It does work. But it seems that this was by luck
| |
| 624 srcRow = SkTAddOffset<uint8_t>(srcRow, rowBytes); | |
| 577 } | 625 } |
| 578 | 626 |
| 579 // Some fully transparent bmp images are intended to be opaque. Here, we | 627 // Some fully transparent bmp images are intended to be opaque. Here, we |
| 580 // correct for this possibility. | 628 // correct for this possibility. |
| 581 dstRow = (SkPMColor*) dst; | |
| 582 if (transparent) { | 629 if (transparent) { |
| 630 const SkImageInfo& opaqueInfo = | |
| 631 dstInfo.makeAlphaType(kOpaque_SkAlphaType); | |
| 632 SkAutoTDelete<SkMaskSwizzler> opaqueSwizzler( | |
| 633 SkMaskSwizzler::CreateMaskSwizzler(opaqueInfo, fMasks, | |
| 634 fBitsPerPixel)); | |
| 635 srcRow = srcBuffer.get(); | |
| 636 dstRow = dstStart; | |
| 583 for (int y = 0; y < height; y++) { | 637 for (int y = 0; y < height; y++) { |
| 584 for (int x = 0; x < width; x++) { | 638 // Decode the row in new format |
| 585 dstRow[x] |= 0xFF000000; | 639 opaqueSwizzler->next(dstRow, srcRow); |
| 586 } | 640 |
| 587 dstRow = SkTAddOffset<SkPMColor>(dstRow, dstRowBytes); | 641 // Move to the next row |
| 642 dstRow = SkTAddOffset<SkPMColor>(dstRow, delta); | |
| 643 srcRow = SkTAddOffset<uint8_t>(srcRow, rowBytes); | |
| 588 } | 644 } |
| 589 } | 645 } |
| 590 | 646 |
| 591 // Finished decoding the entire image | 647 // Finished decoding the entire image |
| 592 return kSuccess; | 648 return kSuccess; |
| 593 } | 649 } |
| 594 | 650 |
| 595 /* | 651 /* |
| 596 * | 652 * |
| 597 * Set an RLE pixel using the color table | 653 * Set an RLE pixel using the color table |
| 598 * | 654 * |
| 599 */ | 655 */ |
| 600 void SkBmpCodec::setRLEPixel(SkPMColor* dst, size_t dstRowBytes, int height, | 656 void SkBmpCodec::setRLEPixel(SkPMColor* dst, size_t dstRowBytes, |
| 601 uint32_t x, uint32_t y, uint8_t index) { | 657 const SkImageInfo& dstInfo, uint32_t x, uint32_t y, |
| 658 uint8_t index) { | |
| 659 // Set the row | |
| 660 int height = dstInfo.height(); | |
| 661 int row; | |
| 602 if (kBottomUp_RowOrder == fRowOrder) { | 662 if (kBottomUp_RowOrder == fRowOrder) { |
| 603 y = height - y - 1; | 663 row = height - y - 1; |
| 664 } else { | |
| 665 row = y; | |
| 604 } | 666 } |
| 605 SkPMColor* dstRow = SkTAddOffset<SkPMColor>(dst, y * dstRowBytes); | 667 |
| 606 dstRow[x] = fColorTable.get()[index]; | 668 // Set the pixel based on destination color type |
| 669 switch (dstInfo.colorType()) { | |
| 670 case kN32_SkColorType: { | |
| 671 SkPMColor* dstRow = SkTAddOffset<SkPMColor>(dst, | |
| 672 row * (int) dstRowBytes); | |
| 673 dstRow[x] = fColorTable->operator[](index); | |
| 674 break; | |
| 675 } | |
| 676 case kRGB_565_SkColorType: { | |
| 677 uint16_t* dstRow = SkTAddOffset<uint16_t>(dst, | |
| 678 row * (int) dstRowBytes); | |
| 679 dstRow[x] = SkPixel32ToPixel16(fColorTable->operator[](index)); | |
| 680 break; | |
| 681 } | |
| 682 default: | |
| 683 // This case should not be reached. We should catch an invalid | |
| 684 // color type when we check that the conversion is possible. | |
| 685 SkASSERT(false); | |
| 686 break; | |
| 687 } | |
| 607 } | 688 } |
| 608 | 689 |
| 609 /* | 690 /* |
| 691 * | |
| 692 * Set an RLE pixel from R, G, B values | |
| 693 * | |
| 694 */ | |
| 695 void SkBmpCodec::setRLE24Pixel(SkPMColor* dst, size_t dstRowBytes, | |
| 696 const SkImageInfo& dstInfo, uint32_t x, | |
| 697 uint32_t y, uint8_t red, uint8_t green, | |
| 698 uint8_t blue) { | |
| 699 // Set the row | |
| 700 int height = dstInfo.height(); | |
| 701 int row; | |
| 702 if (kBottomUp_RowOrder == fRowOrder) { | |
| 703 row = height - y - 1; | |
| 704 } else { | |
| 705 row = y; | |
| 706 } | |
| 707 | |
| 708 // Set the pixel based on destination color type | |
| 709 switch (dstInfo.colorType()) { | |
| 710 case kN32_SkColorType: { | |
| 711 SkPMColor* dstRow = SkTAddOffset<SkPMColor>(dst, | |
| 712 row * (int) dstRowBytes); | |
| 713 dstRow[x] = SkPackARGB32NoCheck(0xFF, red, green, blue); | |
| 714 break; | |
| 715 } | |
| 716 case kRGB_565_SkColorType: { | |
| 717 uint16_t* dstRow = SkTAddOffset<uint16_t>(dst, | |
| 718 row * (int) dstRowBytes); | |
| 719 dstRow[x] = SkPack888ToRGB16(red, green, blue); | |
| 720 break; | |
| 721 } | |
| 722 default: | |
| 723 // This case should not be reached. We should catch an invalid | |
| 724 // color type when we check that the conversion is possible. | |
| 725 SkASSERT(false); | |
| 726 break; | |
| 727 } | |
| 728 } | |
| 729 | |
| 730 /* | |
| 610 * | 731 * |
| 611 * Performs the bitmap decoding for RLE input format | 732 * Performs the bitmap decoding for RLE input format |
| 612 * RLE decoding is performed all at once, rather than a one row at a time | 733 * RLE decoding is performed all at once, rather than a one row at a time |
| 613 * | 734 * |
| 614 */ | 735 */ |
| 615 SkCodec::Result SkBmpCodec::decodeRLE(const SkImageInfo& dstInfo, | 736 SkCodec::Result SkBmpCodec::decodeRLE(const SkImageInfo& dstInfo, |
| 616 void* dst, size_t dstRowBytes) { | 737 void* dst, size_t dstRowBytes) { |
| 617 // Set RLE flags | 738 // Set RLE flags |
| 618 static const uint8_t RLE_ESCAPE = 0; | 739 static const uint8_t RLE_ESCAPE = 0; |
| 619 static const uint8_t RLE_EOL = 0; | 740 static const uint8_t RLE_EOL = 0; |
| 620 static const uint8_t RLE_EOF = 1; | 741 static const uint8_t RLE_EOF = 1; |
| 621 static const uint8_t RLE_DELTA = 2; | 742 static const uint8_t RLE_DELTA = 2; |
| 622 | 743 |
| 623 // Set constant values | 744 // Set constant values |
| 624 const int width = dstInfo.width(); | 745 const int width = dstInfo.width(); |
| 625 const int height = dstInfo.height(); | 746 const int height = dstInfo.height(); |
| 626 | 747 |
| 627 // Input buffer parameters | 748 // Input buffer parameters |
| 628 uint32_t currByte = 0; | 749 uint32_t currByte = 0; |
| 629 SkAutoTDeleteArray<uint8_t> buffer(SkNEW_ARRAY(uint8_t, fRemainingBytes)); | 750 SkAutoTDeleteArray<uint8_t> buffer(SkNEW_ARRAY(uint8_t, fRLEBytes)); |
| 630 size_t totalBytes = stream()->read(buffer.get(), fRemainingBytes); | 751 size_t totalBytes = stream()->read(buffer.get(), fRLEBytes); |
| 631 if ((uint32_t) totalBytes < fRemainingBytes) { | 752 if (totalBytes < fRLEBytes) { |
| 632 SkDebugf("Warning: incomplete RLE file.\n"); | 753 SkDebugf("Warning: incomplete RLE file.\n"); |
| 633 } else if (totalBytes <= 0) { | 754 } else if (totalBytes <= 0) { |
| 634 SkDebugf("Error: could not read RLE image data.\n"); | 755 SkDebugf("Error: could not read RLE image data.\n"); |
| 635 return kInvalidInput; | 756 return kInvalidInput; |
| 636 } | 757 } |
| 637 | 758 |
| 638 // Destination parameters | 759 // Destination parameters |
| 639 int x = 0; | 760 int x = 0; |
| 640 int y = 0; | 761 int y = 0; |
| 641 // If the code skips pixels, remaining pixels are transparent or black | 762 // If the code skips pixels, remaining pixels are transparent or black |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 700 fBitsPerPixel); | 821 fBitsPerPixel); |
| 701 // Abort if setting numPixels moves us off the edge of the | 822 // Abort if setting numPixels moves us off the edge of the |
| 702 // image. Also abort if there are not enough bytes | 823 // image. Also abort if there are not enough bytes |
| 703 // remaining in the stream to set numPixels. | 824 // remaining in the stream to set numPixels. |
| 704 if (x + numPixels > width || | 825 if (x + numPixels > width || |
| 705 (int) totalBytes - currByte < SkAlign2(rowBytes)) { | 826 (int) totalBytes - currByte < SkAlign2(rowBytes)) { |
| 706 SkDebugf("Warning: invalid RLE input.\n"); | 827 SkDebugf("Warning: invalid RLE input.\n"); |
| 707 return kIncompleteInput; | 828 return kIncompleteInput; |
| 708 } | 829 } |
| 709 // Set numPixels number of pixels | 830 // Set numPixels number of pixels |
| 710 SkPMColor* dstRow = SkTAddOffset<SkPMColor>( | |
| 711 dstPtr, y * dstRowBytes); | |
| 712 while (numPixels > 0) { | 831 while (numPixels > 0) { |
| 713 switch(fBitsPerPixel) { | 832 switch(fBitsPerPixel) { |
| 714 case 4: { | 833 case 4: { |
| 715 SkASSERT(currByte < totalBytes); | 834 SkASSERT(currByte < totalBytes); |
| 716 uint8_t val = buffer.get()[currByte++]; | 835 uint8_t val = buffer.get()[currByte++]; |
| 717 setRLEPixel(dstPtr, dstRowBytes, height, x++, y, | 836 setRLEPixel(dstPtr, dstRowBytes, dstInfo, x++, |
| 718 val >> 4); | 837 y, val >> 4); |
| 719 numPixels--; | 838 numPixels--; |
| 720 if (numPixels != 0) { | 839 if (numPixels != 0) { |
| 721 setRLEPixel(dstPtr, dstRowBytes, height, | 840 setRLEPixel(dstPtr, dstRowBytes, dstInfo, |
| 722 x++, y, val & 0xF); | 841 x++, y, val & 0xF); |
| 723 numPixels--; | 842 numPixels--; |
| 724 } | 843 } |
| 725 break; | 844 break; |
| 726 } | 845 } |
| 727 case 8: | 846 case 8: |
| 728 SkASSERT(currByte < totalBytes); | 847 SkASSERT(currByte < totalBytes); |
| 729 setRLEPixel(dstPtr, dstRowBytes, height, x++, y, | 848 setRLEPixel(dstPtr, dstRowBytes, dstInfo, x++, |
| 730 buffer.get()[currByte++]); | 849 y, buffer.get()[currByte++]); |
| 731 numPixels--; | 850 numPixels--; |
| 732 break; | 851 break; |
| 733 case 24: { | 852 case 24: { |
| 734 SkASSERT(currByte + 2 < totalBytes); | 853 SkASSERT(currByte + 2 < totalBytes); |
| 735 uint8_t blue = buffer.get()[currByte++]; | 854 uint8_t blue = buffer.get()[currByte++]; |
| 736 uint8_t green = buffer.get()[currByte++]; | 855 uint8_t green = buffer.get()[currByte++]; |
| 737 uint8_t red = buffer.get()[currByte++]; | 856 uint8_t red = buffer.get()[currByte++]; |
| 738 SkPMColor color = SkPackARGB32NoCheck( | 857 setRLE24Pixel(dstPtr, dstRowBytes, dstInfo, |
| 739 0xFF, red, green, blue); | 858 x++, y, red, green, blue); |
| 740 dstRow[x++] = color; | |
| 741 numPixels--; | 859 numPixels--; |
| 742 } | 860 } |
| 743 default: | 861 default: |
| 744 SkASSERT(false); | 862 SkASSERT(false); |
| 745 return kInvalidInput; | 863 return kInvalidInput; |
| 746 } | 864 } |
| 747 } | 865 } |
| 748 // Skip a byte if necessary to maintain alignment | 866 // Skip a byte if necessary to maintain alignment |
| 749 if (!SkIsAlign2(rowBytes)) { | 867 if (!SkIsAlign2(rowBytes)) { |
| 750 currByte++; | 868 currByte++; |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 764 // color. | 882 // color. |
| 765 if ((int) totalBytes - currByte < 2) { | 883 if ((int) totalBytes - currByte < 2) { |
| 766 SkDebugf("Warning: incomplete RLE input\n"); | 884 SkDebugf("Warning: incomplete RLE input\n"); |
| 767 return kIncompleteInput; | 885 return kIncompleteInput; |
| 768 } | 886 } |
| 769 | 887 |
| 770 // Fill the pixels up to endX with the specified color | 888 // Fill the pixels up to endX with the specified color |
| 771 uint8_t blue = task; | 889 uint8_t blue = task; |
| 772 uint8_t green = buffer.get()[currByte++]; | 890 uint8_t green = buffer.get()[currByte++]; |
| 773 uint8_t red = buffer.get()[currByte++]; | 891 uint8_t red = buffer.get()[currByte++]; |
| 774 SkPMColor color = SkPackARGB32NoCheck(0xFF, red, green, blue); | |
| 775 SkPMColor* dstRow = | |
| 776 SkTAddOffset<SkPMColor>(dstPtr, y * dstRowBytes); | |
| 777 while (x < endX) { | 892 while (x < endX) { |
| 778 dstRow[x++] = color; | 893 setRLE24Pixel(dstPtr, dstRowBytes, dstInfo, x++, y, red, |
| 894 green, blue); | |
| 779 } | 895 } |
| 780 } else { | 896 } else { |
| 781 // In RLE8 or RLE4, the second byte read gives the index in the | 897 // In RLE8 or RLE4, the second byte read gives the index in the |
| 782 // color table to look up the pixel color. | 898 // color table to look up the pixel color. |
| 783 // RLE8 has one color index that gets repeated | 899 // RLE8 has one color index that gets repeated |
| 784 // RLE4 has two color indexes in the upper and lower 4 bits of | 900 // RLE4 has two color indexes in the upper and lower 4 bits of |
| 785 // the bytes, which are alternated | 901 // the bytes, which are alternated |
| 786 uint8_t indices[2] = { task, task }; | 902 uint8_t indices[2] = { task, task }; |
| 787 if (4 == fBitsPerPixel) { | 903 if (4 == fBitsPerPixel) { |
| 788 indices[0] >>= 4; | 904 indices[0] >>= 4; |
| 789 indices[1] &= 0xf; | 905 indices[1] &= 0xf; |
| 790 } | 906 } |
| 791 | 907 |
| 792 // Set the indicated number of pixels | 908 // Set the indicated number of pixels |
| 793 for (int which = 0; x < endX; x++) { | 909 for (int which = 0; x < endX; x++) { |
| 794 setRLEPixel(dstPtr, dstRowBytes, height, x, y, | 910 setRLEPixel(dstPtr, dstRowBytes, dstInfo, x, y, |
| 795 indices[which]); | 911 indices[which]); |
| 796 which = !which; | 912 which = !which; |
| 797 } | 913 } |
| 798 } | 914 } |
| 799 } | 915 } |
| 800 } | 916 } |
| 801 } | 917 } |
| 802 | 918 |
| 803 /* | 919 /* |
| 804 * | 920 * |
| 805 * Performs the bitmap decoding for standard input format | 921 * Performs the bitmap decoding for standard input format |
| 806 * | 922 * |
| 807 */ | 923 */ |
| 808 SkCodec::Result SkBmpCodec::decode(const SkImageInfo& dstInfo, | 924 SkCodec::Result SkBmpCodec::decode(const SkImageInfo& dstInfo, |
| 809 void* dst, size_t dstRowBytes) { | 925 void* dst, size_t dstRowBytes) { |
| 810 // Set constant values | 926 // Set constant values |
| 811 const int width = dstInfo.width(); | 927 const int width = dstInfo.width(); |
| 812 const int height = dstInfo.height(); | 928 const int height = dstInfo.height(); |
| 813 const size_t rowBytes = SkAlign4(compute_row_bytes(width, fBitsPerPixel)); | 929 const size_t rowBytes = SkAlign4(compute_row_bytes(width, fBitsPerPixel)); |
| 814 const uint32_t alphaMask = fMasks->getAlphaMask(); | |
| 815 | 930 |
| 816 // Get swizzler configuration | 931 // Get swizzler configuration |
| 817 SkSwizzler::SrcConfig config; | 932 SkSwizzler::SrcConfig config; |
| 818 switch (fBitsPerPixel) { | 933 switch (fBitsPerPixel) { |
| 819 case 1: | 934 case 1: |
| 820 config = SkSwizzler::kIndex1; | 935 config = SkSwizzler::kIndex1; |
| 821 break; | 936 break; |
| 822 case 2: | 937 case 2: |
| 823 config = SkSwizzler::kIndex2; | 938 config = SkSwizzler::kIndex2; |
| 824 break; | 939 break; |
| 825 case 4: | 940 case 4: |
| 826 config = SkSwizzler::kIndex4; | 941 config = SkSwizzler::kIndex4; |
| 827 break; | 942 break; |
| 828 case 8: | 943 case 8: |
| 829 config = SkSwizzler::kIndex; | 944 config = SkSwizzler::kIndex; |
| 830 break; | 945 break; |
| 831 case 24: | 946 case 24: |
| 832 config = SkSwizzler::kBGR; | 947 config = SkSwizzler::kBGR; |
| 833 break; | 948 break; |
| 834 case 32: | 949 case 32: |
| 835 if (0 == alphaMask) { | 950 if (kOpaque_SkAlphaType == dstInfo.alphaType()) { |
| 836 config = SkSwizzler::kBGRX; | 951 config = SkSwizzler::kBGRX; |
| 837 } else { | 952 } else { |
| 838 config = SkSwizzler::kBGRA; | 953 config = SkSwizzler::kBGRA; |
| 839 } | 954 } |
| 840 break; | 955 break; |
| 841 default: | 956 default: |
| 842 SkASSERT(false); | 957 SkASSERT(false); |
| 843 return kInvalidInput; | 958 return kInvalidInput; |
| 844 } | 959 } |
| 845 | 960 |
| 846 // Create swizzler | 961 // Create swizzler |
| 847 SkSwizzler* swizzler = SkSwizzler::CreateSwizzler(config, fColorTable.get(), | 962 SkAutoTDelete<SkSwizzler> swizzler(SkSwizzler::CreateSwizzler(config, |
| 848 dstInfo, dst, dstRowBytes, SkImageGenerator::kNo_ZeroInitialized); | 963 fColorTable->readColors(), dstInfo, dst, dstRowBytes, |
| 964 SkImageGenerator::kNo_ZeroInitialized)); | |
| 849 | 965 |
| 850 // Allocate space for a row buffer and a source for the swizzler | 966 // Allocate space for a row buffer and a source for the swizzler |
| 851 SkAutoTDeleteArray<uint8_t> srcBuffer(SkNEW_ARRAY(uint8_t, rowBytes)); | 967 SkAutoTDeleteArray<uint8_t> srcBuffer(SkNEW_ARRAY(uint8_t, rowBytes)); |
| 852 | 968 |
| 853 // Iterate over rows of the image | 969 // Iterate over rows of the image |
| 854 // FIXME: bool transparent = true; | 970 // FIXME: bool transparent = true; |
| 855 for (int y = 0; y < height; y++) { | 971 for (int y = 0; y < height; y++) { |
| 856 // Read a row of the input | 972 // Read a row of the input |
| 857 if (stream()->read(srcBuffer.get(), rowBytes) != rowBytes) { | 973 if (stream()->read(srcBuffer.get(), rowBytes) != rowBytes) { |
| 858 SkDebugf("Warning: incomplete input stream.\n"); | 974 SkDebugf("Warning: incomplete input stream.\n"); |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 895 } | 1011 } |
| 896 dstRow = SkTAddOffset<SkPMColor>(dstRow, dstRowBytes); | 1012 dstRow = SkTAddOffset<SkPMColor>(dstRow, dstRowBytes); |
| 897 } | 1013 } |
| 898 } | 1014 } |
| 899 } | 1015 } |
| 900 */ | 1016 */ |
| 901 | 1017 |
| 902 // Finished decoding the entire image | 1018 // Finished decoding the entire image |
| 903 return kSuccess; | 1019 return kSuccess; |
| 904 } | 1020 } |
| OLD | NEW |