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 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
58 SkStream* stream = static_cast<SkStream*>(png_get_io_ptr(png_ptr)); | 58 SkStream* stream = static_cast<SkStream*>(png_get_io_ptr(png_ptr)); |
59 const size_t bytes = stream->read(data, length); | 59 const size_t bytes = stream->read(data, length); |
60 if (bytes != length) { | 60 if (bytes != length) { |
61 // FIXME: We want to report the fact that the stream was truncated. | 61 // FIXME: We want to report the fact that the stream was truncated. |
62 // One way to do that might be to pass a enum to longjmp so setjmp can | 62 // One way to do that might be to pass a enum to longjmp so setjmp can |
63 // specify the failure. | 63 // specify the failure. |
64 png_error(png_ptr, "Read Error!"); | 64 png_error(png_ptr, "Read Error!"); |
65 } | 65 } |
66 } | 66 } |
67 | 67 |
68 #ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED | |
69 static int sk_read_user_chunk(png_structp png_ptr, png_unknown_chunkp chunk) { | |
70 SkPngChunkReader* chunkReader = (SkPngChunkReader*)png_get_user_chunk_ptr(pn
g_ptr); | |
71 // readChunk() returning true means continue decoding | |
72 return chunkReader->readChunk((const char*)chunk->name, chunk->data, chunk->
size) ? 1 : -1; | |
73 } | |
74 #endif | |
75 | |
76 /////////////////////////////////////////////////////////////////////////////// | 68 /////////////////////////////////////////////////////////////////////////////// |
77 // Helpers | 69 // Helpers |
78 /////////////////////////////////////////////////////////////////////////////// | 70 /////////////////////////////////////////////////////////////////////////////// |
79 | 71 |
80 class AutoCleanPng : public SkNoncopyable { | 72 class AutoCleanPng : public SkNoncopyable { |
81 public: | 73 public: |
82 AutoCleanPng(png_structp png_ptr) | 74 AutoCleanPng(png_structp png_ptr) |
83 : fPng_ptr(png_ptr) | 75 : fPng_ptr(png_ptr) |
84 , fInfo_ptr(nullptr) {} | 76 , fInfo_ptr(nullptr) {} |
85 | 77 |
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
212 char buf[PNG_BYTES_TO_CHECK]; | 204 char buf[PNG_BYTES_TO_CHECK]; |
213 if (stream->read(buf, PNG_BYTES_TO_CHECK) != PNG_BYTES_TO_CHECK) { | 205 if (stream->read(buf, PNG_BYTES_TO_CHECK) != PNG_BYTES_TO_CHECK) { |
214 return false; | 206 return false; |
215 } | 207 } |
216 if (png_sig_cmp((png_bytep) buf, (png_size_t)0, PNG_BYTES_TO_CHECK)) { | 208 if (png_sig_cmp((png_bytep) buf, (png_size_t)0, PNG_BYTES_TO_CHECK)) { |
217 return false; | 209 return false; |
218 } | 210 } |
219 return true; | 211 return true; |
220 } | 212 } |
221 | 213 |
222 // Reads the header and initializes the output fields, if not NULL. | 214 // Reads the header, and initializes the passed in fields, if not nullptr (excep
t |
223 // | 215 // stream, which is passed to the read function). |
224 // @param stream Input data. Will be read to get enough information to properly | 216 // Returns true on success, in which case the caller is responsible for calling |
225 // setup the codec. | 217 // png_destroy_read_struct. If it returns false, the passed in fields (except |
226 // @param chunkReader SkPngChunkReader, for reading unknown chunks. May be NULL. | 218 // stream) are unchanged. |
227 // If not NULL, png_ptr will hold an *unowned* pointer to it. The caller is | 219 static bool read_header(SkStream* stream, png_structp* png_ptrp, |
228 // expected to continue to own it for the lifetime of the png_ptr. | 220 png_infop* info_ptrp, SkImageInfo* imageInfo, |
229 // @param png_ptrp Optional output variable. If non-NULL, will be set to a new | 221 int* bitDepthPtr, int* numberPassesPtr) { |
230 // png_structp on success. | |
231 // @param info_ptrp Optional output variable. If non-NULL, will be set to a new | |
232 // png_infop on success; | |
233 // @param imageInfo Optional output variable. If non-NULL, will be set to | |
234 // reflect the properties of the encoded image on success. | |
235 // @param bitDepthPtr Optional output variable. If non-NULL, will be set to the | |
236 // bit depth of the encoded image on success. | |
237 // @param numberPassesPtr Optional output variable. If non-NULL, will be set to | |
238 // the number_passes of the encoded image on success. | |
239 // @return true on success, in which case the caller is responsible for calling | |
240 // png_destroy_read_struct(png_ptrp, info_ptrp). | |
241 // If it returns false, the passed in fields (except stream) are unchanged. | |
242 static bool read_header(SkStream* stream, SkPngChunkReader* chunkReader, | |
243 png_structp* png_ptrp, png_infop* info_ptrp, | |
244 SkImageInfo* imageInfo, int* bitDepthPtr, int* numberPas
sesPtr) { | |
245 // The image is known to be a PNG. Decode enough to know the SkImageInfo. | 222 // The image is known to be a PNG. Decode enough to know the SkImageInfo. |
246 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, | 223 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, |
247 sk_error_fn, sk_warning_fn); | 224 sk_error_fn, sk_warning_fn); |
248 if (!png_ptr) { | 225 if (!png_ptr) { |
249 return false; | 226 return false; |
250 } | 227 } |
251 | 228 |
252 AutoCleanPng autoClean(png_ptr); | 229 AutoCleanPng autoClean(png_ptr); |
253 | 230 |
254 png_infop info_ptr = png_create_info_struct(png_ptr); | 231 png_infop info_ptr = png_create_info_struct(png_ptr); |
255 if (info_ptr == nullptr) { | 232 if (info_ptr == nullptr) { |
256 return false; | 233 return false; |
257 } | 234 } |
258 | 235 |
259 autoClean.setInfoPtr(info_ptr); | 236 autoClean.setInfoPtr(info_ptr); |
260 | 237 |
261 // FIXME: Could we use the return value of setjmp to specify the type of | 238 // FIXME: Could we use the return value of setjmp to specify the type of |
262 // error? | 239 // error? |
263 if (setjmp(png_jmpbuf(png_ptr))) { | 240 if (setjmp(png_jmpbuf(png_ptr))) { |
264 return false; | 241 return false; |
265 } | 242 } |
266 | 243 |
267 png_set_read_fn(png_ptr, static_cast<void*>(stream), sk_read_fn); | 244 png_set_read_fn(png_ptr, static_cast<void*>(stream), sk_read_fn); |
268 | 245 |
269 #ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED | 246 // FIXME: This is where the old code hooks up the Peeker. Does it need to |
270 // FIXME: Does this need to be installed so early? | 247 // be set this early? (i.e. where are the user chunks? early in the stream, |
271 // hookup our chunkReader so we can see any user-chunks the caller may be in
terested in | 248 // potentially?) |
272 if (chunkReader) { | 249 // If it does, we need to figure out a way to set it here. |
273 png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*
)"", 0); | |
274 png_set_read_user_chunk_fn(png_ptr, (png_voidp) chunkReader, sk_read_use
r_chunk); | |
275 } | |
276 #endif | |
277 | 250 |
278 // The call to png_read_info() gives us all of the information from the | 251 // The call to png_read_info() gives us all of the information from the |
279 // PNG file before the first IDAT (image data chunk). | 252 // PNG file before the first IDAT (image data chunk). |
280 png_read_info(png_ptr, info_ptr); | 253 png_read_info(png_ptr, info_ptr); |
281 png_uint_32 origWidth, origHeight; | 254 png_uint_32 origWidth, origHeight; |
282 int bitDepth, colorType; | 255 int bitDepth, colorType; |
283 png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth, | 256 png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth, |
284 &colorType, int_p_NULL, int_p_NULL, int_p_NULL); | 257 &colorType, int_p_NULL, int_p_NULL, int_p_NULL); |
285 | 258 |
286 if (bitDepthPtr) { | 259 if (bitDepthPtr) { |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
376 if (png_ptrp) { | 349 if (png_ptrp) { |
377 *png_ptrp = png_ptr; | 350 *png_ptrp = png_ptr; |
378 } | 351 } |
379 if (info_ptrp) { | 352 if (info_ptrp) { |
380 *info_ptrp = info_ptr; | 353 *info_ptrp = info_ptr; |
381 } | 354 } |
382 | 355 |
383 return true; | 356 return true; |
384 } | 357 } |
385 | 358 |
386 SkPngCodec::SkPngCodec(const SkImageInfo& info, SkStream* stream, SkPngChunkRead
er* chunkReader, | 359 SkPngCodec::SkPngCodec(const SkImageInfo& info, SkStream* stream, |
387 png_structp png_ptr, png_infop info_ptr, int bitDepth, in
t numberPasses) | 360 png_structp png_ptr, png_infop info_ptr, int bitDepth, in
t numberPasses) |
388 : INHERITED(info, stream) | 361 : INHERITED(info, stream) |
389 , fPngChunkReader(SkSafeRef(chunkReader)) | |
390 , fPng_ptr(png_ptr) | 362 , fPng_ptr(png_ptr) |
391 , fInfo_ptr(info_ptr) | 363 , fInfo_ptr(info_ptr) |
392 , fSrcConfig(SkSwizzler::kUnknown) | 364 , fSrcConfig(SkSwizzler::kUnknown) |
393 , fNumberPasses(numberPasses) | 365 , fNumberPasses(numberPasses) |
394 , fBitDepth(bitDepth) | 366 , fBitDepth(bitDepth) |
395 { | 367 { |
396 if (info.alphaType() == kOpaque_SkAlphaType) { | 368 if (info.alphaType() == kOpaque_SkAlphaType) { |
397 fAlphaState = kOpaque_AlphaState; | 369 fAlphaState = kOpaque_AlphaState; |
398 } else { | 370 } else { |
399 fAlphaState = kUnknown_AlphaState; | 371 fAlphaState = kUnknown_AlphaState; |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
474 bool SkPngCodec::onRewind() { | 446 bool SkPngCodec::onRewind() { |
475 // This sets fPng_ptr and fInfo_ptr to nullptr. If read_header | 447 // This sets fPng_ptr and fInfo_ptr to nullptr. If read_header |
476 // succeeds, they will be repopulated, and if it fails, they will | 448 // succeeds, they will be repopulated, and if it fails, they will |
477 // remain nullptr. Any future accesses to fPng_ptr and fInfo_ptr will | 449 // remain nullptr. Any future accesses to fPng_ptr and fInfo_ptr will |
478 // come through this function which will rewind and again attempt | 450 // come through this function which will rewind and again attempt |
479 // to reinitialize them. | 451 // to reinitialize them. |
480 this->destroyReadStruct(); | 452 this->destroyReadStruct(); |
481 | 453 |
482 png_structp png_ptr; | 454 png_structp png_ptr; |
483 png_infop info_ptr; | 455 png_infop info_ptr; |
484 if (!read_header(this->stream(), fPngChunkReader.get(), &png_ptr, &info_ptr, | 456 if (!read_header(this->stream(), &png_ptr, &info_ptr, nullptr, nullptr, null
ptr)) { |
485 nullptr, nullptr, nullptr)) { | |
486 return false; | 457 return false; |
487 } | 458 } |
488 | 459 |
489 fPng_ptr = png_ptr; | 460 fPng_ptr = png_ptr; |
490 fInfo_ptr = info_ptr; | 461 fInfo_ptr = info_ptr; |
491 return true; | 462 return true; |
492 } | 463 } |
493 | 464 |
494 SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void*
dst, | 465 SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void*
dst, |
495 size_t dstRowBytes, const Options& optio
ns, | 466 size_t dstRowBytes, const Options& optio
ns, |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
624 | 595 |
625 // All valid AlphaStates have been covered, so this should not be reached. | 596 // All valid AlphaStates have been covered, so this should not be reached. |
626 SkASSERT(false); | 597 SkASSERT(false); |
627 return true; | 598 return true; |
628 } | 599 } |
629 | 600 |
630 // Subclass of SkPngCodec which supports scanline decoding | 601 // Subclass of SkPngCodec which supports scanline decoding |
631 class SkPngScanlineDecoder : public SkPngCodec { | 602 class SkPngScanlineDecoder : public SkPngCodec { |
632 public: | 603 public: |
633 SkPngScanlineDecoder(const SkImageInfo& srcInfo, SkStream* stream, | 604 SkPngScanlineDecoder(const SkImageInfo& srcInfo, SkStream* stream, |
634 SkPngChunkReader* chunkReader, png_structp png_ptr, png_infop info_p
tr, int bitDepth) | 605 png_structp png_ptr, png_infop info_ptr, int bitDepth) |
635 : INHERITED(srcInfo, stream, chunkReader, png_ptr, info_ptr, bitDepth, 1
) | 606 : INHERITED(srcInfo, stream, png_ptr, info_ptr, bitDepth, 1) |
636 , fAlphaState(kUnknown_AlphaState) | 607 , fAlphaState(kUnknown_AlphaState) |
637 , fSrcRow(nullptr) | 608 , fSrcRow(nullptr) |
638 {} | 609 {} |
639 | 610 |
640 Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& opti
ons, | 611 Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& opti
ons, |
641 SkPMColor ctable[], int* ctableCount) override { | 612 SkPMColor ctable[], int* ctableCount) override { |
642 if (!conversion_possible(dstInfo, this->getInfo())) { | 613 if (!conversion_possible(dstInfo, this->getInfo())) { |
643 return kInvalidConversion; | 614 return kInvalidConversion; |
644 } | 615 } |
645 | 616 |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
708 SkAutoMalloc fStorage; | 679 SkAutoMalloc fStorage; |
709 uint8_t* fSrcRow; | 680 uint8_t* fSrcRow; |
710 | 681 |
711 typedef SkPngCodec INHERITED; | 682 typedef SkPngCodec INHERITED; |
712 }; | 683 }; |
713 | 684 |
714 | 685 |
715 class SkPngInterlacedScanlineDecoder : public SkPngCodec { | 686 class SkPngInterlacedScanlineDecoder : public SkPngCodec { |
716 public: | 687 public: |
717 SkPngInterlacedScanlineDecoder(const SkImageInfo& srcInfo, SkStream* stream, | 688 SkPngInterlacedScanlineDecoder(const SkImageInfo& srcInfo, SkStream* stream, |
718 SkPngChunkReader* chunkReader, png_structp png_ptr, png_infop info_p
tr, | 689 png_structp png_ptr, png_infop info_ptr, int bitDepth, int numberPas
ses) |
719 int bitDepth, int numberPasses) | 690 : INHERITED(srcInfo, stream, png_ptr, info_ptr, bitDepth, numberPasses) |
720 : INHERITED(srcInfo, stream, chunkReader, png_ptr, info_ptr, bitDepth, n
umberPasses) | |
721 , fAlphaState(kUnknown_AlphaState) | 691 , fAlphaState(kUnknown_AlphaState) |
722 , fHeight(-1) | 692 , fHeight(-1) |
723 , fCanSkipRewind(false) | 693 , fCanSkipRewind(false) |
724 { | 694 { |
725 SkASSERT(numberPasses != 1); | 695 SkASSERT(numberPasses != 1); |
726 } | 696 } |
727 | 697 |
728 Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& opti
ons, | 698 Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& opti
ons, |
729 SkPMColor ctable[], int* ctableCount) override { | 699 SkPMColor ctable[], int* ctableCount) override { |
730 if (!conversion_possible(dstInfo, this->getInfo())) { | 700 if (!conversion_possible(dstInfo, this->getInfo())) { |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
845 // to note that the *next* time it is called a rewind is needed. | 815 // to note that the *next* time it is called a rewind is needed. |
846 // SkPngInterlacedScanlineDecoder has an extra wrinkle - calling | 816 // SkPngInterlacedScanlineDecoder has an extra wrinkle - calling |
847 // onStartScanlineDecode followed by onGetScanlines does *not* require a | 817 // onStartScanlineDecode followed by onGetScanlines does *not* require a |
848 // rewind. Since rewindIfNeeded does not have this flexibility, we need to | 818 // rewind. Since rewindIfNeeded does not have this flexibility, we need to |
849 // add another layer. | 819 // add another layer. |
850 bool fCanSkipRewind; | 820 bool fCanSkipRewind; |
851 | 821 |
852 typedef SkPngCodec INHERITED; | 822 typedef SkPngCodec INHERITED; |
853 }; | 823 }; |
854 | 824 |
855 SkCodec* SkPngCodec::NewFromStream(SkStream* stream, SkPngChunkReader* chunkRead
er) { | 825 SkCodec* SkPngCodec::NewFromStream(SkStream* stream) { |
856 SkAutoTDelete<SkStream> streamDeleter(stream); | 826 SkAutoTDelete<SkStream> streamDeleter(stream); |
857 png_structp png_ptr; | 827 png_structp png_ptr; |
858 png_infop info_ptr; | 828 png_infop info_ptr; |
859 SkImageInfo imageInfo; | 829 SkImageInfo imageInfo; |
860 int bitDepth; | 830 int bitDepth; |
861 int numberPasses; | 831 int numberPasses; |
862 | 832 |
863 if (!read_header(stream, chunkReader, &png_ptr, &info_ptr, &imageInfo, &bitD
epth, | 833 if (!read_header(stream, &png_ptr, &info_ptr, &imageInfo, &bitDepth, &number
Passes)) { |
864 &numberPasses)) { | |
865 return nullptr; | 834 return nullptr; |
866 } | 835 } |
867 | 836 |
868 if (1 == numberPasses) { | 837 if (1 == numberPasses) { |
869 return new SkPngScanlineDecoder(imageInfo, streamDeleter.detach(), chunk
Reader, | 838 return new SkPngScanlineDecoder(imageInfo, streamDeleter.detach(), png_p
tr, info_ptr, |
870 png_ptr, info_ptr, bitDepth); | 839 bitDepth); |
871 } | 840 } |
872 | 841 |
873 return new SkPngInterlacedScanlineDecoder(imageInfo, streamDeleter.detach(),
chunkReader, | 842 return new SkPngInterlacedScanlineDecoder(imageInfo, streamDeleter.detach(),
png_ptr, |
874 png_ptr, info_ptr, bitDepth, numbe
rPasses); | 843 info_ptr, bitDepth, numberPasses); |
875 } | 844 } |
OLD | NEW |