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 // Check for supported color types |
| 22 // TODO: Update this when more swizzles are supported | 22 if (kN32_SkColorType != dst.colorType() && |
| 23 if (kN32_SkColorType != dst.colorType()) { | 23 kRGB_565_SkColorType != dst.colorType()) { |
| 24 return false; | 24 return false; |
| 25 } | 25 } |
| 26 // Support the swizzle if the requested alpha type is the same as our guess | 26 // Support the swizzle if the requested alpha type is the same as our guess |
| 27 // for the input alpha type | 27 // for the input alpha type |
| 28 if (src.alphaType() == dst.alphaType()) { | 28 if (src.alphaType() == dst.alphaType()) { |
| 29 return true; | 29 return true; |
| 30 } | 30 } |
| 31 // TODO: Support more swizzles, especially premul | 31 |
| 32 return false; | 32 // Support premul as the destination when the source is unpremul |
| 33 return premul_and_unpremul(dst.alphaType(), src.alphaType()); | |
| 33 } | 34 } |
| 34 | 35 |
| 35 /* | 36 /* |
| 36 * | 37 * |
| 37 * Defines the version and type of the second bitmap header | 38 * Defines the version and type of the second bitmap header |
| 38 * | 39 * |
| 39 */ | 40 */ |
| 40 enum BitmapHeaderType { | 41 enum BitmapHeaderType { |
| 41 kInfoV1_BitmapHeaderType, | 42 kInfoV1_BitmapHeaderType, |
| 42 kInfoV2_BitmapHeaderType, | 43 kInfoV2_BitmapHeaderType, |
| (...skipping 342 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 385 } | 386 } |
| 386 | 387 |
| 387 // Check that input bit masks are valid and create the masks object | 388 // Check that input bit masks are valid and create the masks object |
| 388 SkAutoTDelete<SkMasks> | 389 SkAutoTDelete<SkMasks> |
| 389 masks(SkMasks::CreateMasks(inputMasks, bitsPerPixel)); | 390 masks(SkMasks::CreateMasks(inputMasks, bitsPerPixel)); |
| 390 if (NULL == masks) { | 391 if (NULL == masks) { |
| 391 SkDebugf("Error: invalid input masks.\n"); | 392 SkDebugf("Error: invalid input masks.\n"); |
| 392 return NULL; | 393 return NULL; |
| 393 } | 394 } |
| 394 | 395 |
| 395 // Process the color table | 396 // Verify the number of colors in the color table |
| 396 uint32_t colorBytes = 0; | 397 const uint32_t maxColors = 1 << bitsPerPixel; |
|
scroggo
2015/03/17 13:27:22
Could you move all of this into SkBmpCodec's onGet
msarett
2015/03/17 16:54:05
Doing these checks in onGetPixels actually causes
scroggo
2015/03/17 20:02:58
I think we can get around this...
How about this:
msarett
2015/03/18 13:02:52
Yes great! That's a much better way to do it.
| |
| 397 SkPMColor* colorTable = NULL; | 398 // Zero is a default for maxColors |
| 398 if (bitsPerPixel < 16) { | 399 // Also set numColors to maxColors when input is too large |
| 399 // Verify the number of colors for the color table | 400 if (numColors <= 0 || numColors > maxColors) { |
| 400 const uint32_t maxColors = 1 << bitsPerPixel; | 401 numColors = maxColors; |
| 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 } | 402 } |
| 438 | 403 |
| 439 // Ensure that the stream now points to the start of the pixel array | 404 // Account for the color table size |
| 405 uint32_t colorBytes; | |
| 406 if (bitsPerPixel < 16) { | |
| 407 colorBytes = numColors * bytesPerColor; | |
| 408 } else { | |
| 409 colorBytes = 0; | |
| 410 } | |
| 411 | |
| 412 // Calculate the number of bytes read so far (including the color table) | |
| 440 uint32_t bytesRead = kBmpHeaderBytes + infoBytes + maskBytes + colorBytes; | 413 uint32_t bytesRead = kBmpHeaderBytes + infoBytes + maskBytes + colorBytes; |
| 441 | 414 |
| 442 // Check that we have not read past the pixel array offset | 415 // Check that we have not read past the pixel array offset |
| 443 if(bytesRead > offset) { | 416 if(bytesRead > offset) { |
| 444 // This may occur on OS 2.1 and other old versions where the color | 417 // 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 | 418 // 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, | 419 // 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 | 420 // rather than try to guess the intended size of the color table. |
| 448 // rewind the stream to display the image. | |
| 449 SkDebugf("Error: pixel data offset less than header size.\n"); | 421 SkDebugf("Error: pixel data offset less than header size.\n"); |
| 450 return NULL; | 422 return NULL; |
| 451 } | 423 } |
| 452 | 424 |
| 453 // Skip to the start of the pixel array | |
| 454 if (stream->skip(offset - bytesRead) != offset - bytesRead) { | |
| 455 SkDebugf("Error: unable to skip to image data.\n"); | |
| 456 return NULL; | |
| 457 } | |
| 458 | |
| 459 // Remaining bytes is only used for RLE | 425 // Remaining bytes is only used for RLE |
| 460 const int remainingBytes = totalBytes - offset; | 426 const int remainingBytes = totalBytes - offset; |
| 461 if (remainingBytes <= 0 && kRLE_BitmapInputFormat == inputFormat) { | 427 if (remainingBytes <= 0 && kRLE_BitmapInputFormat == inputFormat) { |
| 462 SkDebugf("Error: RLE requires valid input size.\n"); | 428 SkDebugf("Error: RLE requires valid input size.\n"); |
| 463 return NULL; | 429 return NULL; |
| 464 } | 430 } |
| 465 | 431 |
| 466 // Return the codec | 432 // Return the codec |
| 467 // We will use ImageInfo to store width, height, and alpha type. We will | 433 // 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 | 434 // set color type to kN32_SkColorType because that should be the default |
| 469 // expected choice for a destination color type. In reality, the input | 435 // output. |
| 470 // color type has many possible formats. | |
| 471 const SkImageInfo& imageInfo = SkImageInfo::Make(width, height, | 436 const SkImageInfo& imageInfo = SkImageInfo::Make(width, height, |
| 472 kN32_SkColorType, alphaType); | 437 kN32_SkColorType, alphaType); |
| 473 return SkNEW_ARGS(SkBmpCodec, (imageInfo, stream, bitsPerPixel, | 438 return SkNEW_ARGS(SkBmpCodec, (imageInfo, stream, bitsPerPixel, |
| 474 inputFormat, masks.detach(), colorTable, | 439 inputFormat, masks.detach(), numColors, |
| 440 bytesPerColor, offset - bytesRead, | |
| 475 rowOrder, remainingBytes)); | 441 rowOrder, remainingBytes)); |
| 476 } | 442 } |
| 477 | 443 |
| 478 /* | 444 /* |
| 479 * | 445 * |
| 480 * Creates an instance of the decoder | 446 * Creates an instance of the decoder |
| 481 * Called only by NewFromStream | 447 * Called only by NewFromStream |
| 482 * | 448 * |
| 483 */ | 449 */ |
| 484 SkBmpCodec::SkBmpCodec(const SkImageInfo& info, SkStream* stream, | 450 SkBmpCodec::SkBmpCodec(const SkImageInfo& info, SkStream* stream, |
| 485 uint16_t bitsPerPixel, BitmapInputFormat inputFormat, | 451 uint16_t bitsPerPixel, BitmapInputFormat inputFormat, |
| 486 SkMasks* masks, SkPMColor* colorTable, | 452 SkMasks* masks, uint32_t numColors, |
| 487 RowOrder rowOrder, | 453 uint32_t bytesPerColor, uint32_t offset, |
| 488 const uint32_t remainingBytes) | 454 RowOrder rowOrder, uint32_t remainingBytes) |
| 489 : INHERITED(info, stream) | 455 : INHERITED(info, stream) |
| 490 , fBitsPerPixel(bitsPerPixel) | 456 , fBitsPerPixel(bitsPerPixel) |
| 491 , fInputFormat(inputFormat) | 457 , fInputFormat(inputFormat) |
| 492 , fMasks(masks) | 458 , fMasks(masks) |
| 493 , fColorTable(colorTable) | 459 , fColorTable(NULL) |
| 460 , fNumColors(numColors) | |
| 461 , fBytesPerColor(bytesPerColor) | |
| 462 , fOffset(offset) | |
| 494 , fRowOrder(rowOrder) | 463 , fRowOrder(rowOrder) |
| 495 , fRemainingBytes(remainingBytes) | 464 , fRemainingBytes(remainingBytes) |
| 496 {} | 465 {} |
| 497 | 466 |
| 498 /* | 467 /* |
| 499 * | 468 * |
| 500 * Initiates the bitmap decode | 469 * Initiates the bitmap decode |
| 501 * | 470 * |
| 502 */ | 471 */ |
| 503 SkCodec::Result SkBmpCodec::onGetPixels(const SkImageInfo& dstInfo, | 472 SkCodec::Result SkBmpCodec::onGetPixels(const SkImageInfo& dstInfo, |
| 504 void* dst, size_t dstRowBytes, | 473 void* dst, size_t dstRowBytes, |
| 505 SkPMColor*, int*) { | 474 SkPMColor*, int*) { |
| 475 // Check for proper input and output formats | |
| 506 if (!this->rewindIfNeeded()) { | 476 if (!this->rewindIfNeeded()) { |
| 507 return kCouldNotRewind; | 477 return kCouldNotRewind; |
| 508 } | 478 } |
| 509 if (dstInfo.dimensions() != this->getOriginalInfo().dimensions()) { | 479 if (dstInfo.dimensions() != this->getOriginalInfo().dimensions()) { |
| 510 SkDebugf("Error: scaling not supported.\n"); | 480 SkDebugf("Error: scaling not supported.\n"); |
| 511 return kInvalidScale; | 481 return kInvalidScale; |
| 512 } | 482 } |
| 513 if (!conversion_possible(dstInfo, this->getOriginalInfo())) { | 483 if (!conversion_possible(dstInfo, this->getOriginalInfo())) { |
| 514 SkDebugf("Error: cannot convert input type to output type.\n"); | 484 SkDebugf("Error: cannot convert input type to output type.\n"); |
| 515 return kInvalidConversion; | 485 return kInvalidConversion; |
| 516 } | 486 } |
| 517 | 487 |
| 488 // Create the color table if necessary and prepare the stream for decode | |
| 489 if (!createColorTable(dstInfo.alphaType())) { | |
| 490 SkDebugf("Error: could not create color table.\n"); | |
| 491 return kInvalidInput; | |
| 492 } | |
| 493 | |
| 494 // Perform the decode | |
| 518 switch (fInputFormat) { | 495 switch (fInputFormat) { |
| 519 case kBitMask_BitmapInputFormat: | 496 case kBitMask_BitmapInputFormat: |
| 520 return decodeMask(dstInfo, dst, dstRowBytes); | 497 return decodeMask(dstInfo, dst, dstRowBytes); |
| 521 case kRLE_BitmapInputFormat: | 498 case kRLE_BitmapInputFormat: |
| 522 return decodeRLE(dstInfo, dst, dstRowBytes); | 499 return decodeRLE(dstInfo, dst, dstRowBytes); |
| 523 case kStandard_BitmapInputFormat: | 500 case kStandard_BitmapInputFormat: |
| 524 return decode(dstInfo, dst, dstRowBytes); | 501 return decode(dstInfo, dst, dstRowBytes); |
| 525 default: | 502 default: |
| 526 SkASSERT(false); | 503 SkASSERT(false); |
| 527 return kInvalidInput; | 504 return kInvalidInput; |
| 528 } | 505 } |
| 529 } | 506 } |
| 530 | 507 |
| 531 /* | 508 /* |
| 532 * | 509 * |
| 510 * Process the color table for the bmp input | |
| 511 * | |
| 512 */ | |
| 513 bool SkBmpCodec::createColorTable(const SkAlphaType alphaType) { | |
| 514 SkPMColor* colorTable = NULL; | |
| 515 if (fBitsPerPixel < 16) { | |
| 516 // Allocate memory for a color table | |
| 517 const uint32_t maxColors = 1 << fBitsPerPixel; | |
| 518 colorTable = SkNEW_ARRAY(SkPMColor, maxColors); | |
|
scroggo
2015/03/17 13:27:22
colorTable will leak if we return NULL below.
msarett
2015/03/17 16:54:06
Done.
| |
| 519 | |
| 520 // Read the color table from the stream | |
| 521 uint32_t colorBytes = fNumColors * fBytesPerColor; | |
| 522 SkAutoTDeleteArray<uint8_t> cBuffer(SkNEW_ARRAY(uint8_t, colorBytes)); | |
| 523 if (stream()->read(cBuffer.get(), colorBytes) != colorBytes) { | |
| 524 SkDebugf("Error: unable to read color table.\n"); | |
| 525 return NULL; | |
| 526 } | |
| 527 | |
| 528 // Fill in the color table | |
| 529 uint32_t i = 0; | |
| 530 for (; i < fNumColors; i++) { | |
| 531 uint8_t blue = get_byte(cBuffer.get(), i*fBytesPerColor); | |
| 532 uint8_t green = get_byte(cBuffer.get(), i*fBytesPerColor + 1); | |
| 533 uint8_t red = get_byte(cBuffer.get(), i*fBytesPerColor + 2); | |
| 534 uint8_t alpha; | |
| 535 switch (alphaType) { | |
| 536 case kOpaque_SkAlphaType: | |
| 537 alpha = 0xFF; | |
| 538 colorTable[i] = SkPackARGB32NoCheck(alpha, red, green, | |
|
scroggo
2015/03/17 13:27:22
nit: no need to update the variable alpha. You can
msarett
2015/03/17 16:54:05
Done.
| |
| 539 blue); | |
| 540 break; | |
| 541 case kUnpremul_SkAlphaType: | |
| 542 alpha = (fMasks->getAlphaMask() >> 24) & | |
| 543 get_byte(cBuffer.get(), i*fBytesPerColor + 3); | |
| 544 colorTable[i] = SkPackARGB32NoCheck(alpha, red, green, | |
| 545 blue); | |
| 546 break; | |
| 547 case kPremul_SkAlphaType: | |
| 548 alpha = (fMasks->getAlphaMask() >> 24) & | |
| 549 get_byte(cBuffer.get(), i*fBytesPerColor + 3); | |
| 550 colorTable[i] = SkPreMultiplyARGB(alpha, red, green, blue); | |
| 551 break; | |
| 552 default: | |
| 553 // This should not be reached because conversion possible | |
| 554 // should fail if the alpha type is not one of the above | |
| 555 // values. | |
| 556 SkASSERT(false); | |
| 557 break; | |
| 558 } | |
| 559 } | |
| 560 | |
| 561 // To avoid segmentation faults on bad pixel data, fill the end of the | |
| 562 // color table with black. This is the same the behavior as the | |
| 563 // chromium decoder. | |
| 564 for (; i < maxColors; i++) { | |
| 565 colorTable[i] = SkPackARGB32NoCheck(0xFF, 0, 0, 0); | |
| 566 } | |
| 567 } | |
| 568 | |
| 569 // After reading the color table, skip to the start of the pixel array | |
| 570 if (stream()->skip(fOffset) != fOffset) { | |
| 571 SkDebugf("Error: unable to skip to image data.\n"); | |
| 572 return false; | |
| 573 } | |
| 574 | |
| 575 // Set the color table and return true on success | |
| 576 fColorTable.reset(colorTable); | |
| 577 return true; | |
| 578 } | |
| 579 | |
| 580 /* | |
| 581 * | |
| 533 * Performs the bitmap decoding for bit masks input format | 582 * Performs the bitmap decoding for bit masks input format |
| 534 * | 583 * |
| 535 */ | 584 */ |
| 536 SkCodec::Result SkBmpCodec::decodeMask(const SkImageInfo& dstInfo, | 585 SkCodec::Result SkBmpCodec::decodeMask(const SkImageInfo& dstInfo, |
| 537 void* dst, size_t dstRowBytes) { | 586 void* dst, size_t dstRowBytes) { |
| 538 // Set constant values | 587 // Set constant values |
| 539 const int width = dstInfo.width(); | 588 const int width = dstInfo.width(); |
| 540 const int height = dstInfo.height(); | 589 const int height = dstInfo.height(); |
| 541 const size_t rowBytes = SkAlign4(compute_row_bytes(width, fBitsPerPixel)); | 590 const size_t rowBytes = SkAlign4(compute_row_bytes(width, fBitsPerPixel)); |
| 542 | 591 |
| 543 // Allocate space for a row buffer and a source for the swizzler | 592 // Allocate a buffer large enough to hold the full input stream |
| 544 SkAutoTDeleteArray<uint8_t> srcBuffer(SkNEW_ARRAY(uint8_t, rowBytes)); | 593 uint8_t* srcBuffer(SkNEW_ARRAY(uint8_t, height*rowBytes)); |
|
msarett
2015/03/16 20:21:53
I know that it is preferred to use an SkAutoTDelet
scroggo
2015/03/17 13:27:22
You should definitely use some sort of auto delete
msarett
2015/03/17 16:54:06
Agreed, not sure what I was thinking.
| |
| 594 uint8_t* srcRow = srcBuffer; | |
| 545 | 595 |
| 546 // Get the destination start row and delta | 596 // Get the destination start row and delta |
| 597 SkPMColor* dstStart; | |
| 547 SkPMColor* dstRow; | 598 SkPMColor* dstRow; |
| 548 int delta; | 599 int delta; |
| 549 if (kTopDown_RowOrder == fRowOrder) { | 600 if (kTopDown_RowOrder == fRowOrder) { |
| 550 dstRow = (SkPMColor*) dst; | 601 dstStart = (SkPMColor*) dst; |
| 602 dstRow = dstStart; | |
| 551 delta = (int) dstRowBytes; | 603 delta = (int) dstRowBytes; |
| 552 } else { | 604 } else { |
| 553 dstRow = (SkPMColor*) SkTAddOffset<void>(dst, (height-1) * dstRowBytes); | 605 dstStart = (SkPMColor*) SkTAddOffset<void>( |
| 606 dst, (height - 1) * dstRowBytes); | |
| 607 dstRow = dstStart; | |
| 554 delta = -((int) dstRowBytes); | 608 delta = -((int) dstRowBytes); |
| 555 } | 609 } |
| 556 | 610 |
| 557 // Create the swizzler | 611 // Create the swizzler |
| 558 SkMaskSwizzler* swizzler = SkMaskSwizzler::CreateMaskSwizzler( | 612 SkMaskSwizzler* swizzler = SkMaskSwizzler::CreateMaskSwizzler( |
| 559 dstInfo, fMasks, fBitsPerPixel); | 613 dstInfo, fMasks, fBitsPerPixel); |
| 560 | 614 |
| 561 // Iterate over rows of the image | 615 // Iterate over rows of the image |
| 562 bool transparent = true; | 616 bool transparent = true; |
| 563 for (int y = 0; y < height; y++) { | 617 for (int y = 0; y < height; y++) { |
| 564 // Read a row of the input | 618 // Read a row of the input |
| 565 if (stream()->read(srcBuffer.get(), rowBytes) != rowBytes) { | 619 if (stream()->read(srcRow, rowBytes) != rowBytes) { |
| 566 SkDebugf("Warning: incomplete input stream.\n"); | 620 SkDebugf("Warning: incomplete input stream.\n"); |
| 621 SkDELETE_ARRAY(srcBuffer); | |
| 567 return kIncompleteInput; | 622 return kIncompleteInput; |
| 568 } | 623 } |
| 569 | 624 |
| 570 // Decode the row in destination format | 625 // Decode the row in destination format |
| 571 SkSwizzler::ResultAlpha r = swizzler->next(dstRow, srcBuffer.get()); | 626 SkSwizzler::ResultAlpha r = swizzler->next(dstRow, srcRow); |
| 572 transparent &= SkSwizzler::IsTransparent(r); | 627 transparent &= SkSwizzler::IsTransparent(r); |
| 573 | 628 |
| 574 // Move to the next row | 629 // Move to the next row |
| 575 dstRow = SkTAddOffset<SkPMColor>(dstRow, delta); | 630 dstRow = SkTAddOffset<SkPMColor>(dstRow, delta); |
| 631 srcRow = SkTAddOffset<uint8_t>(srcRow, rowBytes); | |
|
scroggo
2015/03/17 13:27:22
How did this work before?
msarett
2015/03/17 16:54:05
We used to overwrite the same row buffer for each
scroggo
2015/03/17 20:02:58
Ah, of course!
| |
| 576 } | 632 } |
| 577 | 633 |
| 578 // Some fully transparent bmp images are intended to be opaque. Here, we | 634 // Some fully transparent bmp images are intended to be opaque. Here, we |
| 579 // correct for this possibility. | 635 // correct for this possibility. |
| 580 dstRow = (SkPMColor*) dst; | |
| 581 if (transparent) { | 636 if (transparent) { |
| 637 const SkImageInfo& newInfo = dstInfo.makeAlphaType(kOpaque_SkAlphaType); | |
|
scroggo
2015/03/17 13:27:22
nit: Maybe this should be opaqueInfo? Or maskInfo?
msarett
2015/03/17 16:54:06
Done.
| |
| 638 SkMaskSwizzler* newSwizzler = SkMaskSwizzler::CreateMaskSwizzler( | |
|
scroggo
2015/03/17 13:27:22
This will leak.
scroggo
2015/03/17 13:27:22
nit: Maybe name this maskSwizzler?
msarett
2015/03/17 16:54:05
Yeah it looks like it. I think this is not the on
| |
| 639 newInfo, fMasks, fBitsPerPixel); | |
|
msarett
2015/03/16 20:21:53
Increase indent
| |
| 640 srcRow = srcBuffer; | |
| 641 dstRow = dstStart; | |
| 582 for (int y = 0; y < height; y++) { | 642 for (int y = 0; y < height; y++) { |
| 583 for (int x = 0; x < width; x++) { | 643 // Decode the row in new format |
| 584 dstRow[x] |= 0xFF000000; | 644 newSwizzler->next(dstRow, srcRow); |
| 585 } | 645 |
| 586 dstRow = SkTAddOffset<SkPMColor>(dstRow, dstRowBytes); | 646 // Move to the next row |
| 647 dstRow = SkTAddOffset<SkPMColor>(dstRow, delta); | |
| 648 srcRow = SkTAddOffset<uint8_t>(srcRow, rowBytes); | |
| 587 } | 649 } |
| 588 } | 650 } |
| 589 | 651 |
| 652 // Clean up memory | |
| 653 SkDELETE_ARRAY(srcBuffer); | |
| 654 | |
| 590 // Finished decoding the entire image | 655 // Finished decoding the entire image |
| 591 return kSuccess; | 656 return kSuccess; |
| 592 } | 657 } |
| 593 | 658 |
| 594 /* | 659 /* |
| 595 * | 660 * |
| 596 * Set an RLE pixel using the color table | 661 * Set an RLE pixel using the color table |
| 597 * | 662 * |
| 598 */ | 663 */ |
| 599 void SkBmpCodec::setRLEPixel(SkPMColor* dst, size_t dstRowBytes, int height, | 664 void SkBmpCodec::setRLEPixel(SkPMColor* dst, size_t dstRowBytes, |
| 600 uint32_t x, uint32_t y, uint8_t index) { | 665 const SkImageInfo& dstInfo, uint32_t x, uint32_t y, |
| 666 uint8_t index) { | |
| 667 // Set the row | |
| 668 int height = dstInfo.height(); | |
| 669 int row; | |
| 601 if (kBottomUp_RowOrder == fRowOrder) { | 670 if (kBottomUp_RowOrder == fRowOrder) { |
| 602 y = height - y - 1; | 671 row = height - y - 1; |
| 672 } else { | |
| 673 row = y; | |
| 603 } | 674 } |
| 604 SkPMColor* dstRow = SkTAddOffset<SkPMColor>(dst, y * dstRowBytes); | 675 |
| 605 dstRow[x] = fColorTable.get()[index]; | 676 // Set the pixel based on destination color type |
| 677 switch (dstInfo.colorType()) { | |
| 678 case kN32_SkColorType: { | |
| 679 SkPMColor* dstRow = SkTAddOffset<SkPMColor>(dst, | |
| 680 row * (int) dstRowBytes); | |
| 681 dstRow[x] = fColorTable.get()[index]; | |
| 682 break; | |
| 683 } | |
| 684 case kRGB_565_SkColorType: { | |
| 685 uint16_t* dstRow = SkTAddOffset<uint16_t>(dst, | |
| 686 row * (int) dstRowBytes); | |
| 687 dstRow[x] = SkPixel32ToPixel16(fColorTable.get()[index]); | |
| 688 break; | |
| 689 } | |
| 690 default: | |
| 691 // This case should not be reached. We should catch an invalid | |
| 692 // color type when we check that the conversion is possible. | |
| 693 SkASSERT(false); | |
| 694 break; | |
| 695 } | |
| 606 } | 696 } |
| 607 | 697 |
| 608 /* | 698 /* |
| 699 * | |
| 700 * Set an RLE pixel from R, G, B values | |
| 701 * | |
| 702 */ | |
| 703 void SkBmpCodec::setRLE24Pixel(SkPMColor* dst, size_t dstRowBytes, | |
| 704 const SkImageInfo& dstInfo, uint32_t x, | |
| 705 uint32_t y, uint8_t red, uint8_t green, | |
| 706 uint8_t blue) { | |
| 707 // Set the row | |
| 708 int height = dstInfo.height(); | |
| 709 int row; | |
| 710 if (kBottomUp_RowOrder == fRowOrder) { | |
| 711 row = height - y - 1; | |
| 712 } else { | |
| 713 row = y; | |
| 714 } | |
| 715 | |
| 716 // Set the pixel based on destination color type | |
| 717 switch (dstInfo.colorType()) { | |
| 718 case kN32_SkColorType: { | |
| 719 SkPMColor* dstRow = SkTAddOffset<SkPMColor>(dst, | |
| 720 row * (int) dstRowBytes); | |
| 721 dstRow[x] = SkPackARGB32NoCheck(0xFF, red, green, blue); | |
| 722 break; | |
| 723 } | |
| 724 case kRGB_565_SkColorType: { | |
| 725 uint16_t* dstRow = SkTAddOffset<uint16_t>(dst, | |
| 726 row * (int) dstRowBytes); | |
| 727 dstRow[x] = SkPack888ToRGB16(red, green, blue); | |
| 728 break; | |
| 729 } | |
| 730 default: | |
| 731 // This case should not be reached. We should catch an invalid | |
| 732 // color type when we check that the conversion is possible. | |
| 733 SkASSERT(false); | |
| 734 break; | |
| 735 } | |
| 736 } | |
| 737 | |
| 738 /* | |
| 609 * | 739 * |
| 610 * Performs the bitmap decoding for RLE input format | 740 * Performs the bitmap decoding for RLE input format |
| 611 * RLE decoding is performed all at once, rather than a one row at a time | 741 * RLE decoding is performed all at once, rather than a one row at a time |
| 612 * | 742 * |
| 613 */ | 743 */ |
| 614 SkCodec::Result SkBmpCodec::decodeRLE(const SkImageInfo& dstInfo, | 744 SkCodec::Result SkBmpCodec::decodeRLE(const SkImageInfo& dstInfo, |
| 615 void* dst, size_t dstRowBytes) { | 745 void* dst, size_t dstRowBytes) { |
| 616 // Set RLE flags | 746 // Set RLE flags |
| 617 static const uint8_t RLE_ESCAPE = 0; | 747 static const uint8_t RLE_ESCAPE = 0; |
| 618 static const uint8_t RLE_EOL = 0; | 748 static const uint8_t RLE_EOL = 0; |
| 619 static const uint8_t RLE_EOF = 1; | 749 static const uint8_t RLE_EOF = 1; |
| 620 static const uint8_t RLE_DELTA = 2; | 750 static const uint8_t RLE_DELTA = 2; |
| 621 | 751 |
| 622 // Set constant values | 752 // Set constant values |
| 623 const int width = dstInfo.width(); | 753 const int width = dstInfo.width(); |
| 624 const int height = dstInfo.height(); | 754 const int height = dstInfo.height(); |
| 625 | 755 |
| 626 // Input buffer parameters | 756 // Input buffer parameters |
| 627 uint32_t currByte = 0; | 757 uint32_t currByte = 0; |
| 628 SkAutoTDeleteArray<uint8_t> buffer(SkNEW_ARRAY(uint8_t, fRemainingBytes)); | 758 SkAutoTDeleteArray<uint8_t> buffer(SkNEW_ARRAY(uint8_t, fRemainingBytes)); |
| 629 size_t totalBytes = stream()->read(buffer.get(), fRemainingBytes); | 759 size_t totalBytes = stream()->read(buffer.get(), fRemainingBytes); |
| 630 if ((uint32_t) totalBytes < fRemainingBytes) { | 760 if (totalBytes < fRemainingBytes) { |
| 631 SkDebugf("Warning: incomplete RLE file.\n"); | 761 SkDebugf("Warning: incomplete RLE file.\n"); |
| 632 } else if (totalBytes <= 0) { | 762 } else if (totalBytes <= 0) { |
| 633 SkDebugf("Error: could not read RLE image data.\n"); | 763 SkDebugf("Error: could not read RLE image data.\n"); |
| 634 return kInvalidInput; | 764 return kInvalidInput; |
| 635 } | 765 } |
| 636 | 766 |
| 637 // Destination parameters | 767 // Destination parameters |
| 638 int x = 0; | 768 int x = 0; |
| 639 int y = 0; | 769 int y = 0; |
| 640 // If the code skips pixels, remaining pixels are transparent or black | 770 // If the code skips pixels, remaining pixels are transparent or black |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 699 fBitsPerPixel); | 829 fBitsPerPixel); |
| 700 // Abort if setting numPixels moves us off the edge of the | 830 // Abort if setting numPixels moves us off the edge of the |
| 701 // image. Also abort if there are not enough bytes | 831 // image. Also abort if there are not enough bytes |
| 702 // remaining in the stream to set numPixels. | 832 // remaining in the stream to set numPixels. |
| 703 if (x + numPixels > width || | 833 if (x + numPixels > width || |
| 704 (int) totalBytes - currByte < SkAlign2(rowBytes)) { | 834 (int) totalBytes - currByte < SkAlign2(rowBytes)) { |
| 705 SkDebugf("Warning: invalid RLE input.\n"); | 835 SkDebugf("Warning: invalid RLE input.\n"); |
| 706 return kIncompleteInput; | 836 return kIncompleteInput; |
| 707 } | 837 } |
| 708 // Set numPixels number of pixels | 838 // Set numPixels number of pixels |
| 709 SkPMColor* dstRow = SkTAddOffset<SkPMColor>( | |
| 710 dstPtr, y * dstRowBytes); | |
| 711 while (numPixels > 0) { | 839 while (numPixels > 0) { |
| 712 switch(fBitsPerPixel) { | 840 switch(fBitsPerPixel) { |
| 713 case 4: { | 841 case 4: { |
| 714 SkASSERT(currByte < totalBytes); | 842 SkASSERT(currByte < totalBytes); |
| 715 uint8_t val = buffer.get()[currByte++]; | 843 uint8_t val = buffer.get()[currByte++]; |
| 716 setRLEPixel(dstPtr, dstRowBytes, height, x++, y, | 844 setRLEPixel(dstPtr, dstRowBytes, dstInfo, x++, |
| 717 val >> 4); | 845 y, val >> 4); |
| 718 numPixels--; | 846 numPixels--; |
| 719 if (numPixels != 0) { | 847 if (numPixels != 0) { |
| 720 setRLEPixel(dstPtr, dstRowBytes, height, | 848 setRLEPixel(dstPtr, dstRowBytes, dstInfo, |
| 721 x++, y, val & 0xF); | 849 x++, y, val & 0xF); |
| 722 numPixels--; | 850 numPixels--; |
| 723 } | 851 } |
| 724 break; | 852 break; |
| 725 } | 853 } |
| 726 case 8: | 854 case 8: |
| 727 SkASSERT(currByte < totalBytes); | 855 SkASSERT(currByte < totalBytes); |
| 728 setRLEPixel(dstPtr, dstRowBytes, height, x++, y, | 856 setRLEPixel(dstPtr, dstRowBytes, dstInfo, x++, |
| 729 buffer.get()[currByte++]); | 857 y, buffer.get()[currByte++]); |
| 730 numPixels--; | 858 numPixels--; |
| 731 break; | 859 break; |
| 732 case 24: { | 860 case 24: { |
| 733 SkASSERT(currByte + 2 < totalBytes); | 861 SkASSERT(currByte + 2 < totalBytes); |
| 734 uint8_t blue = buffer.get()[currByte++]; | 862 uint8_t blue = buffer.get()[currByte++]; |
| 735 uint8_t green = buffer.get()[currByte++]; | 863 uint8_t green = buffer.get()[currByte++]; |
| 736 uint8_t red = buffer.get()[currByte++]; | 864 uint8_t red = buffer.get()[currByte++]; |
| 737 SkPMColor color = SkPackARGB32NoCheck( | 865 setRLE24Pixel(dstPtr, dstRowBytes, dstInfo, |
| 738 0xFF, red, green, blue); | 866 x++, y, red, green, blue); |
| 739 dstRow[x++] = color; | |
| 740 numPixels--; | 867 numPixels--; |
| 741 } | 868 } |
| 742 default: | 869 default: |
| 743 SkASSERT(false); | 870 SkASSERT(false); |
| 744 return kInvalidInput; | 871 return kInvalidInput; |
| 745 } | 872 } |
| 746 } | 873 } |
| 747 // Skip a byte if necessary to maintain alignment | 874 // Skip a byte if necessary to maintain alignment |
| 748 if (!SkIsAlign2(rowBytes)) { | 875 if (!SkIsAlign2(rowBytes)) { |
| 749 currByte++; | 876 currByte++; |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 763 // color. | 890 // color. |
| 764 if ((int) totalBytes - currByte < 2) { | 891 if ((int) totalBytes - currByte < 2) { |
| 765 SkDebugf("Warning: incomplete RLE input\n"); | 892 SkDebugf("Warning: incomplete RLE input\n"); |
| 766 return kIncompleteInput; | 893 return kIncompleteInput; |
| 767 } | 894 } |
| 768 | 895 |
| 769 // Fill the pixels up to endX with the specified color | 896 // Fill the pixels up to endX with the specified color |
| 770 uint8_t blue = task; | 897 uint8_t blue = task; |
| 771 uint8_t green = buffer.get()[currByte++]; | 898 uint8_t green = buffer.get()[currByte++]; |
| 772 uint8_t red = buffer.get()[currByte++]; | 899 uint8_t red = buffer.get()[currByte++]; |
| 773 SkPMColor color = SkPackARGB32NoCheck(0xFF, red, green, blue); | |
| 774 SkPMColor* dstRow = | |
| 775 SkTAddOffset<SkPMColor>(dstPtr, y * dstRowBytes); | |
| 776 while (x < endX) { | 900 while (x < endX) { |
| 777 dstRow[x++] = color; | 901 setRLE24Pixel(dstPtr, dstRowBytes, dstInfo, x++, y, red, |
| 902 green, blue); | |
| 778 } | 903 } |
| 779 } else { | 904 } else { |
| 780 // In RLE8 or RLE4, the second byte read gives the index in the | 905 // In RLE8 or RLE4, the second byte read gives the index in the |
| 781 // color table to look up the pixel color. | 906 // color table to look up the pixel color. |
| 782 // RLE8 has one color index that gets repeated | 907 // RLE8 has one color index that gets repeated |
| 783 // RLE4 has two color indexes in the upper and lower 4 bits of | 908 // RLE4 has two color indexes in the upper and lower 4 bits of |
| 784 // the bytes, which are alternated | 909 // the bytes, which are alternated |
| 785 uint8_t indices[2] = { task, task }; | 910 uint8_t indices[2] = { task, task }; |
| 786 if (4 == fBitsPerPixel) { | 911 if (4 == fBitsPerPixel) { |
| 787 indices[0] >>= 4; | 912 indices[0] >>= 4; |
| 788 indices[1] &= 0xf; | 913 indices[1] &= 0xf; |
| 789 } | 914 } |
| 790 | 915 |
| 791 // Set the indicated number of pixels | 916 // Set the indicated number of pixels |
| 792 for (int which = 0; x < endX; x++) { | 917 for (int which = 0; x < endX; x++) { |
| 793 setRLEPixel(dstPtr, dstRowBytes, height, x, y, | 918 setRLEPixel(dstPtr, dstRowBytes, dstInfo, x, y, |
| 794 indices[which]); | 919 indices[which]); |
| 795 which = !which; | 920 which = !which; |
| 796 } | 921 } |
| 797 } | 922 } |
| 798 } | 923 } |
| 799 } | 924 } |
| 800 } | 925 } |
| 801 | 926 |
| 802 /* | 927 /* |
| 803 * | 928 * |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 894 } | 1019 } |
| 895 dstRow = SkTAddOffset<SkPMColor>(dstRow, dstRowBytes); | 1020 dstRow = SkTAddOffset<SkPMColor>(dstRow, dstRowBytes); |
| 896 } | 1021 } |
| 897 } | 1022 } |
| 898 } | 1023 } |
| 899 */ | 1024 */ |
| 900 | 1025 |
| 901 // Finished decoding the entire image | 1026 // Finished decoding the entire image |
| 902 return kSuccess; | 1027 return kSuccess; |
| 903 } | 1028 } |
| OLD | NEW |