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 // Ensure that the profile type is unchanged | 21 // Ensure that the profile type is unchanged |
| 22 if (dst.profileType() != src.profileType()) { | 22 if (dst.profileType() != src.profileType()) { |
| 23 return false; | 23 return false; |
| 24 } | 24 } |
| 25 | 25 |
| 26 // Check for supported color and alpha types | 26 // Check for supported alpha types |
| 27 if (src.alphaType() != dst.alphaType() && | |
| 28 (kPremul_SkAlphaType != dst.alphaType() || | |
| 29 kUnpremul_SkAlphaType == src.alphaType())) { | |
| 30 return false; | |
| 31 } | |
| 32 | |
| 33 // Check for supported color types | |
| 27 switch (dst.colorType()) { | 34 switch (dst.colorType()) { |
| 35 // Allow output to kN32 from any type of input | |
| 28 case kN32_SkColorType: | 36 case kN32_SkColorType: |
| 29 return src.alphaType() == dst.alphaType() || | 37 return true; |
| 30 (kPremul_SkAlphaType == dst.alphaType() && | 38 // Allow output to kIndex_8 from compatible inputs |
| 31 kUnpremul_SkAlphaType == src.alphaType()); | 39 case kIndex_8_SkColorType: |
| 40 return kIndex_8_SkColorType == src.colorType(); | |
| 32 default: | 41 default: |
| 33 return false; | 42 return false; |
| 34 } | 43 } |
| 35 } | 44 } |
| 36 | 45 |
| 37 /* | 46 /* |
| 38 * | 47 * |
| 39 * Defines the version and type of the second bitmap header | 48 * Defines the version and type of the second bitmap header |
| 40 * | 49 * |
| 41 */ | 50 */ |
| (...skipping 370 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 412 // Header types are matched based on size. If the header is | 421 // Header types are matched based on size. If the header is |
| 413 // V3+, we are guaranteed to be able to read at least this size. | 422 // V3+, we are guaranteed to be able to read at least this size. |
| 414 SkASSERT(infoBytesRemaining > 52); | 423 SkASSERT(infoBytesRemaining > 52); |
| 415 inputMasks.alpha = get_int(iBuffer.get(), 48); | 424 inputMasks.alpha = get_int(iBuffer.get(), 48); |
| 416 if (inputMasks.alpha != 0) { | 425 if (inputMasks.alpha != 0) { |
| 417 alphaType = kUnpremul_SkAlphaType; | 426 alphaType = kUnpremul_SkAlphaType; |
| 418 } | 427 } |
| 419 } | 428 } |
| 420 iBuffer.free(); | 429 iBuffer.free(); |
| 421 | 430 |
| 422 // Additionally, 32 bit bmp-in-icos use the alpha channel | 431 // Additionally, 32 bit bmp-in-icos use the alpha channel. |
| 423 if (isIco && 32 == bitsPerPixel) { | 432 // And, RLE inputs may skip pixels, leaving them as transparent. This |
| 433 // is uncommon, but we cannot be certain that an RLE bmp will be opaque. | |
| 434 if ((isIco && 32 == bitsPerPixel) || (kRLE_BitmapInputFormat == inputFormat) ) { | |
| 424 alphaType = kUnpremul_SkAlphaType; | 435 alphaType = kUnpremul_SkAlphaType; |
| 425 } | 436 } |
| 426 | 437 |
| 427 // Check for valid bits per pixel input | 438 // Check for valid bits per pixel. |
| 439 // At the same time, use this information to choose a suggested color type | |
| 440 // and to set default masks. | |
| 441 SkColorType colorType = kN32_SkColorType; | |
| 428 switch (bitsPerPixel) { | 442 switch (bitsPerPixel) { |
| 429 // In addition to more standard pixel compression formats, bmp supports | 443 // In addition to more standard pixel compression formats, bmp supports |
| 430 // the use of bit masks to determine pixel components. The standard | 444 // the use of bit masks to determine pixel components. The standard |
| 431 // format for representing 16-bit colors is 555 (XRRRRRGGGGGBBBBB), | 445 // format for representing 16-bit colors is 555 (XRRRRRGGGGGBBBBB), |
| 432 // which does not map well to any Skia color formats. For this reason, | 446 // which does not map well to any Skia color formats. For this reason, |
| 433 // we will always enable mask mode with 16 bits per pixel. | 447 // we will always enable mask mode with 16 bits per pixel. |
| 434 case 16: | 448 case 16: |
| 435 if (kBitMask_BitmapInputFormat != inputFormat) { | 449 if (kBitMask_BitmapInputFormat != inputFormat) { |
| 436 inputMasks.red = 0x7C00; | 450 inputMasks.red = 0x7C00; |
| 437 inputMasks.green = 0x03E0; | 451 inputMasks.green = 0x03E0; |
| 438 inputMasks.blue = 0x001F; | 452 inputMasks.blue = 0x001F; |
| 439 inputFormat = kBitMask_BitmapInputFormat; | 453 inputFormat = kBitMask_BitmapInputFormat; |
| 440 } | 454 } |
| 441 break; | 455 break; |
| 456 // We want to decode to kIndex_8 for input formats that are already | |
| 457 // designed in index format. | |
| 442 case 1: | 458 case 1: |
| 443 case 2: | 459 case 2: |
| 444 case 4: | 460 case 4: |
| 445 case 8: | 461 case 8: |
| 462 // However, we cannot in RLE format since we may need to leave s ome | |
|
scroggo
2015/04/02 19:20:30
It seems a shame that we cannot support this. It s
msarett
2015/04/03 18:01:32
Agreed. Wish there was a good way.
| |
| 463 // pixels as transparent. Similarly, we also cannot for ICO ima ges | |
| 464 // since we may need to apply a transparent mask. | |
| 465 if (kRLE_BitmapInputFormat != inputFormat && !isIco) { | |
| 466 colorType = kIndex_8_SkColorType; | |
| 467 } | |
| 446 case 24: | 468 case 24: |
| 447 case 32: | 469 case 32: |
| 448 break; | 470 break; |
| 449 default: | 471 default: |
| 450 SkCodecPrintf("Error: invalid input value for bits per pixel.\n"); | 472 SkCodecPrintf("Error: invalid input value for bits per pixel.\n"); |
| 451 return false; | 473 return false; |
| 452 } | 474 } |
| 453 | 475 |
| 454 // Check that input bit masks are valid and create the masks object | 476 // Check that input bit masks are valid and create the masks object |
| 455 SkAutoTDelete<SkMasks> | 477 SkAutoTDelete<SkMasks> |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 468 | 490 |
| 469 // Calculate the number of bytes read so far | 491 // Calculate the number of bytes read so far |
| 470 const uint32_t bytesRead = kBmpHeaderBytes + infoBytes + maskBytes; | 492 const uint32_t bytesRead = kBmpHeaderBytes + infoBytes + maskBytes; |
| 471 if (!isIco && offset < bytesRead) { | 493 if (!isIco && offset < bytesRead) { |
| 472 SkCodecPrintf("Error: pixel data offset less than header size.\n"); | 494 SkCodecPrintf("Error: pixel data offset less than header size.\n"); |
| 473 return false; | 495 return false; |
| 474 } | 496 } |
| 475 | 497 |
| 476 if (codecOut) { | 498 if (codecOut) { |
| 477 // Return the codec | 499 // Return the codec |
| 478 // We will use ImageInfo to store width, height, and alpha type. We | 500 // We will use ImageInfo to store width, height, suggested color type, a nd |
| 479 // will set color type to kN32_SkColorType because that should be the | 501 // suggested alpha type. |
| 480 // default output. | |
| 481 const SkImageInfo& imageInfo = SkImageInfo::Make(width, height, | 502 const SkImageInfo& imageInfo = SkImageInfo::Make(width, height, |
| 482 kN32_SkColorType, alphaType); | 503 colorType, alphaType); |
| 483 *codecOut = SkNEW_ARGS(SkBmpCodec, (imageInfo, stream, bitsPerPixel, | 504 *codecOut = SkNEW_ARGS(SkBmpCodec, (imageInfo, stream, bitsPerPixel, |
| 484 inputFormat, masks.detach(), | 505 inputFormat, masks.detach(), |
| 485 numColors, bytesPerColor, | 506 numColors, bytesPerColor, |
| 486 offset - bytesRead, rowOrder, | 507 offset - bytesRead, rowOrder, |
| 487 RLEBytes, isIco)); | 508 RLEBytes, isIco)); |
| 488 } | 509 } |
| 489 return true; | 510 return true; |
| 490 } | 511 } |
| 491 | 512 |
| 492 /* | 513 /* |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 528 | 549 |
| 529 {} | 550 {} |
| 530 | 551 |
| 531 /* | 552 /* |
| 532 * | 553 * |
| 533 * Initiates the bitmap decode | 554 * Initiates the bitmap decode |
| 534 * | 555 * |
| 535 */ | 556 */ |
| 536 SkCodec::Result SkBmpCodec::onGetPixels(const SkImageInfo& dstInfo, | 557 SkCodec::Result SkBmpCodec::onGetPixels(const SkImageInfo& dstInfo, |
| 537 void* dst, size_t dstRowBytes, | 558 void* dst, size_t dstRowBytes, |
| 538 const Options&, | 559 const Options& opts, |
| 539 SkPMColor*, int*) { | 560 SkPMColor* inputColorPtr, |
| 561 int* inputColorCount) { | |
| 540 // Check for proper input and output formats | 562 // Check for proper input and output formats |
| 541 SkCodec::RewindState rewindState = this->rewindIfNeeded(); | 563 SkCodec::RewindState rewindState = this->rewindIfNeeded(); |
| 542 if (rewindState == kCouldNotRewind_RewindState) { | 564 if (rewindState == kCouldNotRewind_RewindState) { |
| 543 return kCouldNotRewind; | 565 return kCouldNotRewind; |
| 544 } else if (rewindState == kRewound_RewindState) { | 566 } else if (rewindState == kRewound_RewindState) { |
| 545 if (!ReadHeader(this->stream(), fIsIco, NULL)) { | 567 if (!ReadHeader(this->stream(), fIsIco, NULL)) { |
| 546 return kCouldNotRewind; | 568 return kCouldNotRewind; |
| 547 } | 569 } |
| 548 } | 570 } |
| 549 if (dstInfo.dimensions() != this->getInfo().dimensions()) { | 571 if (dstInfo.dimensions() != this->getInfo().dimensions()) { |
| 550 SkCodecPrintf("Error: scaling not supported.\n"); | 572 SkCodecPrintf("Error: scaling not supported.\n"); |
| 551 return kInvalidScale; | 573 return kInvalidScale; |
| 552 } | 574 } |
| 553 if (!conversion_possible(dstInfo, this->getInfo())) { | 575 if (!conversion_possible(dstInfo, this->getInfo())) { |
| 554 SkCodecPrintf("Error: cannot convert input type to output type.\n"); | 576 SkCodecPrintf("Error: cannot convert input type to output type.\n"); |
| 555 return kInvalidConversion; | 577 return kInvalidConversion; |
| 556 } | 578 } |
| 557 | 579 |
| 580 // Get a color table pointer | |
| 581 SkPMColor alternateColorPtr[256]; | |
| 582 fColorTable = get_color_table_ptr(dstInfo.colorType(), inputColorPtr, | |
|
scroggo
2015/04/02 19:20:31
This seems fragile. You are setting a pointer fiel
msarett
2015/04/03 18:01:32
Yeah that concerned me as well. I think the new a
| |
| 583 inputColorCount, alternateColorPtr); | |
| 584 | |
| 558 // Create the color table if necessary and prepare the stream for decode | 585 // Create the color table if necessary and prepare the stream for decode |
| 559 if (!createColorTable(dstInfo.alphaType())) { | 586 if (!createColorTable(dstInfo.alphaType())) { |
| 560 SkCodecPrintf("Error: could not create color table.\n"); | 587 SkCodecPrintf("Error: could not create color table.\n"); |
| 561 return kInvalidInput; | 588 return kInvalidInput; |
| 562 } | 589 } |
| 563 | 590 |
| 564 // Perform the decode | 591 // Perform the decode |
| 565 switch (fInputFormat) { | 592 switch (fInputFormat) { |
| 566 case kBitMask_BitmapInputFormat: | 593 case kBitMask_BitmapInputFormat: |
| 567 return decodeMask(dstInfo, dst, dstRowBytes); | 594 return decodeMask(dstInfo, dst, dstRowBytes); |
| 568 case kRLE_BitmapInputFormat: | 595 case kRLE_BitmapInputFormat: |
| 569 return decodeRLE(dstInfo, dst, dstRowBytes); | 596 return decodeRLE(dstInfo, dst, dstRowBytes, opts); |
| 570 case kStandard_BitmapInputFormat: | 597 case kStandard_BitmapInputFormat: |
| 571 return decode(dstInfo, dst, dstRowBytes); | 598 return decode(dstInfo, dst, dstRowBytes); |
| 572 default: | 599 default: |
| 573 SkASSERT(false); | 600 SkASSERT(false); |
| 574 return kInvalidInput; | 601 return kInvalidInput; |
| 575 } | 602 } |
| 576 } | 603 } |
| 577 | 604 |
| 578 /* | 605 /* |
| 579 * | 606 * |
| 580 * Process the color table for the bmp input | 607 * Process the color table for the bmp input |
| 581 * | 608 * |
| 582 */ | 609 */ |
| 583 bool SkBmpCodec::createColorTable(SkAlphaType alphaType) { | 610 bool SkBmpCodec::createColorTable(SkAlphaType alphaType) { |
| 584 // Allocate memory for color table | 611 // Allocate memory for color table |
| 585 uint32_t colorBytes = 0; | 612 uint32_t colorBytes = 0; |
| 586 uint32_t maxColors = 0; | 613 uint32_t maxColors = 0; |
| 587 SkPMColor colorTable[256]; | |
| 588 if (fBitsPerPixel <= 8) { | 614 if (fBitsPerPixel <= 8) { |
| 589 // Zero is a default for maxColors | 615 // Zero is a default for maxColors |
| 590 // Also set fNumColors to maxColors when it is too large | 616 // Also set fNumColors to maxColors when it is too large |
| 591 maxColors = 1 << fBitsPerPixel; | 617 maxColors = 1 << fBitsPerPixel; |
| 592 if (fNumColors == 0 || fNumColors >= maxColors) { | 618 if (fNumColors == 0 || fNumColors >= maxColors) { |
| 593 fNumColors = maxColors; | 619 fNumColors = maxColors; |
| 594 } | 620 } |
| 595 | 621 |
| 596 // Read the color table from the stream | 622 // Read the color table from the stream |
| 597 colorBytes = fNumColors * fBytesPerColor; | 623 colorBytes = fNumColors * fBytesPerColor; |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 622 | 648 |
| 623 // Fill in the color table | 649 // Fill in the color table |
| 624 uint32_t i = 0; | 650 uint32_t i = 0; |
| 625 for (; i < fNumColors; i++) { | 651 for (; i < fNumColors; i++) { |
| 626 uint8_t blue = get_byte(cBuffer.get(), i*fBytesPerColor); | 652 uint8_t blue = get_byte(cBuffer.get(), i*fBytesPerColor); |
| 627 uint8_t green = get_byte(cBuffer.get(), i*fBytesPerColor + 1); | 653 uint8_t green = get_byte(cBuffer.get(), i*fBytesPerColor + 1); |
| 628 uint8_t red = get_byte(cBuffer.get(), i*fBytesPerColor + 2); | 654 uint8_t red = get_byte(cBuffer.get(), i*fBytesPerColor + 2); |
| 629 uint8_t alpha = kOpaque_SkAlphaType == alphaType ? 0xFF : | 655 uint8_t alpha = kOpaque_SkAlphaType == alphaType ? 0xFF : |
| 630 (fMasks->getAlphaMask() >> 24) & | 656 (fMasks->getAlphaMask() >> 24) & |
| 631 get_byte(cBuffer.get(), i*fBytesPerColor + 3); | 657 get_byte(cBuffer.get(), i*fBytesPerColor + 3); |
| 632 colorTable[i] = packARGB(alpha, red, green, blue); | 658 fColorTable[i] = packARGB(alpha, red, green, blue); |
| 633 } | 659 } |
| 634 | 660 |
| 635 // To avoid segmentation faults on bad pixel data, fill the end of the | 661 // To avoid segmentation faults on bad pixel data, fill the end of the |
| 636 // color table with black. This is the same the behavior as the | 662 // color table with black. This is the same the behavior as the |
| 637 // chromium decoder. | 663 // chromium decoder. |
| 638 for (; i < maxColors; i++) { | 664 for (; i < maxColors; i++) { |
| 639 colorTable[i] = SkPackARGB32NoCheck(0xFF, 0, 0, 0); | 665 fColorTable[i] = SkPackARGB32NoCheck(0xFF, 0, 0, 0); |
| 640 } | 666 } |
| 641 } | 667 } |
| 642 | 668 |
| 643 // Bmp-in-Ico files do not use an offset to indicate where the pixel data | 669 // Bmp-in-Ico files do not use an offset to indicate where the pixel data |
| 644 // begins. Pixel data always begins immediately after the color table. | 670 // begins. Pixel data always begins immediately after the color table. |
| 645 if (!fIsIco) { | 671 if (!fIsIco) { |
| 646 // Check that we have not read past the pixel array offset | 672 // Check that we have not read past the pixel array offset |
| 647 if(fOffset < colorBytes) { | 673 if(fOffset < colorBytes) { |
| 648 // This may occur on OS 2.1 and other old versions where the color | 674 // This may occur on OS 2.1 and other old versions where the color |
| 649 // table defaults to max size, and the bmp tries to use a smaller | 675 // table defaults to max size, and the bmp tries to use a smaller |
| 650 // color table. This is invalid, and our decision is to indicate | 676 // color table. This is invalid, and our decision is to indicate |
| 651 // an error, rather than try to guess the intended size of the | 677 // an error, rather than try to guess the intended size of the |
| 652 // color table. | 678 // color table. |
| 653 SkCodecPrintf("Error: pixel data offset less than color table size.\ n"); | 679 SkCodecPrintf("Error: pixel data offset less than color table size.\ n"); |
| 654 return false; | 680 return false; |
| 655 } | 681 } |
| 656 | 682 |
| 657 // After reading the color table, skip to the start of the pixel array | 683 // After reading the color table, skip to the start of the pixel array |
| 658 if (stream()->skip(fOffset - colorBytes) != fOffset - colorBytes) { | 684 if (stream()->skip(fOffset - colorBytes) != fOffset - colorBytes) { |
| 659 SkCodecPrintf("Error: unable to skip to image data.\n"); | 685 SkCodecPrintf("Error: unable to skip to image data.\n"); |
| 660 return false; | 686 return false; |
| 661 } | 687 } |
| 662 } | 688 } |
| 663 | 689 |
| 664 // Set the color table and return true on success | 690 // Return true on success |
| 665 fColorTable.reset(SkNEW_ARGS(SkColorTable, (colorTable, maxColors))); | |
| 666 return true; | 691 return true; |
| 667 } | 692 } |
| 668 | 693 |
| 669 /* | 694 /* |
| 670 * | 695 * |
| 671 * Performs the bitmap decoding for bit masks input format | 696 * Performs the bitmap decoding for bit masks input format |
| 672 * | 697 * |
| 673 */ | 698 */ |
| 674 SkCodec::Result SkBmpCodec::decodeMask(const SkImageInfo& dstInfo, | 699 SkCodec::Result SkBmpCodec::decodeMask(const SkImageInfo& dstInfo, |
| 675 void* dst, size_t dstRowBytes) { | 700 void* dst, size_t dstRowBytes) { |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 727 | 752 |
| 728 // Finished decoding the entire image | 753 // Finished decoding the entire image |
| 729 return kSuccess; | 754 return kSuccess; |
| 730 } | 755 } |
| 731 | 756 |
| 732 /* | 757 /* |
| 733 * | 758 * |
| 734 * Set an RLE pixel using the color table | 759 * Set an RLE pixel using the color table |
| 735 * | 760 * |
| 736 */ | 761 */ |
| 737 void SkBmpCodec::setRLEPixel(SkPMColor* dst, size_t dstRowBytes, | 762 void SkBmpCodec::setRLEPixel(void* dst, size_t dstRowBytes, |
| 738 const SkImageInfo& dstInfo, uint32_t x, uint32_t y, | 763 const SkImageInfo& dstInfo, uint32_t x, uint32_t y, |
| 739 uint8_t index) { | 764 uint8_t index) { |
| 740 // Set the row | 765 // Set the row |
| 741 int height = dstInfo.height(); | 766 int height = dstInfo.height(); |
| 742 int row; | 767 int row; |
| 743 if (kBottomUp_RowOrder == fRowOrder) { | 768 if (kBottomUp_RowOrder == fRowOrder) { |
| 744 row = height - y - 1; | 769 row = height - y - 1; |
| 745 } else { | 770 } else { |
| 746 row = y; | 771 row = y; |
| 747 } | 772 } |
| 748 | 773 |
| 749 // Set the pixel based on destination color type | 774 // Set the pixel based on destination color type |
| 750 switch (dstInfo.colorType()) { | 775 switch (dstInfo.colorType()) { |
| 751 case kN32_SkColorType: { | 776 case kN32_SkColorType: { |
| 752 SkPMColor* dstRow = SkTAddOffset<SkPMColor>(dst, | 777 SkPMColor* dstRow = SkTAddOffset<SkPMColor>((SkPMColor*) dst, |
| 753 row * (int) dstRowBytes); | 778 row * (int) dstRowBytes); |
| 754 dstRow[x] = fColorTable->operator[](index); | 779 dstRow[x] = fColorTable[index]; |
| 755 break; | |
| 756 } | |
| 757 case kRGB_565_SkColorType: { | |
| 758 uint16_t* dstRow = SkTAddOffset<uint16_t>(dst, | |
| 759 row * (int) dstRowBytes); | |
| 760 dstRow[x] = SkPixel32ToPixel16(fColorTable->operator[](index)); | |
| 761 break; | 780 break; |
| 762 } | 781 } |
| 763 default: | 782 default: |
| 764 // This case should not be reached. We should catch an invalid | 783 // This case should not be reached. We should catch an invalid |
| 765 // color type when we check that the conversion is possible. | 784 // color type when we check that the conversion is possible. |
| 766 SkASSERT(false); | 785 SkASSERT(false); |
| 767 break; | 786 break; |
| 768 } | 787 } |
| 769 } | 788 } |
| 770 | 789 |
| 771 /* | 790 /* |
| 772 * | 791 * |
| 773 * Set an RLE pixel from R, G, B values | 792 * Set an RLE pixel from R, G, B values |
| 774 * | 793 * |
| 775 */ | 794 */ |
| 776 void SkBmpCodec::setRLE24Pixel(SkPMColor* dst, size_t dstRowBytes, | 795 void SkBmpCodec::setRLE24Pixel(void* dst, size_t dstRowBytes, |
| 777 const SkImageInfo& dstInfo, uint32_t x, | 796 const SkImageInfo& dstInfo, uint32_t x, |
| 778 uint32_t y, uint8_t red, uint8_t green, | 797 uint32_t y, uint8_t red, uint8_t green, |
| 779 uint8_t blue) { | 798 uint8_t blue) { |
| 780 // Set the row | 799 // Set the row |
| 781 int height = dstInfo.height(); | 800 int height = dstInfo.height(); |
| 782 int row; | 801 int row; |
| 783 if (kBottomUp_RowOrder == fRowOrder) { | 802 if (kBottomUp_RowOrder == fRowOrder) { |
| 784 row = height - y - 1; | 803 row = height - y - 1; |
| 785 } else { | 804 } else { |
| 786 row = y; | 805 row = y; |
| 787 } | 806 } |
| 788 | 807 |
| 789 // Set the pixel based on destination color type | 808 // Set the pixel based on destination color type |
| 790 switch (dstInfo.colorType()) { | 809 switch (dstInfo.colorType()) { |
| 791 case kN32_SkColorType: { | 810 case kN32_SkColorType: { |
| 792 SkPMColor* dstRow = SkTAddOffset<SkPMColor>(dst, | 811 SkPMColor* dstRow = SkTAddOffset<SkPMColor>((SkPMColor*) dst, |
| 793 row * (int) dstRowBytes); | 812 row * (int) dstRowBytes); |
| 794 dstRow[x] = SkPackARGB32NoCheck(0xFF, red, green, blue); | 813 dstRow[x] = SkPackARGB32NoCheck(0xFF, red, green, blue); |
| 795 break; | 814 break; |
| 796 } | 815 } |
| 797 case kRGB_565_SkColorType: { | |
| 798 uint16_t* dstRow = SkTAddOffset<uint16_t>(dst, | |
| 799 row * (int) dstRowBytes); | |
| 800 dstRow[x] = SkPack888ToRGB16(red, green, blue); | |
| 801 break; | |
| 802 } | |
| 803 default: | 816 default: |
| 804 // This case should not be reached. We should catch an invalid | 817 // This case should not be reached. We should catch an invalid |
| 805 // color type when we check that the conversion is possible. | 818 // color type when we check that the conversion is possible. |
| 806 SkASSERT(false); | 819 SkASSERT(false); |
| 807 break; | 820 break; |
| 808 } | 821 } |
| 809 } | 822 } |
| 810 | 823 |
| 811 /* | 824 /* |
| 812 * | 825 * |
| 813 * Performs the bitmap decoding for RLE input format | 826 * Performs the bitmap decoding for RLE input format |
| 814 * RLE decoding is performed all at once, rather than a one row at a time | 827 * RLE decoding is performed all at once, rather than a one row at a time |
| 815 * | 828 * |
| 816 */ | 829 */ |
| 817 SkCodec::Result SkBmpCodec::decodeRLE(const SkImageInfo& dstInfo, | 830 SkCodec::Result SkBmpCodec::decodeRLE(const SkImageInfo& dstInfo, |
| 818 void* dst, size_t dstRowBytes) { | 831 void* dst, size_t dstRowBytes, |
| 832 const Options& opts) { | |
| 819 // Set RLE flags | 833 // Set RLE flags |
| 820 static const uint8_t RLE_ESCAPE = 0; | 834 static const uint8_t RLE_ESCAPE = 0; |
| 821 static const uint8_t RLE_EOL = 0; | 835 static const uint8_t RLE_EOL = 0; |
| 822 static const uint8_t RLE_EOF = 1; | 836 static const uint8_t RLE_EOF = 1; |
| 823 static const uint8_t RLE_DELTA = 2; | 837 static const uint8_t RLE_DELTA = 2; |
| 824 | 838 |
| 825 // Set constant values | 839 // Set constant values |
| 826 const int width = dstInfo.width(); | 840 const int width = dstInfo.width(); |
| 827 const int height = dstInfo.height(); | 841 const int height = dstInfo.height(); |
| 828 | 842 |
| 829 // Input buffer parameters | 843 // Input buffer parameters |
| 830 uint32_t currByte = 0; | 844 uint32_t currByte = 0; |
| 831 SkAutoTDeleteArray<uint8_t> buffer(SkNEW_ARRAY(uint8_t, fRLEBytes)); | 845 SkAutoTDeleteArray<uint8_t> buffer(SkNEW_ARRAY(uint8_t, fRLEBytes)); |
| 832 size_t totalBytes = stream()->read(buffer.get(), fRLEBytes); | 846 size_t totalBytes = stream()->read(buffer.get(), fRLEBytes); |
| 833 if (totalBytes < fRLEBytes) { | 847 if (totalBytes < fRLEBytes) { |
| 834 SkCodecPrintf("Warning: incomplete RLE file.\n"); | 848 SkCodecPrintf("Warning: incomplete RLE file.\n"); |
| 835 } else if (totalBytes <= 0) { | 849 } else if (totalBytes <= 0) { |
| 836 SkCodecPrintf("Error: could not read RLE image data.\n"); | 850 SkCodecPrintf("Error: could not read RLE image data.\n"); |
| 837 return kInvalidInput; | 851 return kInvalidInput; |
| 838 } | 852 } |
| 839 | 853 |
| 840 // Destination parameters | 854 // Destination parameters |
| 841 int x = 0; | 855 int x = 0; |
| 842 int y = 0; | 856 int y = 0; |
| 843 // If the code skips pixels, remaining pixels are transparent or black | 857 |
| 844 // TODO: Skip this if memory was already zeroed. | 858 // Set the background as transparent. Then, if the RLE code skips pixels, |
| 845 memset(dst, 0, dstRowBytes * height); | 859 // the skipped pixels will be transparent. |
| 846 SkPMColor* dstPtr = (SkPMColor*) dst; | 860 // Because of the need for transparent pixels, kN32 is the only color |
| 861 // type that makes sense for the destination format. | |
| 862 SkASSERT(kN32_SkColorType == dstInfo.colorType()); | |
| 863 if (kYes_ZeroInitialized == opts.fZeroInitialized) { | |
|
scroggo
2015/04/02 19:20:30
kNo_ZeroInitialized.
If it's already zero initial
msarett
2015/04/03 18:01:32
Of course!
| |
| 864 memset(dst, 0, dstRowBytes * height); | |
|
scroggo
2015/04/02 19:20:30
Ooh, I missed this on an earlier review.
We allow
msarett
2015/04/03 18:01:32
Good to know! I don't think this is the only plac
| |
| 865 } | |
| 847 | 866 |
| 848 while (true) { | 867 while (true) { |
| 849 // Every entry takes at least two bytes | 868 // Every entry takes at least two bytes |
| 850 if ((int) totalBytes - currByte < 2) { | 869 if ((int) totalBytes - currByte < 2) { |
| 851 SkCodecPrintf("Warning: incomplete RLE input.\n"); | 870 SkCodecPrintf("Warning: incomplete RLE input.\n"); |
| 852 return kIncompleteInput; | 871 return kIncompleteInput; |
| 853 } | 872 } |
| 854 | 873 |
| 855 // Read the next two bytes. These bytes have different meanings | 874 // Read the next two bytes. These bytes have different meanings |
| 856 // depending on their values. In the first interpretation, the first | 875 // depending on their values. In the first interpretation, the first |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 907 (int) totalBytes - currByte < SkAlign2(rowBytes)) { | 926 (int) totalBytes - currByte < SkAlign2(rowBytes)) { |
| 908 SkCodecPrintf("Warning: invalid RLE input.\n"); | 927 SkCodecPrintf("Warning: invalid RLE input.\n"); |
| 909 return kIncompleteInput; | 928 return kIncompleteInput; |
| 910 } | 929 } |
| 911 // Set numPixels number of pixels | 930 // Set numPixels number of pixels |
| 912 while (numPixels > 0) { | 931 while (numPixels > 0) { |
| 913 switch(fBitsPerPixel) { | 932 switch(fBitsPerPixel) { |
| 914 case 4: { | 933 case 4: { |
| 915 SkASSERT(currByte < totalBytes); | 934 SkASSERT(currByte < totalBytes); |
| 916 uint8_t val = buffer.get()[currByte++]; | 935 uint8_t val = buffer.get()[currByte++]; |
| 917 setRLEPixel(dstPtr, dstRowBytes, dstInfo, x++, | 936 setRLEPixel(dst, dstRowBytes, dstInfo, x++, |
| 918 y, val >> 4); | 937 y, val >> 4); |
| 919 numPixels--; | 938 numPixels--; |
| 920 if (numPixels != 0) { | 939 if (numPixels != 0) { |
| 921 setRLEPixel(dstPtr, dstRowBytes, dstInfo, | 940 setRLEPixel(dst, dstRowBytes, dstInfo, |
| 922 x++, y, val & 0xF); | 941 x++, y, val & 0xF); |
| 923 numPixels--; | 942 numPixels--; |
| 924 } | 943 } |
| 925 break; | 944 break; |
| 926 } | 945 } |
| 927 case 8: | 946 case 8: |
| 928 SkASSERT(currByte < totalBytes); | 947 SkASSERT(currByte < totalBytes); |
| 929 setRLEPixel(dstPtr, dstRowBytes, dstInfo, x++, | 948 setRLEPixel(dst, dstRowBytes, dstInfo, x++, |
| 930 y, buffer.get()[currByte++]); | 949 y, buffer.get()[currByte++]); |
| 931 numPixels--; | 950 numPixels--; |
| 932 break; | 951 break; |
| 933 case 24: { | 952 case 24: { |
| 934 SkASSERT(currByte + 2 < totalBytes); | 953 SkASSERT(currByte + 2 < totalBytes); |
| 935 uint8_t blue = buffer.get()[currByte++]; | 954 uint8_t blue = buffer.get()[currByte++]; |
| 936 uint8_t green = buffer.get()[currByte++]; | 955 uint8_t green = buffer.get()[currByte++]; |
| 937 uint8_t red = buffer.get()[currByte++]; | 956 uint8_t red = buffer.get()[currByte++]; |
| 938 setRLE24Pixel(dstPtr, dstRowBytes, dstInfo, | 957 setRLE24Pixel(dst, dstRowBytes, dstInfo, |
| 939 x++, y, red, green, blue); | 958 x++, y, red, green, blue); |
| 940 numPixels--; | 959 numPixels--; |
| 941 } | 960 } |
| 942 default: | 961 default: |
| 943 SkASSERT(false); | 962 SkASSERT(false); |
| 944 return kInvalidInput; | 963 return kInvalidInput; |
| 945 } | 964 } |
| 946 } | 965 } |
| 947 // Skip a byte if necessary to maintain alignment | 966 // Skip a byte if necessary to maintain alignment |
| 948 if (!SkIsAlign2(rowBytes)) { | 967 if (!SkIsAlign2(rowBytes)) { |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 964 if ((int) totalBytes - currByte < 2) { | 983 if ((int) totalBytes - currByte < 2) { |
| 965 SkCodecPrintf("Warning: incomplete RLE input\n"); | 984 SkCodecPrintf("Warning: incomplete RLE input\n"); |
| 966 return kIncompleteInput; | 985 return kIncompleteInput; |
| 967 } | 986 } |
| 968 | 987 |
| 969 // Fill the pixels up to endX with the specified color | 988 // Fill the pixels up to endX with the specified color |
| 970 uint8_t blue = task; | 989 uint8_t blue = task; |
| 971 uint8_t green = buffer.get()[currByte++]; | 990 uint8_t green = buffer.get()[currByte++]; |
| 972 uint8_t red = buffer.get()[currByte++]; | 991 uint8_t red = buffer.get()[currByte++]; |
| 973 while (x < endX) { | 992 while (x < endX) { |
| 974 setRLE24Pixel(dstPtr, dstRowBytes, dstInfo, x++, y, red, | 993 setRLE24Pixel(dst, dstRowBytes, dstInfo, x++, y, red, |
| 975 green, blue); | 994 green, blue); |
| 976 } | 995 } |
| 977 } else { | 996 } else { |
| 978 // In RLE8 or RLE4, the second byte read gives the index in the | 997 // In RLE8 or RLE4, the second byte read gives the index in the |
| 979 // color table to look up the pixel color. | 998 // color table to look up the pixel color. |
| 980 // RLE8 has one color index that gets repeated | 999 // RLE8 has one color index that gets repeated |
| 981 // RLE4 has two color indexes in the upper and lower 4 bits of | 1000 // RLE4 has two color indexes in the upper and lower 4 bits of |
| 982 // the bytes, which are alternated | 1001 // the bytes, which are alternated |
| 983 uint8_t indices[2] = { task, task }; | 1002 uint8_t indices[2] = { task, task }; |
| 984 if (4 == fBitsPerPixel) { | 1003 if (4 == fBitsPerPixel) { |
| 985 indices[0] >>= 4; | 1004 indices[0] >>= 4; |
| 986 indices[1] &= 0xf; | 1005 indices[1] &= 0xf; |
| 987 } | 1006 } |
| 988 | 1007 |
| 989 // Set the indicated number of pixels | 1008 // Set the indicated number of pixels |
| 990 for (int which = 0; x < endX; x++) { | 1009 for (int which = 0; x < endX; x++) { |
| 991 setRLEPixel(dstPtr, dstRowBytes, dstInfo, x, y, | 1010 setRLEPixel(dst, dstRowBytes, dstInfo, x, y, |
| 992 indices[which]); | 1011 indices[which]); |
| 993 which = !which; | 1012 which = !which; |
| 994 } | 1013 } |
| 995 } | 1014 } |
| 996 } | 1015 } |
| 997 } | 1016 } |
| 998 } | 1017 } |
| 999 | 1018 |
| 1000 /* | 1019 /* |
| 1001 * | 1020 * |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1034 config = SkSwizzler::kBGRA; | 1053 config = SkSwizzler::kBGRA; |
| 1035 } | 1054 } |
| 1036 break; | 1055 break; |
| 1037 default: | 1056 default: |
| 1038 SkASSERT(false); | 1057 SkASSERT(false); |
| 1039 return kInvalidInput; | 1058 return kInvalidInput; |
| 1040 } | 1059 } |
| 1041 | 1060 |
| 1042 // Create swizzler | 1061 // Create swizzler |
| 1043 SkAutoTDelete<SkSwizzler> swizzler(SkSwizzler::CreateSwizzler(config, | 1062 SkAutoTDelete<SkSwizzler> swizzler(SkSwizzler::CreateSwizzler(config, |
| 1044 fColorTable->readColors(), dstInfo, dst, dstRowBytes, | 1063 fColorTable, dstInfo, dst, dstRowBytes, |
| 1045 SkImageGenerator::kNo_ZeroInitialized)); | 1064 SkImageGenerator::kNo_ZeroInitialized)); |
| 1046 | 1065 |
| 1047 // Allocate space for a row buffer and a source for the swizzler | 1066 // Allocate space for a row buffer and a source for the swizzler |
| 1048 SkAutoTDeleteArray<uint8_t> srcBuffer(SkNEW_ARRAY(uint8_t, rowBytes)); | 1067 SkAutoTDeleteArray<uint8_t> srcBuffer(SkNEW_ARRAY(uint8_t, rowBytes)); |
| 1049 | 1068 |
| 1050 // Iterate over rows of the image | 1069 // Iterate over rows of the image |
| 1051 // FIXME: bool transparent = true; | 1070 // FIXME: bool transparent = true; |
| 1052 for (int y = 0; y < height; y++) { | 1071 for (int y = 0; y < height; y++) { |
| 1053 // Read a row of the input | 1072 // Read a row of the input |
| 1054 if (stream()->read(srcBuffer.get(), rowBytes) != rowBytes) { | 1073 if (stream()->read(srcBuffer.get(), rowBytes) != rowBytes) { |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 1071 } | 1090 } |
| 1072 | 1091 |
| 1073 // FIXME: This code exists to match the behavior in the chromium decoder | 1092 // FIXME: This code exists to match the behavior in the chromium decoder |
| 1074 // and to follow the bmp specification as it relates to alpha masks. It is | 1093 // and to follow the bmp specification as it relates to alpha masks. It is |
| 1075 // commented out because we have yet to discover a test image that provides | 1094 // commented out because we have yet to discover a test image that provides |
| 1076 // an alpha mask and uses this decode mode. | 1095 // an alpha mask and uses this decode mode. |
| 1077 | 1096 |
| 1078 // Now we adjust the output image with some additional behavior that | 1097 // Now we adjust the output image with some additional behavior that |
| 1079 // SkSwizzler does not support. Firstly, all bmp images that contain | 1098 // SkSwizzler does not support. Firstly, all bmp images that contain |
| 1080 // alpha are masked by the alpha mask. Secondly, many fully transparent | 1099 // alpha are masked by the alpha mask. Secondly, many fully transparent |
| 1081 // bmp images are intended to be opaque. Here, we make those corrections. | 1100 // bmp images are intended to be opaque. Here, we make those corrections |
| 1101 // in the kN32 case. | |
| 1082 /* | 1102 /* |
| 1083 SkPMColor* dstRow = (SkPMColor*) dst; | 1103 SkPMColor* dstRow = (SkPMColor*) dst; |
| 1084 if (SkSwizzler::kBGRA == config) { | 1104 if (SkSwizzler::kBGRA == config) { |
| 1085 for (int y = 0; y < height; y++) { | 1105 for (int y = 0; y < height; y++) { |
| 1086 for (int x = 0; x < width; x++) { | 1106 for (int x = 0; x < width; x++) { |
| 1087 if (transparent) { | 1107 if (transparent) { |
| 1088 dstRow[x] |= 0xFF000000; | 1108 dstRow[x] |= 0xFF000000; |
| 1089 } else { | 1109 } else { |
| 1090 dstRow[x] &= alphaMask; | 1110 dstRow[x] &= alphaMask; |
| 1091 } | 1111 } |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1126 uint32_t alphaBit = | 1146 uint32_t alphaBit = |
| 1127 (srcBuffer.get()[quotient] >> shift) & 0x1; | 1147 (srcBuffer.get()[quotient] >> shift) & 0x1; |
| 1128 dstRow[x] &= alphaBit - 1; | 1148 dstRow[x] &= alphaBit - 1; |
| 1129 } | 1149 } |
| 1130 } | 1150 } |
| 1131 } | 1151 } |
| 1132 | 1152 |
| 1133 // Finished decoding the entire image | 1153 // Finished decoding the entire image |
| 1134 return kSuccess; | 1154 return kSuccess; |
| 1135 } | 1155 } |
| OLD | NEW |