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