| 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 "SkBitmap.h" | 8 #include "SkBitmap.h" |
| 9 #include "SkCodecPriv.h" | 9 #include "SkCodecPriv.h" |
| 10 #include "SkColorPriv.h" | 10 #include "SkColorPriv.h" |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 79 fPng_ptr = nullptr; | 79 fPng_ptr = nullptr; |
| 80 fInfo_ptr = nullptr; | 80 fInfo_ptr = nullptr; |
| 81 } | 81 } |
| 82 | 82 |
| 83 private: | 83 private: |
| 84 png_structp fPng_ptr; | 84 png_structp fPng_ptr; |
| 85 png_infop fInfo_ptr; | 85 png_infop fInfo_ptr; |
| 86 }; | 86 }; |
| 87 #define AutoCleanPng(...) SK_REQUIRE_LOCAL_VAR(AutoCleanPng) | 87 #define AutoCleanPng(...) SK_REQUIRE_LOCAL_VAR(AutoCleanPng) |
| 88 | 88 |
| 89 // Method for coverting to either an SkPMColor or a similarly packed | |
| 90 // unpremultiplied color. | |
| 91 typedef uint32_t (*PackColorProc)(U8CPU a, U8CPU r, U8CPU g, U8CPU b); | |
| 92 | |
| 93 // Note: SkColorTable claims to store SkPMColors, which is not necessarily | 89 // Note: SkColorTable claims to store SkPMColors, which is not necessarily |
| 94 // the case here. | 90 // the case here. |
| 95 // TODO: If we add support for non-native swizzles, we'll need to handle that he
re. | 91 // TODO: If we add support for non-native swizzles, we'll need to handle that he
re. |
| 96 bool SkPngCodec::decodePalette(bool premultiply, int* ctableCount) { | 92 bool SkPngCodec::decodePalette(bool premultiply, SkColorType dstColorType, int*
ctableCount) { |
| 97 | 93 |
| 98 int numColors; | 94 int numColors; |
| 99 png_color* palette; | 95 png_color* palette; |
| 100 if (!png_get_PLTE(fPng_ptr, fInfo_ptr, &palette, &numColors)) { | 96 if (!png_get_PLTE(fPng_ptr, fInfo_ptr, &palette, &numColors)) { |
| 101 return false; | 97 return false; |
| 102 } | 98 } |
| 103 | 99 |
| 104 // Note: These are not necessarily SkPMColors. | 100 // Note: These are not necessarily SkPMColors. |
| 105 SkPMColor colorPtr[256]; | 101 SkPMColor colorPtr[256]; |
| 106 | 102 |
| 107 png_bytep alphas; | 103 png_bytep alphas; |
| 108 int numColorsWithAlpha = 0; | 104 int numColorsWithAlpha = 0; |
| 109 if (png_get_tRNS(fPng_ptr, fInfo_ptr, &alphas, &numColorsWithAlpha, nullptr)
) { | 105 if (png_get_tRNS(fPng_ptr, fInfo_ptr, &alphas, &numColorsWithAlpha, nullptr)
) { |
| 110 // Choose which function to use to create the color table. If the final
destination's | 106 // Choose which function to use to create the color table. If the final
destination's |
| 111 // colortype is unpremultiplied, the color table will store unpremultipl
ied colors. | 107 // colortype is unpremultiplied, the color table will store unpremultipl
ied colors. |
| 112 PackColorProc proc; | 108 PackColorProc proc = choose_pack_color_proc(premultiply, dstColorType); |
| 113 if (premultiply) { | |
| 114 proc = &SkPremultiplyARGBInline; | |
| 115 } else { | |
| 116 proc = &SkPackARGB32NoCheck; | |
| 117 } | |
| 118 | 109 |
| 119 for (int i = 0; i < numColorsWithAlpha; i++) { | 110 for (int i = 0; i < numColorsWithAlpha; i++) { |
| 120 // We don't have a function in SkOpts that combines a set of alphas
with a set | 111 // We don't have a function in SkOpts that combines a set of alphas
with a set |
| 121 // of RGBs. We could write one, but it's hardly worth it, given tha
t this | 112 // of RGBs. We could write one, but it's hardly worth it, given tha
t this |
| 122 // is such a small fraction of the total decode time. | 113 // is such a small fraction of the total decode time. |
| 123 colorPtr[i] = proc(alphas[i], palette->red, palette->green, palette-
>blue); | 114 colorPtr[i] = proc(alphas[i], palette->red, palette->green, palette-
>blue); |
| 124 palette++; | 115 palette++; |
| 125 } | 116 } |
| 126 } | 117 } |
| 127 | 118 |
| 128 if (numColorsWithAlpha < numColors) { | 119 if (numColorsWithAlpha < numColors) { |
| 129 // The optimized code depends on a 3-byte png_color struct with the colo
rs | 120 // The optimized code depends on a 3-byte png_color struct with the colo
rs |
| 130 // in RGB order. These checks make sure it is safe to use. | 121 // in RGB order. These checks make sure it is safe to use. |
| 131 static_assert(3 == sizeof(png_color), "png_color struct has changed. Op
ts are broken."); | 122 static_assert(3 == sizeof(png_color), "png_color struct has changed. Op
ts are broken."); |
| 132 #ifdef SK_DEBUG | 123 #ifdef SK_DEBUG |
| 133 SkASSERT(&palette->red < &palette->green); | 124 SkASSERT(&palette->red < &palette->green); |
| 134 SkASSERT(&palette->green < &palette->blue); | 125 SkASSERT(&palette->green < &palette->blue); |
| 135 #endif | 126 #endif |
| 136 | 127 |
| 137 #ifdef SK_PMCOLOR_IS_RGBA | 128 if (is_rgba(dstColorType)) { |
| 138 SkOpts::RGB_to_RGB1(colorPtr + numColorsWithAlpha, palette, numColors -
numColorsWithAlpha); | 129 SkOpts::RGB_to_RGB1(colorPtr + numColorsWithAlpha, palette, |
| 139 #else | 130 numColors - numColorsWithAlpha); |
| 140 SkOpts::RGB_to_BGR1(colorPtr + numColorsWithAlpha, palette, numColors -
numColorsWithAlpha); | 131 } else { |
| 141 #endif | 132 SkOpts::RGB_to_BGR1(colorPtr + numColorsWithAlpha, palette, |
| 133 numColors - numColorsWithAlpha); |
| 134 } |
| 142 } | 135 } |
| 143 | 136 |
| 144 // Pad the color table with the last color in the table (or black) in the ca
se that | 137 // Pad the color table with the last color in the table (or black) in the ca
se that |
| 145 // invalid pixel indices exceed the number of colors in the table. | 138 // invalid pixel indices exceed the number of colors in the table. |
| 146 const int maxColors = 1 << fBitDepth; | 139 const int maxColors = 1 << fBitDepth; |
| 147 if (numColors < maxColors) { | 140 if (numColors < maxColors) { |
| 148 SkPMColor lastColor = numColors > 0 ? colorPtr[numColors - 1] : SK_Color
BLACK; | 141 SkPMColor lastColor = numColors > 0 ? colorPtr[numColors - 1] : SK_Color
BLACK; |
| 149 sk_memset32(colorPtr + numColors, lastColor, maxColors - numColors); | 142 sk_memset32(colorPtr + numColors, lastColor, maxColors - numColors); |
| 150 } | 143 } |
| 151 | 144 |
| (...skipping 266 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 418 return true; | 411 return true; |
| 419 } | 412 } |
| 420 | 413 |
| 421 SkPngCodec::SkPngCodec(const SkEncodedInfo& info, SkStream* stream, SkPngChunkRe
ader* chunkReader, | 414 SkPngCodec::SkPngCodec(const SkEncodedInfo& info, SkStream* stream, SkPngChunkRe
ader* chunkReader, |
| 422 png_structp png_ptr, png_infop info_ptr, int bitDepth, in
t numberPasses, | 415 png_structp png_ptr, png_infop info_ptr, int bitDepth, in
t numberPasses, |
| 423 sk_sp<SkColorSpace> colorSpace) | 416 sk_sp<SkColorSpace> colorSpace) |
| 424 : INHERITED(info, stream, colorSpace) | 417 : INHERITED(info, stream, colorSpace) |
| 425 , fPngChunkReader(SkSafeRef(chunkReader)) | 418 , fPngChunkReader(SkSafeRef(chunkReader)) |
| 426 , fPng_ptr(png_ptr) | 419 , fPng_ptr(png_ptr) |
| 427 , fInfo_ptr(info_ptr) | 420 , fInfo_ptr(info_ptr) |
| 428 , fSrcConfig(SkSwizzler::kUnknown) | |
| 429 , fNumberPasses(numberPasses) | 421 , fNumberPasses(numberPasses) |
| 430 , fBitDepth(bitDepth) | 422 , fBitDepth(bitDepth) |
| 431 {} | 423 {} |
| 432 | 424 |
| 433 SkPngCodec::~SkPngCodec() { | 425 SkPngCodec::~SkPngCodec() { |
| 434 this->destroyReadStruct(); | 426 this->destroyReadStruct(); |
| 435 } | 427 } |
| 436 | 428 |
| 437 void SkPngCodec::destroyReadStruct() { | 429 void SkPngCodec::destroyReadStruct() { |
| 438 if (fPng_ptr) { | 430 if (fPng_ptr) { |
| (...skipping 14 matching lines...) Expand all Loading... |
| 453 SkPMColor ctable[], | 445 SkPMColor ctable[], |
| 454 int* ctableCount) { | 446 int* ctableCount) { |
| 455 // FIXME: Could we use the return value of setjmp to specify the type of | 447 // FIXME: Could we use the return value of setjmp to specify the type of |
| 456 // error? | 448 // error? |
| 457 if (setjmp(png_jmpbuf(fPng_ptr))) { | 449 if (setjmp(png_jmpbuf(fPng_ptr))) { |
| 458 SkCodecPrintf("setjmp long jump!\n"); | 450 SkCodecPrintf("setjmp long jump!\n"); |
| 459 return kInvalidInput; | 451 return kInvalidInput; |
| 460 } | 452 } |
| 461 png_read_update_info(fPng_ptr, fInfo_ptr); | 453 png_read_update_info(fPng_ptr, fInfo_ptr); |
| 462 | 454 |
| 463 // suggestedColorType was determined in read_header() based on the encodedCo
lorType | 455 if (SkEncodedInfo::kPalette_Color == this->getEncodedInfo().color()) { |
| 464 const SkColorType suggestedColorType = this->getInfo().colorType(); | 456 if (!this->decodePalette(kPremul_SkAlphaType == requestedInfo.alphaType(
), |
| 465 | 457 requestedInfo.colorType(), ctableCount)) { |
| 466 switch (suggestedColorType) { | 458 return kInvalidInput; |
| 467 case kIndex_8_SkColorType: | |
| 468 //decode palette to Skia format | |
| 469 fSrcConfig = SkSwizzler::kIndex; | |
| 470 if (!this->decodePalette(kPremul_SkAlphaType == requestedInfo.alphaT
ype(), | |
| 471 ctableCount)) { | |
| 472 return kInvalidInput; | |
| 473 } | |
| 474 break; | |
| 475 case kGray_8_SkColorType: | |
| 476 fSrcConfig = SkSwizzler::kGray; | |
| 477 break; | |
| 478 case kN32_SkColorType: { | |
| 479 const uint8_t encodedColorType = png_get_color_type(fPng_ptr, fInfo_
ptr); | |
| 480 if (PNG_COLOR_TYPE_GRAY_ALPHA == encodedColorType || | |
| 481 PNG_COLOR_TYPE_GRAY == encodedColorType) { | |
| 482 // If encodedColorType is GRAY, there must be a transparent chun
k. | |
| 483 // Otherwise, suggestedColorType would be kGray. We have alread
y | |
| 484 // instructed libpng to convert the transparent chunk to alpha, | |
| 485 // so we can treat both GRAY and GRAY_ALPHA as kGrayAlpha. | |
| 486 SkASSERT(encodedColorType == PNG_COLOR_TYPE_GRAY_ALPHA || | |
| 487 png_get_valid(fPng_ptr, fInfo_ptr, PNG_INFO_tRNS)); | |
| 488 | |
| 489 fSrcConfig = SkSwizzler::kGrayAlpha; | |
| 490 } else { | |
| 491 if (this->getInfo().alphaType() == kOpaque_SkAlphaType) { | |
| 492 fSrcConfig = SkSwizzler::kRGB; | |
| 493 } else { | |
| 494 fSrcConfig = SkSwizzler::kRGBA; | |
| 495 } | |
| 496 } | |
| 497 break; | |
| 498 } | 459 } |
| 499 default: | |
| 500 // We will always recommend one of the above colorTypes. | |
| 501 SkASSERT(false); | |
| 502 } | 460 } |
| 503 | 461 |
| 504 // Copy the color table to the client if they request kIndex8 mode | 462 // Copy the color table to the client if they request kIndex8 mode |
| 505 copy_color_table(requestedInfo, fColorTable, ctable, ctableCount); | 463 copy_color_table(requestedInfo, fColorTable, ctable, ctableCount); |
| 506 | 464 |
| 507 // Create the swizzler. SkPngCodec retains ownership of the color table. | 465 // Create the swizzler. SkPngCodec retains ownership of the color table. |
| 508 const SkPMColor* colors = get_color_ptr(fColorTable.get()); | 466 const SkPMColor* colors = get_color_ptr(fColorTable.get()); |
| 509 fSwizzler.reset(SkSwizzler::CreateSwizzler(fSrcConfig, colors, requestedInfo
, options)); | 467 fSwizzler.reset(SkSwizzler::CreateSwizzler(this->getEncodedInfo(), colors, r
equestedInfo, |
| 468 options)); |
| 510 SkASSERT(fSwizzler); | 469 SkASSERT(fSwizzler); |
| 511 | 470 |
| 512 return kSuccess; | 471 return kSuccess; |
| 513 } | 472 } |
| 514 | 473 |
| 515 | 474 |
| 516 bool SkPngCodec::onRewind() { | 475 bool SkPngCodec::onRewind() { |
| 517 // This sets fPng_ptr and fInfo_ptr to nullptr. If read_header | 476 // This sets fPng_ptr and fInfo_ptr to nullptr. If read_header |
| 518 // succeeds, they will be repopulated, and if it fails, they will | 477 // succeeds, they will be repopulated, and if it fails, they will |
| 519 // remain nullptr. Any future accesses to fPng_ptr and fInfo_ptr will | 478 // remain nullptr. Any future accesses to fPng_ptr and fInfo_ptr will |
| (...skipping 26 matching lines...) Expand all Loading... |
| 546 } | 505 } |
| 547 | 506 |
| 548 // Note that ctable and ctableCount may be modified if there is a color tabl
e | 507 // Note that ctable and ctableCount may be modified if there is a color tabl
e |
| 549 const Result result = this->initializeSwizzler(requestedInfo, options, ctabl
e, ctableCount); | 508 const Result result = this->initializeSwizzler(requestedInfo, options, ctabl
e, ctableCount); |
| 550 if (result != kSuccess) { | 509 if (result != kSuccess) { |
| 551 return result; | 510 return result; |
| 552 } | 511 } |
| 553 | 512 |
| 554 const int width = requestedInfo.width(); | 513 const int width = requestedInfo.width(); |
| 555 const int height = requestedInfo.height(); | 514 const int height = requestedInfo.height(); |
| 556 const int bpp = SkSwizzler::BytesPerPixel(fSrcConfig); | 515 const int bpp = this->getEncodedInfo().bytesPerPixel(); |
| 557 const size_t srcRowBytes = width * bpp; | 516 const size_t srcRowBytes = width * bpp; |
| 558 | 517 |
| 559 // FIXME: Could we use the return value of setjmp to specify the type of | 518 // FIXME: Could we use the return value of setjmp to specify the type of |
| 560 // error? | 519 // error? |
| 561 int row = 0; | 520 int row = 0; |
| 562 // This must be declared above the call to setjmp to avoid memory leaks on i
ncomplete images. | 521 // This must be declared above the call to setjmp to avoid memory leaks on i
ncomplete images. |
| 563 SkAutoTMalloc<uint8_t> storage; | 522 SkAutoTMalloc<uint8_t> storage; |
| 564 if (setjmp(png_jmpbuf(fPng_ptr))) { | 523 if (setjmp(png_jmpbuf(fPng_ptr))) { |
| 565 // Assume that any error that occurs while reading rows is caused by an
incomplete input. | 524 // Assume that any error that occurs while reading rows is caused by an
incomplete input. |
| 566 if (fNumberPasses > 1) { | 525 if (fNumberPasses > 1) { |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 642 if (!conversion_possible(dstInfo, this->getInfo())) { | 601 if (!conversion_possible(dstInfo, this->getInfo())) { |
| 643 return kInvalidConversion; | 602 return kInvalidConversion; |
| 644 } | 603 } |
| 645 | 604 |
| 646 const Result result = this->initializeSwizzler(dstInfo, options, ctable, | 605 const Result result = this->initializeSwizzler(dstInfo, options, ctable, |
| 647 ctableCount); | 606 ctableCount); |
| 648 if (result != kSuccess) { | 607 if (result != kSuccess) { |
| 649 return result; | 608 return result; |
| 650 } | 609 } |
| 651 | 610 |
| 652 fStorage.reset(this->getInfo().width() * SkSwizzler::BytesPerPixel(this-
>srcConfig())); | 611 fStorage.reset(this->getInfo().width() * this->getEncodedInfo().bytesPer
Pixel()); |
| 653 fSrcRow = fStorage.get(); | 612 fSrcRow = fStorage.get(); |
| 654 | 613 |
| 655 return kSuccess; | 614 return kSuccess; |
| 656 } | 615 } |
| 657 | 616 |
| 658 int onGetScanlines(void* dst, int count, size_t rowBytes) override { | 617 int onGetScanlines(void* dst, int count, size_t rowBytes) override { |
| 659 // Assume that an error in libpng indicates an incomplete input. | 618 // Assume that an error in libpng indicates an incomplete input. |
| 660 int row = 0; | 619 int row = 0; |
| 661 if (setjmp(png_jmpbuf(this->png_ptr()))) { | 620 if (setjmp(png_jmpbuf(this->png_ptr()))) { |
| 662 SkCodecPrintf("setjmp long jump!\n"); | 621 SkCodecPrintf("setjmp long jump!\n"); |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 714 } | 673 } |
| 715 | 674 |
| 716 const Result result = this->initializeSwizzler(dstInfo, options, ctable, | 675 const Result result = this->initializeSwizzler(dstInfo, options, ctable, |
| 717 ctableCount); | 676 ctableCount); |
| 718 if (result != kSuccess) { | 677 if (result != kSuccess) { |
| 719 return result; | 678 return result; |
| 720 } | 679 } |
| 721 | 680 |
| 722 fHeight = dstInfo.height(); | 681 fHeight = dstInfo.height(); |
| 723 // FIXME: This need not be called on a second call to onStartScanlineDec
ode. | 682 // FIXME: This need not be called on a second call to onStartScanlineDec
ode. |
| 724 fSrcRowBytes = this->getInfo().width() * SkSwizzler::BytesPerPixel(this-
>srcConfig()); | 683 fSrcRowBytes = this->getInfo().width() * this->getEncodedInfo().bytesPer
Pixel(); |
| 725 fGarbageRow.reset(fSrcRowBytes); | 684 fGarbageRow.reset(fSrcRowBytes); |
| 726 fGarbageRowPtr = static_cast<uint8_t*>(fGarbageRow.get()); | 685 fGarbageRowPtr = static_cast<uint8_t*>(fGarbageRow.get()); |
| 727 fCanSkipRewind = true; | 686 fCanSkipRewind = true; |
| 728 | 687 |
| 729 return SkCodec::kSuccess; | 688 return SkCodec::kSuccess; |
| 730 } | 689 } |
| 731 | 690 |
| 732 int onGetScanlines(void* dst, int count, size_t dstRowBytes) override { | 691 int onGetScanlines(void* dst, int count, size_t dstRowBytes) override { |
| 733 // rewind stream if have previously called onGetScanlines, | 692 // rewind stream if have previously called onGetScanlines, |
| 734 // since we need entire progressive image to get scanlines | 693 // since we need entire progressive image to get scanlines |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 835 | 794 |
| 836 if (1 == numberPasses) { | 795 if (1 == numberPasses) { |
| 837 return new SkPngScanlineDecoder(imageInfo, streamDeleter.release(), chun
kReader, | 796 return new SkPngScanlineDecoder(imageInfo, streamDeleter.release(), chun
kReader, |
| 838 png_ptr, info_ptr, bitDepth, colorSpace)
; | 797 png_ptr, info_ptr, bitDepth, colorSpace)
; |
| 839 } | 798 } |
| 840 | 799 |
| 841 return new SkPngInterlacedScanlineDecoder(imageInfo, streamDeleter.release()
, chunkReader, | 800 return new SkPngInterlacedScanlineDecoder(imageInfo, streamDeleter.release()
, chunkReader, |
| 842 png_ptr, info_ptr, bitDepth, numbe
rPasses, | 801 png_ptr, info_ptr, bitDepth, numbe
rPasses, |
| 843 colorSpace); | 802 colorSpace); |
| 844 } | 803 } |
| OLD | NEW |