Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(144)

Side by Side Diff: src/codec/SkCodec_libpng.cpp

Issue 1040453002: Add SkPngChunkReader. (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Update SkImageDecoder_empty Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/codec/SkCodec_libpng.h ('k') | src/images/SkImageDecoder.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « src/codec/SkCodec_libpng.h ('k') | src/images/SkImageDecoder.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698