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