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 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
59 SkStream* stream = static_cast<SkStream*>(png_get_io_ptr(png_ptr)); | 59 SkStream* stream = static_cast<SkStream*>(png_get_io_ptr(png_ptr)); |
60 const size_t bytes = stream->read(data, length); | 60 const size_t bytes = stream->read(data, length); |
61 if (bytes != length) { | 61 if (bytes != length) { |
62 // FIXME: We want to report the fact that the stream was truncated. | 62 // FIXME: We want to report the fact that the stream was truncated. |
63 // One way to do that might be to pass a enum to longjmp so setjmp can | 63 // One way to do that might be to pass a enum to longjmp so setjmp can |
64 // specify the failure. | 64 // specify the failure. |
65 png_error(png_ptr, "Read Error!"); | 65 png_error(png_ptr, "Read Error!"); |
66 } | 66 } |
67 } | 67 } |
68 | 68 |
| 69 #ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED |
| 70 static int sk_read_user_chunk(png_structp png_ptr, png_unknown_chunkp chunk) { |
| 71 SkChunkReader* chunkReader = (SkChunkReader*)png_get_user_chunk_ptr(png_ptr)
; |
| 72 // peek() returning true means continue decoding |
| 73 return chunkReader->readChunk((const char*)chunk->name, chunk->data, chunk->
size) ? 1 : -1; |
| 74 } |
| 75 #endif |
| 76 |
69 /////////////////////////////////////////////////////////////////////////////// | 77 /////////////////////////////////////////////////////////////////////////////// |
70 // Helpers | 78 // Helpers |
71 /////////////////////////////////////////////////////////////////////////////// | 79 /////////////////////////////////////////////////////////////////////////////// |
72 | 80 |
73 class AutoCleanPng : public SkNoncopyable { | 81 class AutoCleanPng : public SkNoncopyable { |
74 public: | 82 public: |
75 AutoCleanPng(png_structp png_ptr) | 83 AutoCleanPng(png_structp png_ptr) |
76 : fPng_ptr(png_ptr) | 84 : fPng_ptr(png_ptr) |
77 , fInfo_ptr(NULL) {} | 85 , fInfo_ptr(NULL) {} |
78 | 86 |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
194 char buf[PNG_BYTES_TO_CHECK]; | 202 char buf[PNG_BYTES_TO_CHECK]; |
195 if (stream->read(buf, PNG_BYTES_TO_CHECK) != PNG_BYTES_TO_CHECK) { | 203 if (stream->read(buf, PNG_BYTES_TO_CHECK) != PNG_BYTES_TO_CHECK) { |
196 return false; | 204 return false; |
197 } | 205 } |
198 if (png_sig_cmp((png_bytep) buf, (png_size_t)0, PNG_BYTES_TO_CHECK)) { | 206 if (png_sig_cmp((png_bytep) buf, (png_size_t)0, PNG_BYTES_TO_CHECK)) { |
199 return false; | 207 return false; |
200 } | 208 } |
201 return true; | 209 return true; |
202 } | 210 } |
203 | 211 |
204 SkCodec* SkPngCodec::NewFromStream(SkStream* stream) { | 212 SkCodec* SkPngCodec::NewFromStream(SkStream* stream, SkChunkReader* chunkReader)
{ |
205 // The image is known to be a PNG. Decode enough to know the SkImageInfo. | 213 // The image is known to be a PNG. Decode enough to know the SkImageInfo. |
206 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, | 214 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, |
207 sk_error_fn, sk_warning_fn); | 215 sk_error_fn, sk_warning_fn); |
208 if (!png_ptr) { | 216 if (!png_ptr) { |
209 return NULL; | 217 return NULL; |
210 } | 218 } |
211 | 219 |
212 AutoCleanPng autoClean(png_ptr); | 220 AutoCleanPng autoClean(png_ptr); |
213 | 221 |
214 png_infop info_ptr = png_create_info_struct(png_ptr); | 222 png_infop info_ptr = png_create_info_struct(png_ptr); |
215 if (info_ptr == NULL) { | 223 if (info_ptr == NULL) { |
216 return NULL; | 224 return NULL; |
217 } | 225 } |
218 | 226 |
219 autoClean.setInfoPtr(info_ptr); | 227 autoClean.setInfoPtr(info_ptr); |
220 | 228 |
221 // FIXME: Could we use the return value of setjmp to specify the type of | 229 // FIXME: Could we use the return value of setjmp to specify the type of |
222 // error? | 230 // error? |
223 if (setjmp(png_jmpbuf(png_ptr))) { | 231 if (setjmp(png_jmpbuf(png_ptr))) { |
224 return NULL; | 232 return NULL; |
225 } | 233 } |
226 | 234 |
227 png_set_read_fn(png_ptr, static_cast<void*>(stream), sk_read_fn); | 235 png_set_read_fn(png_ptr, static_cast<void*>(stream), sk_read_fn); |
228 | 236 |
229 // FIXME: This is where the old code hooks up the Peeker. Does it need to | 237 #ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED |
230 // be set this early? (i.e. where are the user chunks? early in the stream, | 238 // hookup our chunkReader so we can see any user-chunks the caller may be in
terested in |
231 // potentially?) | 239 if (chunkReader) { |
232 // If it does, we need to figure out a way to set it here. | 240 png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*
)"", 0); |
| 241 png_set_read_user_chunk_fn(png_ptr, (png_voidp) chunkReader, sk_read_use
r_chunk); |
| 242 } |
| 243 #endif |
233 | 244 |
234 // The call to png_read_info() gives us all of the information from the | 245 // The call to png_read_info() gives us all of the information from the |
235 // PNG file before the first IDAT (image data chunk). | 246 // PNG file before the first IDAT (image data chunk). |
236 png_read_info(png_ptr, info_ptr); | 247 png_read_info(png_ptr, info_ptr); |
237 png_uint_32 origWidth, origHeight; | 248 png_uint_32 origWidth, origHeight; |
238 int bitDepth, colorType; | 249 int bitDepth, colorType; |
239 png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth, | 250 png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth, |
240 &colorType, int_p_NULL, int_p_NULL, int_p_NULL); | 251 &colorType, int_p_NULL, int_p_NULL, int_p_NULL); |
241 | 252 |
242 // sanity check for size | 253 // sanity check for size |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
320 // FIXME: It seems like we could just use RGB as the SrcConfig here. | 331 // FIXME: It seems like we could just use RGB as the SrcConfig here. |
321 if (colorType == PNG_COLOR_TYPE_RGB || convertGrayToRGB) { | 332 if (colorType == PNG_COLOR_TYPE_RGB || convertGrayToRGB) { |
322 png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); | 333 png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); |
323 } | 334 } |
324 } | 335 } |
325 | 336 |
326 // FIXME: Also need to check for sRGB (skbug.com/3471). | 337 // FIXME: Also need to check for sRGB (skbug.com/3471). |
327 | 338 |
328 SkImageInfo info = SkImageInfo::Make(origWidth, origHeight, skColorType, | 339 SkImageInfo info = SkImageInfo::Make(origWidth, origHeight, skColorType, |
329 skAlphaType); | 340 skAlphaType); |
330 SkCodec* codec = SkNEW_ARGS(SkPngCodec, (info, stream, png_ptr, info_ptr)); | 341 SkCodec* codec = SkNEW_ARGS(SkPngCodec, (info, stream, chunkReader, png_ptr,
info_ptr)); |
331 autoClean.detach(); | 342 autoClean.detach(); |
332 return codec; | 343 return codec; |
333 } | 344 } |
334 | 345 |
335 #define INVALID_NUMBER_PASSES -1 | 346 #define INVALID_NUMBER_PASSES -1 |
336 SkPngCodec::SkPngCodec(const SkImageInfo& info, SkStream* stream, | 347 SkPngCodec::SkPngCodec(const SkImageInfo& info, SkStream* stream, SkChunkReader*
chunkReader, |
337 png_structp png_ptr, png_infop info_ptr) | 348 png_structp png_ptr, png_infop info_ptr) |
338 : INHERITED(info, stream) | 349 : INHERITED(info, stream) |
| 350 , fChunkReader(SkSafeRef(chunkReader)) |
339 , fPng_ptr(png_ptr) | 351 , fPng_ptr(png_ptr) |
340 , fInfo_ptr(info_ptr) | 352 , fInfo_ptr(info_ptr) |
341 , fSrcConfig(SkSwizzler::kUnknown) | 353 , fSrcConfig(SkSwizzler::kUnknown) |
342 , fNumberPasses(INVALID_NUMBER_PASSES) | 354 , fNumberPasses(INVALID_NUMBER_PASSES) |
343 , fReallyHasAlpha(false) | 355 , fReallyHasAlpha(false) |
344 {} | 356 {} |
345 | 357 |
346 SkPngCodec::~SkPngCodec() { | 358 SkPngCodec::~SkPngCodec() { |
347 png_destroy_read_struct(&fPng_ptr, &fInfo_ptr, png_infopp_NULL); | 359 png_destroy_read_struct(&fPng_ptr, &fInfo_ptr, png_infopp_NULL); |
348 } | 360 } |
(...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
572 | 584 |
573 SkASSERT(fNumberPasses != INVALID_NUMBER_PASSES); | 585 SkASSERT(fNumberPasses != INVALID_NUMBER_PASSES); |
574 if (fNumberPasses > 1) { | 586 if (fNumberPasses > 1) { |
575 // We cannot efficiently do scanline decoding. | 587 // We cannot efficiently do scanline decoding. |
576 return NULL; | 588 return NULL; |
577 } | 589 } |
578 | 590 |
579 return SkNEW_ARGS(SkPngScanlineDecoder, (dstInfo, this)); | 591 return SkNEW_ARGS(SkPngScanlineDecoder, (dstInfo, this)); |
580 } | 592 } |
581 | 593 |
OLD | NEW |