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_libpng.h" | 8 #include "SkCodec_libpng.h" |
9 #include "SkCodecPriv.h" | 9 #include "SkCodecPriv.h" |
10 #include "SkColorPriv.h" | 10 #include "SkColorPriv.h" |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
113 png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL); | 113 png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL); |
114 return num_trans > 0; | 114 return num_trans > 0; |
115 } | 115 } |
116 | 116 |
117 // Method for coverting to either an SkPMColor or a similarly packed | 117 // Method for coverting to either an SkPMColor or a similarly packed |
118 // unpremultiplied color. | 118 // unpremultiplied color. |
119 typedef uint32_t (*PackColorProc)(U8CPU a, U8CPU r, U8CPU g, U8CPU b); | 119 typedef uint32_t (*PackColorProc)(U8CPU a, U8CPU r, U8CPU g, U8CPU b); |
120 | 120 |
121 // Note: SkColorTable claims to store SkPMColors, which is not necessarily | 121 // Note: SkColorTable claims to store SkPMColors, which is not necessarily |
122 // the case here. | 122 // the case here. |
123 bool SkPngCodec::decodePalette(bool premultiply, int bitDepth, int* ctableCount)
{ | 123 bool SkPngCodec::decodePalette(bool premultiply, int* ctableCount) { |
124 int numPalette; | 124 int numPalette; |
125 png_colorp palette; | 125 png_colorp palette; |
126 png_bytep trans; | 126 png_bytep trans; |
127 | 127 |
128 if (!png_get_PLTE(fPng_ptr, fInfo_ptr, &palette, &numPalette)) { | 128 if (!png_get_PLTE(fPng_ptr, fInfo_ptr, &palette, &numPalette)) { |
129 return false; | 129 return false; |
130 } | 130 } |
131 | 131 |
132 // Note: These are not necessarily SkPMColors | 132 // Note: These are not necessarily SkPMColors |
133 SkPMColor colorStorage[256]; // worst-case storage | 133 SkPMColor colorStorage[256]; // worst-case storage |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
170 } | 170 } |
171 | 171 |
172 /* BUGGY IMAGE WORKAROUND | 172 /* BUGGY IMAGE WORKAROUND |
173 Invalid images could contain pixel values that are greater than the numb
er of palette | 173 Invalid images could contain pixel values that are greater than the numb
er of palette |
174 entries. Since we use pixel values as indices into the palette this coul
d result in reading | 174 entries. Since we use pixel values as indices into the palette this coul
d result in reading |
175 beyond the end of the palette which could leak the contents of uninitial
ized memory. To | 175 beyond the end of the palette which could leak the contents of uninitial
ized memory. To |
176 ensure this doesn't happen, we grow the colortable to the maximum size t
hat can be | 176 ensure this doesn't happen, we grow the colortable to the maximum size t
hat can be |
177 addressed by the bitdepth of the image and fill it with the last palette
color or black if | 177 addressed by the bitdepth of the image and fill it with the last palette
color or black if |
178 the palette is empty (really broken image). | 178 the palette is empty (really broken image). |
179 */ | 179 */ |
180 int colorCount = SkTMax(numPalette, 1 << SkTMin(bitDepth, 8)); | 180 int colorCount = SkTMax(numPalette, 1 << SkTMin(fBitDepth, 8)); |
181 SkPMColor lastColor = index > 0 ? colorPtr[-1] : SkPackARGB32(0xFF, 0, 0, 0)
; | 181 SkPMColor lastColor = index > 0 ? colorPtr[-1] : SkPackARGB32(0xFF, 0, 0, 0)
; |
182 for (; index < colorCount; index++) { | 182 for (; index < colorCount; index++) { |
183 *colorPtr++ = lastColor; | 183 *colorPtr++ = lastColor; |
184 } | 184 } |
185 | 185 |
186 // Set the new color count | 186 // Set the new color count |
187 if (ctableCount != NULL) { | 187 if (ctableCount != NULL) { |
188 *ctableCount = colorCount; | 188 *ctableCount = colorCount; |
189 } | 189 } |
190 | 190 |
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
367 : INHERITED(info, stream) | 367 : INHERITED(info, stream) |
368 , fPng_ptr(png_ptr) | 368 , fPng_ptr(png_ptr) |
369 , fInfo_ptr(info_ptr) | 369 , fInfo_ptr(info_ptr) |
370 , fSrcConfig(SkSwizzler::kUnknown) | 370 , fSrcConfig(SkSwizzler::kUnknown) |
371 , fNumberPasses(INVALID_NUMBER_PASSES) | 371 , fNumberPasses(INVALID_NUMBER_PASSES) |
372 , fReallyHasAlpha(false) | 372 , fReallyHasAlpha(false) |
373 , fBitDepth(bitDepth) | 373 , fBitDepth(bitDepth) |
374 {} | 374 {} |
375 | 375 |
376 SkPngCodec::~SkPngCodec() { | 376 SkPngCodec::~SkPngCodec() { |
377 // First, ensure that the scanline decoder is left in a finished state. | |
378 SkAutoTDelete<SkScanlineDecoder> decoder(this->detachScanlineDecoder()); | |
379 if (NULL != decoder) { | |
380 this->finish(); | |
381 } | |
382 | |
383 this->destroyReadStruct(); | 377 this->destroyReadStruct(); |
384 } | 378 } |
385 | 379 |
386 void SkPngCodec::destroyReadStruct() { | 380 void SkPngCodec::destroyReadStruct() { |
387 if (fPng_ptr) { | 381 if (fPng_ptr) { |
388 // We will never have a NULL fInfo_ptr with a non-NULL fPng_ptr | 382 // We will never have a NULL fInfo_ptr with a non-NULL fPng_ptr |
389 SkASSERT(fInfo_ptr); | 383 SkASSERT(fInfo_ptr); |
390 png_destroy_read_struct(&fPng_ptr, &fInfo_ptr, png_infopp_NULL); | 384 png_destroy_read_struct(&fPng_ptr, &fInfo_ptr, png_infopp_NULL); |
391 fPng_ptr = NULL; | 385 fPng_ptr = NULL; |
392 fInfo_ptr = NULL; | 386 fInfo_ptr = NULL; |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
447 // Set to the default before calling decodePalette, which may change it. | 441 // Set to the default before calling decodePalette, which may change it. |
448 fReallyHasAlpha = false; | 442 fReallyHasAlpha = false; |
449 | 443 |
450 //srcColorType was determined in readHeader() which determined png color typ
e | 444 //srcColorType was determined in readHeader() which determined png color typ
e |
451 const SkColorType srcColorType = this->getInfo().colorType(); | 445 const SkColorType srcColorType = this->getInfo().colorType(); |
452 | 446 |
453 switch (srcColorType) { | 447 switch (srcColorType) { |
454 case kIndex_8_SkColorType: | 448 case kIndex_8_SkColorType: |
455 //decode palette to Skia format | 449 //decode palette to Skia format |
456 fSrcConfig = SkSwizzler::kIndex; | 450 fSrcConfig = SkSwizzler::kIndex; |
457 if (!this->decodePalette(kPremul_SkAlphaType == requestedInfo.alphaT
ype(), fBitDepth, | 451 if (!this->decodePalette(kPremul_SkAlphaType == requestedInfo.alphaT
ype(), |
458 ctableCount)) { | 452 ctableCount)) { |
459 return kInvalidInput; | 453 return kInvalidInput; |
460 } | 454 } |
461 break; | 455 break; |
462 case kGray_8_SkColorType: | 456 case kGray_8_SkColorType: |
463 fSrcConfig = SkSwizzler::kGray; | 457 fSrcConfig = SkSwizzler::kGray; |
464 break; | 458 break; |
465 case kN32_SkColorType: | 459 case kN32_SkColorType: |
466 if (this->getInfo().alphaType() == kOpaque_SkAlphaType) { | 460 if (this->getInfo().alphaType() == kOpaque_SkAlphaType) { |
467 fSrcConfig = SkSwizzler::kRGBX; | 461 fSrcConfig = SkSwizzler::kRGBX; |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
516 return false; | 510 return false; |
517 } | 511 } |
518 } | 512 } |
519 | 513 |
520 SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void*
dst, | 514 SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void*
dst, |
521 size_t rowBytes, const Options& options, | 515 size_t rowBytes, const Options& options, |
522 SkPMColor ctable[], int* ctableCount) { | 516 SkPMColor ctable[], int* ctableCount) { |
523 if (!conversion_possible(requestedInfo, this->getInfo())) { | 517 if (!conversion_possible(requestedInfo, this->getInfo())) { |
524 return kInvalidConversion; | 518 return kInvalidConversion; |
525 } | 519 } |
526 // Do not allow a regular decode if the caller has asked for a scanline deco
der | |
527 if (NULL != this->scanlineDecoder()) { | |
528 SkCodecPrintf("cannot getPixels() if a scanline decoder has been created
\n"); | |
529 return kInvalidParameters; | |
530 } | |
531 if (requestedInfo.dimensions() != this->getInfo().dimensions()) { | 520 if (requestedInfo.dimensions() != this->getInfo().dimensions()) { |
532 return kInvalidScale; | 521 return kInvalidScale; |
533 } | 522 } |
534 if (!this->handleRewind()) { | 523 if (!this->handleRewind()) { |
535 return kCouldNotRewind; | 524 return kCouldNotRewind; |
536 } | 525 } |
537 | 526 |
538 // Note that ctable and ctableCount may be modified if there is a color tabl
e | 527 // Note that ctable and ctableCount may be modified if there is a color tabl
e |
539 const Result result = this->initializeSwizzler(requestedInfo, dst, rowBytes, | 528 const Result result = this->initializeSwizzler(requestedInfo, dst, rowBytes, |
540 options, ctable, ctableCount)
; | 529 options, ctable, ctableCount)
; |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
589 | 578 |
590 this->finish(); | 579 this->finish(); |
591 return kSuccess; | 580 return kSuccess; |
592 } | 581 } |
593 | 582 |
594 void SkPngCodec::finish() { | 583 void SkPngCodec::finish() { |
595 if (setjmp(png_jmpbuf(fPng_ptr))) { | 584 if (setjmp(png_jmpbuf(fPng_ptr))) { |
596 // We've already read all the scanlines. This is a success. | 585 // We've already read all the scanlines. This is a success. |
597 return; | 586 return; |
598 } | 587 } |
| 588 // FIXME: Is this necessary? |
599 /* read rest of file, and get additional chunks in info_ptr - REQUIRED */ | 589 /* read rest of file, and get additional chunks in info_ptr - REQUIRED */ |
600 png_read_end(fPng_ptr, fInfo_ptr); | 590 png_read_end(fPng_ptr, fInfo_ptr); |
601 } | 591 } |
602 | 592 |
603 class SkPngScanlineDecoder : public SkScanlineDecoder { | 593 class SkPngScanlineDecoder : public SkScanlineDecoder { |
604 public: | 594 public: |
605 SkPngScanlineDecoder(const SkImageInfo& dstInfo, SkPngCodec* codec) | 595 SkPngScanlineDecoder(const SkImageInfo& dstInfo, SkPngCodec* codec) |
606 : INHERITED(dstInfo) | 596 : INHERITED(dstInfo) |
607 , fCodec(codec) | 597 , fCodec(codec) |
608 , fHasAlpha(false) | 598 , fHasAlpha(false) |
609 { | 599 { |
610 fStorage.reset(dstInfo.width() * SkSwizzler::BytesPerPixel(fCodec->fSrcC
onfig)); | 600 fStorage.reset(dstInfo.width() * SkSwizzler::BytesPerPixel(fCodec->fSrcC
onfig)); |
611 fSrcRow = static_cast<uint8_t*>(fStorage.get()); | 601 fSrcRow = static_cast<uint8_t*>(fStorage.get()); |
612 } | 602 } |
613 | 603 |
| 604 ~SkPngScanlineDecoder() { |
| 605 fCodec->finish(); |
| 606 } |
| 607 |
614 SkCodec::Result onGetScanlines(void* dst, int count, size_t rowBytes) overri
de { | 608 SkCodec::Result onGetScanlines(void* dst, int count, size_t rowBytes) overri
de { |
615 if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) { | 609 if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) { |
616 SkCodecPrintf("setjmp long jump!\n"); | 610 SkCodecPrintf("setjmp long jump!\n"); |
617 return SkCodec::kInvalidInput; | 611 return SkCodec::kInvalidInput; |
618 } | 612 } |
619 | 613 |
620 for (int i = 0; i < count; i++) { | 614 for (int i = 0; i < count; i++) { |
621 png_read_rows(fCodec->fPng_ptr, &fSrcRow, png_bytepp_NULL, 1); | 615 png_read_rows(fCodec->fPng_ptr, &fSrcRow, png_bytepp_NULL, 1); |
622 fCodec->fSwizzler->setDstRow(dst); | 616 fCodec->fSwizzler->setDstRow(dst); |
623 fHasAlpha |= !SkSwizzler::IsOpaque(fCodec->fSwizzler->next(fSrcRow))
; | 617 fHasAlpha |= !SkSwizzler::IsOpaque(fCodec->fSwizzler->next(fSrcRow))
; |
(...skipping 14 matching lines...) Expand all Loading... |
638 //as png_read_rows has it's own loop which calls png_read_row count time
s. | 632 //as png_read_rows has it's own loop which calls png_read_row count time
s. |
639 for (int i = 0; i < count; i++) { | 633 for (int i = 0; i < count; i++) { |
640 png_read_rows(fCodec->fPng_ptr, &fSrcRow, png_bytepp_NULL, 1); | 634 png_read_rows(fCodec->fPng_ptr, &fSrcRow, png_bytepp_NULL, 1); |
641 } | 635 } |
642 return SkCodec::kSuccess; | 636 return SkCodec::kSuccess; |
643 } | 637 } |
644 | 638 |
645 bool onReallyHasAlpha() const override { return fHasAlpha; } | 639 bool onReallyHasAlpha() const override { return fHasAlpha; } |
646 | 640 |
647 private: | 641 private: |
648 SkPngCodec* fCodec; // Unowned. | 642 SkAutoTDelete<SkPngCodec> fCodec; |
649 bool fHasAlpha; | 643 bool fHasAlpha; |
650 SkAutoMalloc fStorage; | 644 SkAutoMalloc fStorage; |
651 uint8_t* fSrcRow; | 645 uint8_t* fSrcRow; |
652 | 646 |
653 typedef SkScanlineDecoder INHERITED; | 647 typedef SkScanlineDecoder INHERITED; |
654 }; | 648 }; |
655 | 649 |
656 | 650 |
657 class SkPngInterlacedScanlineDecoder : public SkScanlineDecoder { | 651 class SkPngInterlacedScanlineDecoder : public SkScanlineDecoder { |
658 public: | 652 public: |
659 SkPngInterlacedScanlineDecoder(const SkImageInfo& dstInfo, SkPngCodec* codec
) | 653 SkPngInterlacedScanlineDecoder(const SkImageInfo& dstInfo, SkPngCodec* codec
) |
660 : INHERITED(dstInfo) | 654 : INHERITED(dstInfo) |
661 , fCodec(codec) | 655 , fCodec(codec) |
662 , fHasAlpha(false) | 656 , fHasAlpha(false) |
663 , fCurrentRow(0) | 657 , fCurrentRow(0) |
664 , fHeight(dstInfo.height()) | 658 , fHeight(dstInfo.height()) |
665 , fRewindNeeded(false) | |
666 { | 659 { |
667 fSrcRowBytes = dstInfo.width() * SkSwizzler::BytesPerPixel(fCodec->fSrcC
onfig); | 660 fSrcRowBytes = dstInfo.width() * SkSwizzler::BytesPerPixel(fCodec->fSrcC
onfig); |
668 fGarbageRow.reset(fSrcRowBytes); | 661 fGarbageRow.reset(fSrcRowBytes); |
669 fGarbageRowPtr = static_cast<uint8_t*>(fGarbageRow.get()); | 662 fGarbageRowPtr = static_cast<uint8_t*>(fGarbageRow.get()); |
670 } | 663 } |
671 | 664 |
| 665 ~SkPngInterlacedScanlineDecoder() { |
| 666 fCodec->finish(); |
| 667 } |
| 668 |
672 SkCodec::Result onGetScanlines(void* dst, int count, size_t dstRowBytes) ove
rride { | 669 SkCodec::Result onGetScanlines(void* dst, int count, size_t dstRowBytes) ove
rride { |
673 //rewind stream if have previously called onGetScanlines, | 670 //rewind stream if have previously called onGetScanlines, |
674 //since we need entire progressive image to get scanlines | 671 //since we need entire progressive image to get scanlines |
675 if (fRewindNeeded) { | 672 if (!fCodec->handleRewind()) { |
676 if(false == fCodec->handleRewind()) { | 673 return SkCodec::kCouldNotRewind; |
677 return SkCodec::kCouldNotRewind; | |
678 } | |
679 } else { | |
680 fRewindNeeded = true; | |
681 } | 674 } |
682 if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) { | 675 if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) { |
683 SkCodecPrintf("setjmp long jump!\n"); | 676 SkCodecPrintf("setjmp long jump!\n"); |
684 return SkCodec::kInvalidInput; | 677 return SkCodec::kInvalidInput; |
685 } | 678 } |
686 const int number_passes = png_set_interlace_handling(fCodec->fPng_ptr); | 679 const int number_passes = png_set_interlace_handling(fCodec->fPng_ptr); |
687 SkAutoMalloc storage(count * fSrcRowBytes); | 680 SkAutoMalloc storage(count * fSrcRowBytes); |
688 uint8_t* storagePtr = static_cast<uint8_t*>(storage.get()); | 681 uint8_t* storagePtr = static_cast<uint8_t*>(storage.get()); |
689 uint8_t* srcRow; | 682 uint8_t* srcRow; |
690 for (int i = 0; i < number_passes; i++) { | 683 for (int i = 0; i < number_passes; i++) { |
(...skipping 26 matching lines...) Expand all Loading... |
717 | 710 |
718 SkCodec::Result onSkipScanlines(int count) override { | 711 SkCodec::Result onSkipScanlines(int count) override { |
719 //when ongetScanlines is called it will skip to fCurrentRow | 712 //when ongetScanlines is called it will skip to fCurrentRow |
720 fCurrentRow += count; | 713 fCurrentRow += count; |
721 return SkCodec::kSuccess; | 714 return SkCodec::kSuccess; |
722 } | 715 } |
723 | 716 |
724 bool onReallyHasAlpha() const override { return fHasAlpha; } | 717 bool onReallyHasAlpha() const override { return fHasAlpha; } |
725 | 718 |
726 private: | 719 private: |
727 SkPngCodec* fCodec; // Unowned. | 720 SkAutoTDelete<SkPngCodec> fCodec; |
728 bool fHasAlpha; | 721 bool fHasAlpha; |
729 int fCurrentRow; | 722 int fCurrentRow; |
730 int fHeight; | 723 int fHeight; |
731 size_t fSrcRowBytes; | 724 size_t fSrcRowBytes; |
732 bool fRewindNeeded; | 725 SkAutoMalloc fGarbageRow; |
733 SkAutoMalloc fGarbageRow; | 726 uint8_t* fGarbageRowPtr; |
734 uint8_t* fGarbageRowPtr; | |
735 | 727 |
736 typedef SkScanlineDecoder INHERITED; | 728 typedef SkScanlineDecoder INHERITED; |
737 }; | 729 }; |
738 | 730 |
739 | 731 |
740 SkScanlineDecoder* SkPngCodec::onGetScanlineDecoder(const SkImageInfo& dstInfo, | 732 SkScanlineDecoder* SkPngCodec::onGetScanlineDecoder(const SkImageInfo& dstInfo, |
741 const Options& options, SkPMColor ctable[], int* ctableCount) { | 733 const Options& options, SkPMColor ctable[], int* ctableCount) { |
742 if (!conversion_possible(dstInfo, this->getInfo())) { | 734 if (!conversion_possible(dstInfo, this->getInfo())) { |
743 SkCodecPrintf("no conversion possible\n"); | 735 SkCodecPrintf("no conversion possible\n"); |
744 return NULL; | 736 return NULL; |
745 } | 737 } |
746 // Check to see if scaling was requested. | 738 // Check to see if scaling was requested. |
747 if (dstInfo.dimensions() != this->getInfo().dimensions()) { | 739 if (dstInfo.dimensions() != this->getInfo().dimensions()) { |
748 return NULL; | 740 return NULL; |
749 } | 741 } |
750 if (!this->handleRewind()) { | 742 // Create a new SkPngCodec, to be owned by the scanline decoder. |
| 743 SkStream* stream = this->stream()->duplicate(); |
| 744 if (!stream) { |
| 745 return NULL; |
| 746 } |
| 747 SkAutoTDelete<SkPngCodec> codec (static_cast<SkPngCodec*>(SkPngCodec::NewFro
mStream(stream))); |
| 748 if (!codec) { |
751 return NULL; | 749 return NULL; |
752 } | 750 } |
753 | 751 |
754 // Note: We set dst to NULL since we do not know it yet. rowBytes is not nee
ded, | 752 // Note: We set dst to NULL since we do not know it yet. rowBytes is not nee
ded, |
755 // since we'll be manually updating the dstRow, but the SkSwizzler requires
it to | 753 // since we'll be manually updating the dstRow, but the SkSwizzler requires
it to |
756 // be at least dstInfo.minRowBytes. | 754 // be at least dstInfo.minRowBytes. |
757 if (this->initializeSwizzler(dstInfo, NULL, dstInfo.minRowBytes(), options,
ctable, | 755 if (codec->initializeSwizzler(dstInfo, NULL, dstInfo.minRowBytes(), options,
ctable, |
758 ctableCount) != kSuccess) { | 756 ctableCount) != kSuccess) { |
759 SkCodecPrintf("failed to initialize the swizzler.\n"); | 757 SkCodecPrintf("failed to initialize the swizzler.\n"); |
760 return NULL; | 758 return NULL; |
761 } | 759 } |
762 | 760 |
763 SkASSERT(fNumberPasses != INVALID_NUMBER_PASSES); | 761 SkASSERT(codec->fNumberPasses != INVALID_NUMBER_PASSES); |
764 if (fNumberPasses > 1) { | 762 if (codec->fNumberPasses > 1) { |
765 // interlaced image | 763 // interlaced image |
766 return SkNEW_ARGS(SkPngInterlacedScanlineDecoder, (dstInfo, this)); | 764 return SkNEW_ARGS(SkPngInterlacedScanlineDecoder, (dstInfo, codec.detach
())); |
767 } | 765 } |
768 | 766 |
769 return SkNEW_ARGS(SkPngScanlineDecoder, (dstInfo, this)); | 767 return SkNEW_ARGS(SkPngScanlineDecoder, (dstInfo, codec.detach())); |
770 } | 768 } |
771 | 769 |
OLD | NEW |