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 456 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
467 //would have exited before now if the colorType was supported by png | 467 //would have exited before now if the colorType was supported by png |
468 SkASSERT(false); | 468 SkASSERT(false); |
469 } | 469 } |
470 | 470 |
471 // Copy the color table to the client if they request kIndex8 mode | 471 // Copy the color table to the client if they request kIndex8 mode |
472 copy_color_table(requestedInfo, fColorTable, ctable, ctableCount); | 472 copy_color_table(requestedInfo, fColorTable, ctable, ctableCount); |
473 | 473 |
474 // Create the swizzler. SkPngCodec retains ownership of the color table. | 474 // Create the swizzler. SkPngCodec retains ownership of the color table. |
475 const SkPMColor* colors = fColorTable ? fColorTable->readColors() : NULL; | 475 const SkPMColor* colors = fColorTable ? fColorTable->readColors() : NULL; |
476 fSwizzler.reset(SkSwizzler::CreateSwizzler(fSrcConfig, colors, requestedInfo , | 476 fSwizzler.reset(SkSwizzler::CreateSwizzler(fSrcConfig, colors, requestedInfo , |
477 dst, rowBytes, options.fZeroInitialized)); | 477 dst, rowBytes, options.fZeroInitialized, options.fSampleX)); |
478 if (!fSwizzler) { | 478 if (!fSwizzler) { |
479 // FIXME: CreateSwizzler could fail for another reason. | 479 // FIXME: CreateSwizzler could fail for another reason. |
480 return kUnimplemented; | 480 return kUnimplemented; |
481 } | 481 } |
482 return kSuccess; | 482 return kSuccess; |
483 } | 483 } |
484 | 484 |
485 | 485 |
486 bool SkPngCodec::handleRewind() { | 486 bool SkPngCodec::handleRewind() { |
487 switch (this->rewindIfNeeded()) { | 487 switch (this->rewindIfNeeded()) { |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
590 return kSuccess; | 590 return kSuccess; |
591 } | 591 } |
592 | 592 |
593 class SkPngScanlineDecoder : public SkScanlineDecoder { | 593 class SkPngScanlineDecoder : public SkScanlineDecoder { |
594 public: | 594 public: |
595 SkPngScanlineDecoder(const SkImageInfo& dstInfo, SkPngCodec* codec) | 595 SkPngScanlineDecoder(const SkImageInfo& dstInfo, SkPngCodec* codec) |
596 : INHERITED(dstInfo) | 596 : INHERITED(dstInfo) |
597 , fCodec(codec) | 597 , fCodec(codec) |
598 , fHasAlpha(false) | 598 , fHasAlpha(false) |
599 { | 599 { |
600 fStorage.reset(dstInfo.width() * SkSwizzler::BytesPerPixel(fCodec->fSrcC onfig)); | 600 fStorage.reset(fCodec->getInfo().width() * SkSwizzler::BytesPerPixel(fCo dec->fSrcConfig)); |
601 fSrcRow = static_cast<uint8_t*>(fStorage.get()); | 601 fSrcRow = static_cast<uint8_t*>(fStorage.get()); |
602 } | 602 } |
603 | 603 |
604 SkCodec::Result onGetScanlines(void* dst, int count, size_t rowBytes) overri de { | 604 SkCodec::Result onGetScanlines(void* dst, int count, size_t rowBytes) overri de { |
605 if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) { | 605 if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) { |
606 SkCodecPrintf("setjmp long jump!\n"); | 606 SkCodecPrintf("setjmp long jump!\n"); |
607 return SkCodec::kInvalidInput; | 607 return SkCodec::kInvalidInput; |
608 } | 608 } |
609 | 609 |
610 for (int i = 0; i < count; i++) { | 610 for (int i = 0; i < count; i++) { |
(...skipping 16 matching lines...) Expand all Loading... | |
627 //calling png_read_rows in a loop is insignificantly slower than calling it once with count | 627 //calling png_read_rows in a loop is insignificantly slower than calling it once with count |
628 //as png_read_rows has it's own loop which calls png_read_row count time s. | 628 //as png_read_rows has it's own loop which calls png_read_row count time s. |
629 for (int i = 0; i < count; i++) { | 629 for (int i = 0; i < count; i++) { |
630 png_read_rows(fCodec->fPng_ptr, &fSrcRow, png_bytepp_NULL, 1); | 630 png_read_rows(fCodec->fPng_ptr, &fSrcRow, png_bytepp_NULL, 1); |
631 } | 631 } |
632 return SkCodec::kSuccess; | 632 return SkCodec::kSuccess; |
633 } | 633 } |
634 | 634 |
635 bool onReallyHasAlpha() const override { return fHasAlpha; } | 635 bool onReallyHasAlpha() const override { return fHasAlpha; } |
636 | 636 |
637 bool onIsInterlaced() override { | |
638 return false; | |
639 } | |
640 | |
641 | |
637 private: | 642 private: |
638 SkAutoTDelete<SkPngCodec> fCodec; | 643 SkAutoTDelete<SkPngCodec> fCodec; |
639 bool fHasAlpha; | 644 bool fHasAlpha; |
640 SkAutoMalloc fStorage; | 645 SkAutoMalloc fStorage; |
641 uint8_t* fSrcRow; | 646 uint8_t* fSrcRow; |
642 | 647 |
643 typedef SkScanlineDecoder INHERITED; | 648 typedef SkScanlineDecoder INHERITED; |
644 }; | 649 }; |
645 | 650 |
646 | 651 |
647 class SkPngInterlacedScanlineDecoder : public SkScanlineDecoder { | 652 class SkPngInterlacedScanlineDecoder : public SkScanlineDecoder { |
648 public: | 653 public: |
649 SkPngInterlacedScanlineDecoder(const SkImageInfo& dstInfo, SkPngCodec* codec ) | 654 SkPngInterlacedScanlineDecoder(const SkImageInfo& dstInfo, SkPngCodec* codec ) |
650 : INHERITED(dstInfo) | 655 : INHERITED(dstInfo) |
651 , fCodec(codec) | 656 , fCodec(codec) |
652 , fHasAlpha(false) | 657 , fHasAlpha(false) |
653 , fCurrentRow(0) | 658 , fCurrentRow(0) |
654 , fHeight(dstInfo.height()) | 659 , fHeight(dstInfo.height()) |
655 { | 660 { |
656 fSrcRowBytes = dstInfo.width() * SkSwizzler::BytesPerPixel(fCodec->fSrcC onfig); | 661 fSrcRowBytes = codec->getInfo().width() * SkSwizzler::BytesPerPixel(fCod ec->fSrcConfig); |
657 fGarbageRow.reset(fSrcRowBytes); | 662 fGarbageRow.reset(fSrcRowBytes); |
658 fGarbageRowPtr = static_cast<uint8_t*>(fGarbageRow.get()); | 663 fGarbageRowPtr = static_cast<uint8_t*>(fGarbageRow.get()); |
659 } | 664 } |
660 | 665 |
661 SkCodec::Result onGetScanlines(void* dst, int count, size_t dstRowBytes) ove rride { | 666 SkCodec::Result onGetScanlines(void* dst, int count, size_t dstRowBytes) ove rride { |
662 //rewind stream if have previously called onGetScanlines, | 667 //rewind stream if have previously called onGetScanlines, |
663 //since we need entire progressive image to get scanlines | 668 //since we need entire progressive image to get scanlines |
664 if (!fCodec->handleRewind()) { | 669 if (!fCodec->handleRewind()) { |
665 return SkCodec::kCouldNotRewind; | 670 return SkCodec::kCouldNotRewind; |
666 } | 671 } |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
701 } | 706 } |
702 | 707 |
703 SkCodec::Result onSkipScanlines(int count) override { | 708 SkCodec::Result onSkipScanlines(int count) override { |
704 //when ongetScanlines is called it will skip to fCurrentRow | 709 //when ongetScanlines is called it will skip to fCurrentRow |
705 fCurrentRow += count; | 710 fCurrentRow += count; |
706 return SkCodec::kSuccess; | 711 return SkCodec::kSuccess; |
707 } | 712 } |
708 | 713 |
709 bool onReallyHasAlpha() const override { return fHasAlpha; } | 714 bool onReallyHasAlpha() const override { return fHasAlpha; } |
710 | 715 |
716 bool onIsInterlaced() override { | |
717 return true; | |
718 } | |
719 | |
711 private: | 720 private: |
712 SkAutoTDelete<SkPngCodec> fCodec; | 721 SkAutoTDelete<SkPngCodec> fCodec; |
713 bool fHasAlpha; | 722 bool fHasAlpha; |
714 int fCurrentRow; | 723 int fCurrentRow; |
715 int fHeight; | 724 int fHeight; |
716 size_t fSrcRowBytes; | 725 size_t fSrcRowBytes; |
717 SkAutoMalloc fGarbageRow; | 726 SkAutoMalloc fGarbageRow; |
718 uint8_t* fGarbageRowPtr; | 727 uint8_t* fGarbageRowPtr; |
719 | 728 |
720 typedef SkScanlineDecoder INHERITED; | 729 typedef SkScanlineDecoder INHERITED; |
721 }; | 730 }; |
722 | 731 |
723 | 732 |
724 SkScanlineDecoder* SkPngCodec::onGetScanlineDecoder(const SkImageInfo& dstInfo, | 733 SkScanlineDecoder* SkPngCodec::onGetScanlineDecoder(const SkImageInfo& dstInfo, |
725 const Options& options, SkPMColor ctable[], int* ctableCount) { | 734 const Options& options, SkPMColor ctable[], int* ctableCount) { |
726 if (!conversion_possible(dstInfo, this->getInfo())) { | 735 if (!conversion_possible(dstInfo, this->getInfo())) { |
727 SkCodecPrintf("no conversion possible\n"); | 736 SkCodecPrintf("no conversion possible\n"); |
728 return NULL; | 737 return NULL; |
729 } | 738 } |
730 // Check to see if scaling was requested. | 739 // Check to see if scaling was requested. |
731 if (dstInfo.dimensions() != this->getInfo().dimensions()) { | 740 if(options.fSampleX == 1) { |
scroggo
2015/07/28 15:58:10
It would be nice to be able to share this code wit
| |
732 return NULL; | 741 // the caller is not sampling, dimensions must be equal |
742 if (dstInfo.dimensions() != this->getInfo().dimensions()) { | |
743 return NULL; | |
744 } | |
745 | |
746 } else { | |
747 // the caller is sampling | |
748 // heights must be equal as SkCodec_libpng has no native y sampling | |
749 if (dstInfo.height() != this->getInfo().height()) { | |
750 return NULL; | |
751 } | |
752 // dstWidth must be srcWidth / sampleX | |
753 if (dstInfo.width() != this->getInfo().width() / options.fSampleX) { | |
754 return NULL; | |
755 } | |
756 | |
733 } | 757 } |
734 // Create a new SkPngCodec, to be owned by the scanline decoder. | 758 // Create a new SkPngCodec, to be owned by the scanline decoder. |
735 SkStream* stream = this->stream()->duplicate(); | 759 SkStream* stream = this->stream()->duplicate(); |
736 if (!stream) { | 760 if (!stream) { |
737 return NULL; | 761 return NULL; |
738 } | 762 } |
739 SkAutoTDelete<SkPngCodec> codec (static_cast<SkPngCodec*>(SkPngCodec::NewFro mStream(stream))); | 763 SkAutoTDelete<SkPngCodec> codec (static_cast<SkPngCodec*>(SkPngCodec::NewFro mStream(stream))); |
740 if (!codec) { | 764 if (!codec) { |
741 return NULL; | 765 return NULL; |
742 } | 766 } |
743 | 767 |
744 // Note: We set dst to NULL since we do not know it yet. rowBytes is not nee ded, | 768 // Note: We set dst to NULL since we do not know it yet. rowBytes is not nee ded, |
745 // since we'll be manually updating the dstRow, but the SkSwizzler requires it to | 769 // since we'll be manually updating the dstRow, but the SkSwizzler requires it to |
746 // be at least dstInfo.minRowBytes. | 770 // be at least dstInfo.minRowBytes. |
747 if (codec->initializeSwizzler(dstInfo, NULL, dstInfo.minRowBytes(), options, ctable, | 771 if (codec->initializeSwizzler(dstInfo, NULL, dstInfo.minRowBytes(), options, ctable, |
748 ctableCount) != kSuccess) { | 772 ctableCount) != kSuccess) { |
749 SkCodecPrintf("failed to initialize the swizzler.\n"); | 773 SkCodecPrintf("failed to initialize the swizzler.\n"); |
750 return NULL; | 774 return NULL; |
751 } | 775 } |
752 | 776 |
753 SkASSERT(codec->fNumberPasses != INVALID_NUMBER_PASSES); | 777 SkASSERT(codec->fNumberPasses != INVALID_NUMBER_PASSES); |
754 if (codec->fNumberPasses > 1) { | 778 if (codec->fNumberPasses > 1) { |
755 // interlaced image | 779 // interlaced image |
756 return SkNEW_ARGS(SkPngInterlacedScanlineDecoder, (dstInfo, codec.detach ())); | 780 return SkNEW_ARGS(SkPngInterlacedScanlineDecoder, (dstInfo, codec.detach ())); |
757 } | 781 } |
758 | 782 |
759 return SkNEW_ARGS(SkPngScanlineDecoder, (dstInfo, codec.detach())); | 783 return SkNEW_ARGS(SkPngScanlineDecoder, (dstInfo, codec.detach())); |
760 } | 784 } |
761 | 785 |
OLD | NEW |