OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2006 The Android Open Source Project | 2 * Copyright 2006 The Android Open Source Project |
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 "SkImageDecoder.h" | 8 #include "SkImageDecoder.h" |
9 #include "SkImageEncoder.h" | 9 #include "SkImageEncoder.h" |
10 #include "SkColor.h" | 10 #include "SkColor.h" |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
75 SkPNGImageDecoder() { | 75 SkPNGImageDecoder() { |
76 fImageIndex = nullptr; | 76 fImageIndex = nullptr; |
77 } | 77 } |
78 Format getFormat() const override { | 78 Format getFormat() const override { |
79 return kPNG_Format; | 79 return kPNG_Format; |
80 } | 80 } |
81 | 81 |
82 virtual ~SkPNGImageDecoder() { delete fImageIndex; } | 82 virtual ~SkPNGImageDecoder() { delete fImageIndex; } |
83 | 83 |
84 protected: | 84 protected: |
85 #ifdef SK_PNG_INDEX_SUPPORTED | |
86 bool onBuildTileIndex(SkStreamRewindable *stream, int *width, int *height) o
verride; | |
87 bool onDecodeSubset(SkBitmap* bitmap, const SkIRect& region) override; | |
88 #endif | |
89 Result onDecode(SkStream* stream, SkBitmap* bm, Mode) override; | 85 Result onDecode(SkStream* stream, SkBitmap* bm, Mode) override; |
90 | 86 |
91 private: | 87 private: |
92 SkPNGImageIndex* fImageIndex; | 88 SkPNGImageIndex* fImageIndex; |
93 | 89 |
94 bool onDecodeInit(SkStream* stream, png_structp *png_ptrp, png_infop *info_p
trp); | 90 bool onDecodeInit(SkStream* stream, png_structp *png_ptrp, png_infop *info_p
trp); |
95 bool decodePalette(png_structp png_ptr, png_infop info_ptr, int bitDepth, | 91 bool decodePalette(png_structp png_ptr, png_infop info_ptr, int bitDepth, |
96 bool * SK_RESTRICT hasAlphap, bool *reallyHasAlphap, | 92 bool * SK_RESTRICT hasAlphap, bool *reallyHasAlphap, |
97 SkColorTable **colorTablep); | 93 SkColorTable **colorTablep); |
98 bool getBitmapColorType(png_structp, png_infop, SkColorType*, bool* hasAlpha
, | 94 bool getBitmapColorType(png_structp, png_infop, SkColorType*, bool* hasAlpha
, |
(...skipping 20 matching lines...) Expand all Loading... |
119 }; | 115 }; |
120 | 116 |
121 static void sk_read_fn(png_structp png_ptr, png_bytep data, png_size_t length) { | 117 static void sk_read_fn(png_structp png_ptr, png_bytep data, png_size_t length) { |
122 SkStream* sk_stream = (SkStream*) png_get_io_ptr(png_ptr); | 118 SkStream* sk_stream = (SkStream*) png_get_io_ptr(png_ptr); |
123 size_t bytes = sk_stream->read(data, length); | 119 size_t bytes = sk_stream->read(data, length); |
124 if (bytes != length) { | 120 if (bytes != length) { |
125 png_error(png_ptr, "Read Error!"); | 121 png_error(png_ptr, "Read Error!"); |
126 } | 122 } |
127 } | 123 } |
128 | 124 |
129 #ifdef SK_PNG_INDEX_SUPPORTED | |
130 static void sk_seek_fn(png_structp png_ptr, png_uint_32 offset) { | |
131 SkStreamRewindable* sk_stream = (SkStreamRewindable*) png_get_io_ptr(png_ptr
); | |
132 if (!sk_stream->rewind()) { | |
133 png_error(png_ptr, "Failed to rewind stream!"); | |
134 } | |
135 (void)sk_stream->skip(offset); | |
136 } | |
137 #endif | |
138 | |
139 #ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED | 125 #ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED |
140 static int sk_read_user_chunk(png_structp png_ptr, png_unknown_chunkp chunk) { | 126 static int sk_read_user_chunk(png_structp png_ptr, png_unknown_chunkp chunk) { |
141 SkImageDecoder::Peeker* peeker = | 127 SkImageDecoder::Peeker* peeker = |
142 (SkImageDecoder::Peeker*)png_get_user_chunk_ptr(png_ptr); | 128 (SkImageDecoder::Peeker*)png_get_user_chunk_ptr(png_ptr); |
143 // peek() returning true means continue decoding | 129 // peek() returning true means continue decoding |
144 return peeker->peek((const char*)chunk->name, chunk->data, chunk->size) ? | 130 return peeker->peek((const char*)chunk->name, chunk->data, chunk->size) ? |
145 1 : -1; | 131 1 : -1; |
146 } | 132 } |
147 #endif | 133 #endif |
148 | 134 |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
249 */ | 235 */ |
250 if (setjmp(png_jmpbuf(png_ptr))) { | 236 if (setjmp(png_jmpbuf(png_ptr))) { |
251 png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); | 237 png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); |
252 return false; | 238 return false; |
253 } | 239 } |
254 | 240 |
255 /* If you are using replacement read functions, instead of calling | 241 /* If you are using replacement read functions, instead of calling |
256 * png_init_io() here you would call: | 242 * png_init_io() here you would call: |
257 */ | 243 */ |
258 png_set_read_fn(png_ptr, (void *)sk_stream, sk_read_fn); | 244 png_set_read_fn(png_ptr, (void *)sk_stream, sk_read_fn); |
259 #ifdef SK_PNG_INDEX_SUPPORTED | |
260 png_set_seek_fn(png_ptr, sk_seek_fn); | |
261 #endif | |
262 /* where user_io_ptr is a structure you want available to the callbacks */ | 245 /* where user_io_ptr is a structure you want available to the callbacks */ |
263 /* If we have already read some of the signature */ | 246 /* If we have already read some of the signature */ |
264 // png_set_sig_bytes(png_ptr, 0 /* sig_read */ ); | 247 // png_set_sig_bytes(png_ptr, 0 /* sig_read */ ); |
265 | 248 |
266 #ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED | 249 #ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED |
267 // hookup our peeker so we can see any user-chunks the caller may be interes
ted in | 250 // hookup our peeker so we can see any user-chunks the caller may be interes
ted in |
268 png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*)"",
0); | 251 png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*)"",
0); |
269 if (this->getPeeker()) { | 252 if (this->getPeeker()) { |
270 png_set_read_user_chunk_fn(png_ptr, (png_voidp)this->getPeeker(), sk_rea
d_user_chunk); | 253 png_set_read_user_chunk_fn(png_ptr, (png_voidp)this->getPeeker(), sk_rea
d_user_chunk); |
271 } | 254 } |
(...skipping 441 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
713 SkPMColor lastColor = index > 0 ? colorPtr[-1] : SkPackARGB32(0xFF, 0, 0, 0)
; | 696 SkPMColor lastColor = index > 0 ? colorPtr[-1] : SkPackARGB32(0xFF, 0, 0, 0)
; |
714 for (; index < colorCount; index++) { | 697 for (; index < colorCount; index++) { |
715 *colorPtr++ = lastColor; | 698 *colorPtr++ = lastColor; |
716 } | 699 } |
717 | 700 |
718 *colorTablep = new SkColorTable(colorStorage, colorCount); | 701 *colorTablep = new SkColorTable(colorStorage, colorCount); |
719 *reallyHasAlphap = reallyHasAlpha; | 702 *reallyHasAlphap = reallyHasAlpha; |
720 return true; | 703 return true; |
721 } | 704 } |
722 | 705 |
723 #ifdef SK_PNG_INDEX_SUPPORTED | |
724 | |
725 bool SkPNGImageDecoder::onBuildTileIndex(SkStreamRewindable* sk_stream, int *wid
th, int *height) { | |
726 SkAutoTDelete<SkStreamRewindable> streamDeleter(sk_stream); | |
727 png_structp png_ptr; | |
728 png_infop info_ptr; | |
729 | |
730 if (!onDecodeInit(sk_stream, &png_ptr, &info_ptr)) { | |
731 return false; | |
732 } | |
733 | |
734 if (setjmp(png_jmpbuf(png_ptr)) != 0) { | |
735 png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); | |
736 return false; | |
737 } | |
738 | |
739 png_uint_32 origWidth, origHeight; | |
740 int bitDepth, colorType; | |
741 png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth, | |
742 &colorType, int_p_NULL, int_p_NULL, int_p_NULL); | |
743 | |
744 *width = origWidth; | |
745 *height = origHeight; | |
746 | |
747 png_build_index(png_ptr); | |
748 | |
749 if (fImageIndex) { | |
750 delete fImageIndex; | |
751 } | |
752 fImageIndex = new SkPNGImageIndex(streamDeleter.detach(), png_ptr, info_ptr)
; | |
753 | |
754 return true; | |
755 } | |
756 | |
757 bool SkPNGImageDecoder::onDecodeSubset(SkBitmap* bm, const SkIRect& region) { | |
758 if (nullptr == fImageIndex) { | |
759 return false; | |
760 } | |
761 | |
762 png_structp png_ptr = fImageIndex->fPng_ptr; | |
763 png_infop info_ptr = fImageIndex->fInfo_ptr; | |
764 if (setjmp(png_jmpbuf(png_ptr))) { | |
765 return false; | |
766 } | |
767 | |
768 png_uint_32 origWidth, origHeight; | |
769 int bitDepth, pngColorType, interlaceType; | |
770 png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth, | |
771 &pngColorType, &interlaceType, int_p_NULL, int_p_NULL); | |
772 | |
773 SkIRect rect = SkIRect::MakeWH(origWidth, origHeight); | |
774 | |
775 if (!rect.intersect(region)) { | |
776 // If the requested region is entirely outside the image, just | |
777 // returns false | |
778 return false; | |
779 } | |
780 | |
781 SkColorType colorType; | |
782 bool hasAlpha = false; | |
783 SkPMColor theTranspColor = 0; // 0 tells us not to try to match | |
784 | |
785 if (!this->getBitmapColorType(png_ptr, info_ptr, &colorType, &hasAlpha, &the
TranspColor)) { | |
786 return false; | |
787 } | |
788 | |
789 const int sampleSize = this->getSampleSize(); | |
790 SkScaledBitmapSampler sampler(origWidth, rect.height(), sampleSize); | |
791 | |
792 SkBitmap decodedBitmap; | |
793 decodedBitmap.setInfo(SkImageInfo::Make(sampler.scaledWidth(), sampler.scale
dHeight(), | |
794 colorType, kPremul_SkAlphaType)); | |
795 | |
796 // from here down we are concerned with colortables and pixels | |
797 | |
798 // we track if we actually see a non-opaque pixels, since sometimes a PNG se
ts its colortype | |
799 // to |= PNG_COLOR_MASK_ALPHA, but all of its pixels are in fact opaque. We
care, since we | |
800 // draw lots faster if we can flag the bitmap has being opaque | |
801 bool reallyHasAlpha = false; | |
802 SkColorTable* colorTable = nullptr; | |
803 | |
804 if (pngColorType == PNG_COLOR_TYPE_PALETTE) { | |
805 decodePalette(png_ptr, info_ptr, bitDepth, &hasAlpha, &reallyHasAlpha, &
colorTable); | |
806 } | |
807 | |
808 SkAutoUnref aur(colorTable); | |
809 | |
810 // Check ahead of time if the swap(dest, src) is possible. | |
811 // If yes, then we will stick to AllocPixelRef since it's cheaper with the s
wap happening. | |
812 // If no, then we will use alloc to allocate pixels to prevent garbage colle
ction. | |
813 int w = rect.width() / sampleSize; | |
814 int h = rect.height() / sampleSize; | |
815 const bool swapOnly = (rect == region) && (w == decodedBitmap.width()) && | |
816 (h == decodedBitmap.height()) && bm->isNull(); | |
817 const bool needColorTable = kIndex_8_SkColorType == colorType; | |
818 if (swapOnly) { | |
819 if (!this->allocPixelRef(&decodedBitmap, needColorTable ? colorTable : n
ullptr)) { | |
820 return false; | |
821 } | |
822 } else { | |
823 if (!decodedBitmap.tryAllocPixels(nullptr, needColorTable ? colorTable :
nullptr)) { | |
824 return false; | |
825 } | |
826 } | |
827 SkAutoLockPixels alp(decodedBitmap); | |
828 | |
829 /* Turn on interlace handling. REQUIRED if you are not using | |
830 * png_read_image(). To see how to handle interlacing passes, | |
831 * see the png_read_row() method below: | |
832 */ | |
833 const int number_passes = (interlaceType != PNG_INTERLACE_NONE) ? | |
834 png_set_interlace_handling(png_ptr) : 1; | |
835 | |
836 /* Optional call to gamma correct and add the background to the palette | |
837 * and update info structure. REQUIRED if you are expecting libpng to | |
838 * update the palette for you (ie you selected such a transform above). | |
839 */ | |
840 | |
841 // Direct access to png_ptr fields is deprecated in libpng > 1.2. | |
842 #if defined(PNG_1_0_X) || defined (PNG_1_2_X) | |
843 png_ptr->pass = 0; | |
844 #else | |
845 // FIXME: This sets pass as desired, but also sets iwidth. Is that ok? | |
846 png_set_interlaced_pass(png_ptr, 0); | |
847 #endif | |
848 png_read_update_info(png_ptr, info_ptr); | |
849 | |
850 int actualTop = rect.fTop; | |
851 | |
852 if ((kAlpha_8_SkColorType == colorType || kIndex_8_SkColorType == colorType) | |
853 && 1 == sampleSize) { | |
854 if (kAlpha_8_SkColorType == colorType) { | |
855 // For an A8 bitmap, we assume there is an alpha for speed. It is | |
856 // possible the bitmap is opaque, but that is an unlikely use case | |
857 // since it would not be very interesting. | |
858 reallyHasAlpha = true; | |
859 // A8 is only allowed if the original was GRAY. | |
860 SkASSERT(PNG_COLOR_TYPE_GRAY == pngColorType); | |
861 } | |
862 | |
863 for (int i = 0; i < number_passes; i++) { | |
864 png_configure_decoder(png_ptr, &actualTop, i); | |
865 for (int j = 0; j < rect.fTop - actualTop; j++) { | |
866 uint8_t* bmRow = decodedBitmap.getAddr8(0, 0); | |
867 png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1); | |
868 } | |
869 png_uint_32 bitmapHeight = (png_uint_32) decodedBitmap.height(); | |
870 for (png_uint_32 y = 0; y < bitmapHeight; y++) { | |
871 uint8_t* bmRow = decodedBitmap.getAddr8(0, y); | |
872 png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1); | |
873 } | |
874 } | |
875 } else { | |
876 SkScaledBitmapSampler::SrcConfig sc; | |
877 int srcBytesPerPixel = 4; | |
878 | |
879 if (colorTable != nullptr) { | |
880 sc = SkScaledBitmapSampler::kIndex; | |
881 srcBytesPerPixel = 1; | |
882 } else if (kAlpha_8_SkColorType == colorType) { | |
883 // A8 is only allowed if the original was GRAY. | |
884 SkASSERT(PNG_COLOR_TYPE_GRAY == pngColorType); | |
885 sc = SkScaledBitmapSampler::kGray; | |
886 srcBytesPerPixel = 1; | |
887 } else if (hasAlpha) { | |
888 sc = SkScaledBitmapSampler::kRGBA; | |
889 } else { | |
890 sc = SkScaledBitmapSampler::kRGBX; | |
891 } | |
892 | |
893 /* We have to pass the colortable explicitly, since we may have one | |
894 even if our decodedBitmap doesn't, due to the request that we | |
895 upscale png's palette to a direct model | |
896 */ | |
897 const SkPMColor* colors = colorTable ? colorTable->readColors() : nullpt
r; | |
898 if (!sampler.begin(&decodedBitmap, sc, *this, colors)) { | |
899 return false; | |
900 } | |
901 const int height = decodedBitmap.height(); | |
902 | |
903 if (number_passes > 1) { | |
904 SkAutoMalloc storage(origWidth * origHeight * srcBytesPerPixel); | |
905 uint8_t* base = (uint8_t*)storage.get(); | |
906 size_t rb = origWidth * srcBytesPerPixel; | |
907 | |
908 for (int i = 0; i < number_passes; i++) { | |
909 png_configure_decoder(png_ptr, &actualTop, i); | |
910 for (int j = 0; j < rect.fTop - actualTop; j++) { | |
911 png_read_rows(png_ptr, &base, png_bytepp_NULL, 1); | |
912 } | |
913 uint8_t* row = base; | |
914 for (int32_t y = 0; y < rect.height(); y++) { | |
915 uint8_t* bmRow = row; | |
916 png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1); | |
917 row += rb; | |
918 } | |
919 } | |
920 // now sample it | |
921 base += sampler.srcY0() * rb; | |
922 for (int y = 0; y < height; y++) { | |
923 reallyHasAlpha |= sampler.next(base); | |
924 base += sampler.srcDY() * rb; | |
925 } | |
926 } else { | |
927 SkAutoMalloc storage(origWidth * srcBytesPerPixel); | |
928 uint8_t* srcRow = (uint8_t*)storage.get(); | |
929 | |
930 png_configure_decoder(png_ptr, &actualTop, 0); | |
931 skip_src_rows(png_ptr, srcRow, sampler.srcY0()); | |
932 | |
933 for (int i = 0; i < rect.fTop - actualTop; i++) { | |
934 png_read_rows(png_ptr, &srcRow, png_bytepp_NULL, 1); | |
935 } | |
936 for (int y = 0; y < height; y++) { | |
937 uint8_t* tmp = srcRow; | |
938 png_read_rows(png_ptr, &tmp, png_bytepp_NULL, 1); | |
939 reallyHasAlpha |= sampler.next(srcRow); | |
940 if (y < height - 1) { | |
941 skip_src_rows(png_ptr, srcRow, sampler.srcDY() - 1); | |
942 } | |
943 } | |
944 } | |
945 } | |
946 | |
947 if (0 != theTranspColor) { | |
948 reallyHasAlpha |= substituteTranspColor(&decodedBitmap, theTranspColor); | |
949 } | |
950 if (reallyHasAlpha && this->getRequireUnpremultipliedColors()) { | |
951 switch (decodedBitmap.colorType()) { | |
952 case kIndex_8_SkColorType: | |
953 // Fall through. | |
954 case kARGB_4444_SkColorType: | |
955 // We have chosen not to support unpremul for these colortypess. | |
956 return false; | |
957 default: { | |
958 // Fall through to finish the decode. This config either | |
959 // supports unpremul or it is irrelevant because it has no | |
960 // alpha (or only alpha). | |
961 // These brackets prevent a warning. | |
962 } | |
963 } | |
964 } | |
965 SkAlphaType alphaType = kOpaque_SkAlphaType; | |
966 if (reallyHasAlpha) { | |
967 if (this->getRequireUnpremultipliedColors()) { | |
968 alphaType = kUnpremul_SkAlphaType; | |
969 } else { | |
970 alphaType = kPremul_SkAlphaType; | |
971 } | |
972 } | |
973 decodedBitmap.setAlphaType(alphaType); | |
974 | |
975 if (swapOnly) { | |
976 bm->swap(decodedBitmap); | |
977 return true; | |
978 } | |
979 return this->cropBitmap(bm, &decodedBitmap, sampleSize, region.x(), region.y
(), | |
980 region.width(), region.height(), 0, rect.y()); | |
981 } | |
982 #endif | |
983 | |
984 /////////////////////////////////////////////////////////////////////////////// | 706 /////////////////////////////////////////////////////////////////////////////// |
985 | 707 |
986 #include "SkColorPriv.h" | 708 #include "SkColorPriv.h" |
987 #include "SkUnPreMultiply.h" | 709 #include "SkUnPreMultiply.h" |
988 | 710 |
989 static void sk_write_fn(png_structp png_ptr, png_bytep data, png_size_t len) { | 711 static void sk_write_fn(png_structp png_ptr, png_bytep data, png_size_t len) { |
990 SkWStream* sk_stream = (SkWStream*)png_get_io_ptr(png_ptr); | 712 SkWStream* sk_stream = (SkWStream*)png_get_io_ptr(png_ptr); |
991 if (!sk_stream->write(data, len)) { | 713 if (!sk_stream->write(data, len)) { |
992 png_error(png_ptr, "sk_write_fn Error!"); | 714 png_error(png_ptr, "sk_write_fn Error!"); |
993 } | 715 } |
(...skipping 281 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1275 return SkImageDecoder::kUnknown_Format; | 997 return SkImageDecoder::kUnknown_Format; |
1276 } | 998 } |
1277 | 999 |
1278 SkImageEncoder* sk_libpng_efactory(SkImageEncoder::Type t) { | 1000 SkImageEncoder* sk_libpng_efactory(SkImageEncoder::Type t) { |
1279 return (SkImageEncoder::kPNG_Type == t) ? new SkPNGImageEncoder : nullptr; | 1001 return (SkImageEncoder::kPNG_Type == t) ? new SkPNGImageEncoder : nullptr; |
1280 } | 1002 } |
1281 | 1003 |
1282 static SkImageDecoder_DecodeReg gDReg(sk_libpng_dfactory); | 1004 static SkImageDecoder_DecodeReg gDReg(sk_libpng_dfactory); |
1283 static SkImageDecoder_FormatReg gFormatReg(get_format_png); | 1005 static SkImageDecoder_FormatReg gFormatReg(get_format_png); |
1284 static SkImageEncoder_EncodeReg gEReg(sk_libpng_efactory); | 1006 static SkImageEncoder_EncodeReg gEReg(sk_libpng_efactory); |
OLD | NEW |