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 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
194 char buf[PNG_BYTES_TO_CHECK]; | 194 char buf[PNG_BYTES_TO_CHECK]; |
195 if (stream->read(buf, PNG_BYTES_TO_CHECK) != PNG_BYTES_TO_CHECK) { | 195 if (stream->read(buf, PNG_BYTES_TO_CHECK) != PNG_BYTES_TO_CHECK) { |
196 return false; | 196 return false; |
197 } | 197 } |
198 if (png_sig_cmp((png_bytep) buf, (png_size_t)0, PNG_BYTES_TO_CHECK)) { | 198 if (png_sig_cmp((png_bytep) buf, (png_size_t)0, PNG_BYTES_TO_CHECK)) { |
199 return false; | 199 return false; |
200 } | 200 } |
201 return true; | 201 return true; |
202 } | 202 } |
203 | 203 |
204 SkCodec* SkPngCodec::NewFromStream(SkStream* stream) { | 204 // Reads the header, and initializes the passed in fields, if not NULL (except |
| 205 // stream, which is passed to the read function). |
| 206 // Returns true on success, in which case the caller is responsible for calling |
| 207 // png_destroy_read_struct. If it returns false, the passed in fields (except |
| 208 // stream) are unchanged. |
| 209 static bool read_header(SkStream* stream, png_structp* png_ptrp, |
| 210 png_infop* info_ptrp, SkImageInfo* imageInfo) { |
205 // The image is known to be a PNG. Decode enough to know the SkImageInfo. | 211 // 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, | 212 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, |
207 sk_error_fn, sk_warning_fn); | 213 sk_error_fn, sk_warning_fn); |
208 if (!png_ptr) { | 214 if (!png_ptr) { |
209 return NULL; | 215 return false; |
210 } | 216 } |
211 | 217 |
212 AutoCleanPng autoClean(png_ptr); | 218 AutoCleanPng autoClean(png_ptr); |
213 | 219 |
214 png_infop info_ptr = png_create_info_struct(png_ptr); | 220 png_infop info_ptr = png_create_info_struct(png_ptr); |
215 if (info_ptr == NULL) { | 221 if (info_ptr == NULL) { |
216 return NULL; | 222 return false; |
217 } | 223 } |
218 | 224 |
219 autoClean.setInfoPtr(info_ptr); | 225 autoClean.setInfoPtr(info_ptr); |
220 | 226 |
221 // FIXME: Could we use the return value of setjmp to specify the type of | 227 // FIXME: Could we use the return value of setjmp to specify the type of |
222 // error? | 228 // error? |
223 if (setjmp(png_jmpbuf(png_ptr))) { | 229 if (setjmp(png_jmpbuf(png_ptr))) { |
224 return NULL; | 230 return false; |
225 } | 231 } |
226 | 232 |
227 png_set_read_fn(png_ptr, static_cast<void*>(stream), sk_read_fn); | 233 png_set_read_fn(png_ptr, static_cast<void*>(stream), sk_read_fn); |
228 | 234 |
229 // FIXME: This is where the old code hooks up the Peeker. Does it need to | 235 // FIXME: This is where the old code hooks up the Peeker. Does it need to |
230 // be set this early? (i.e. where are the user chunks? early in the stream, | 236 // be set this early? (i.e. where are the user chunks? early in the stream, |
231 // potentially?) | 237 // potentially?) |
232 // If it does, we need to figure out a way to set it here. | 238 // If it does, we need to figure out a way to set it here. |
233 | 239 |
234 // The call to png_read_info() gives us all of the information from the | 240 // The call to png_read_info() gives us all of the information from the |
235 // PNG file before the first IDAT (image data chunk). | 241 // PNG file before the first IDAT (image data chunk). |
236 png_read_info(png_ptr, info_ptr); | 242 png_read_info(png_ptr, info_ptr); |
237 png_uint_32 origWidth, origHeight; | 243 png_uint_32 origWidth, origHeight; |
238 int bitDepth, colorType; | 244 int bitDepth, colorType; |
239 png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth, | 245 png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth, |
240 &colorType, int_p_NULL, int_p_NULL, int_p_NULL); | 246 &colorType, int_p_NULL, int_p_NULL, int_p_NULL); |
241 | 247 |
242 // sanity check for size | 248 // sanity check for size |
243 { | 249 { |
244 int64_t size = sk_64_mul(origWidth, origHeight); | 250 int64_t size = sk_64_mul(origWidth, origHeight); |
245 // now check that if we are 4-bytes per pixel, we also don't overflow | 251 // now check that if we are 4-bytes per pixel, we also don't overflow |
246 if (size < 0 || size > (0x7FFFFFFF >> 2)) { | 252 if (size < 0 || size > (0x7FFFFFFF >> 2)) { |
247 return NULL; | 253 return false; |
248 } | 254 } |
249 } | 255 } |
250 | 256 |
251 // Tell libpng to strip 16 bit/color files down to 8 bits/color | 257 // Tell libpng to strip 16 bit/color files down to 8 bits/color |
252 if (bitDepth == 16) { | 258 if (bitDepth == 16) { |
253 png_set_strip_16(png_ptr); | 259 png_set_strip_16(png_ptr); |
254 } | 260 } |
255 #ifdef PNG_READ_PACK_SUPPORTED | 261 #ifdef PNG_READ_PACK_SUPPORTED |
256 // Extract multiple pixels with bit depths of 1, 2, and 4 from a single | 262 // Extract multiple pixels with bit depths of 1, 2, and 4 from a single |
257 // byte into separate bytes (useful for paletted and grayscale images). | 263 // byte into separate bytes (useful for paletted and grayscale images). |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
318 | 324 |
319 // Add filler (or alpha) byte (after each RGB triplet) if necessary. | 325 // Add filler (or alpha) byte (after each RGB triplet) if necessary. |
320 // FIXME: It seems like we could just use RGB as the SrcConfig here. | 326 // FIXME: It seems like we could just use RGB as the SrcConfig here. |
321 if (colorType == PNG_COLOR_TYPE_RGB || convertGrayToRGB) { | 327 if (colorType == PNG_COLOR_TYPE_RGB || convertGrayToRGB) { |
322 png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); | 328 png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); |
323 } | 329 } |
324 } | 330 } |
325 | 331 |
326 // FIXME: Also need to check for sRGB (skbug.com/3471). | 332 // FIXME: Also need to check for sRGB (skbug.com/3471). |
327 | 333 |
328 SkImageInfo info = SkImageInfo::Make(origWidth, origHeight, skColorType, | 334 if (imageInfo) { |
329 skAlphaType); | 335 *imageInfo = SkImageInfo::Make(origWidth, origHeight, skColorType, |
330 SkCodec* codec = SkNEW_ARGS(SkPngCodec, (info, stream, png_ptr, info_ptr)); | 336 skAlphaType); |
| 337 } |
331 autoClean.detach(); | 338 autoClean.detach(); |
332 return codec; | 339 if (png_ptrp) { |
| 340 *png_ptrp = png_ptr; |
| 341 } |
| 342 if (info_ptrp) { |
| 343 *info_ptrp = info_ptr; |
| 344 } |
| 345 return true; |
| 346 } |
| 347 |
| 348 SkCodec* SkPngCodec::NewFromStream(SkStream* stream) { |
| 349 png_structp png_ptr; |
| 350 png_infop info_ptr; |
| 351 SkImageInfo imageInfo; |
| 352 if (read_header(stream, &png_ptr, &info_ptr, &imageInfo)) { |
| 353 return SkNEW_ARGS(SkPngCodec, (imageInfo, stream, png_ptr, info_ptr)); |
| 354 } |
| 355 return NULL; |
333 } | 356 } |
334 | 357 |
335 #define INVALID_NUMBER_PASSES -1 | 358 #define INVALID_NUMBER_PASSES -1 |
336 SkPngCodec::SkPngCodec(const SkImageInfo& info, SkStream* stream, | 359 SkPngCodec::SkPngCodec(const SkImageInfo& info, SkStream* stream, |
337 png_structp png_ptr, png_infop info_ptr) | 360 png_structp png_ptr, png_infop info_ptr) |
338 : INHERITED(info, stream) | 361 : INHERITED(info, stream) |
339 , fPng_ptr(png_ptr) | 362 , fPng_ptr(png_ptr) |
340 , fInfo_ptr(info_ptr) | 363 , fInfo_ptr(info_ptr) |
341 , fSrcConfig(SkSwizzler::kUnknown) | 364 , fSrcConfig(SkSwizzler::kUnknown) |
342 , fNumberPasses(INVALID_NUMBER_PASSES) | 365 , fNumberPasses(INVALID_NUMBER_PASSES) |
343 , fReallyHasAlpha(false) | 366 , fReallyHasAlpha(false) |
344 {} | 367 {} |
345 | 368 |
346 SkPngCodec::~SkPngCodec() { | 369 SkPngCodec::~SkPngCodec() { |
347 png_destroy_read_struct(&fPng_ptr, &fInfo_ptr, png_infopp_NULL); | 370 this->destroyReadStruct(); |
| 371 } |
| 372 |
| 373 void SkPngCodec::destroyReadStruct() { |
| 374 if (fPng_ptr) { |
| 375 // We will never have a NULL fInfo_ptr with a non-NULL fPng_ptr |
| 376 SkASSERT(fInfo_ptr); |
| 377 png_destroy_read_struct(&fPng_ptr, &fInfo_ptr, png_infopp_NULL); |
| 378 fPng_ptr = NULL; |
| 379 fInfo_ptr = NULL; |
| 380 } |
348 } | 381 } |
349 | 382 |
350 /////////////////////////////////////////////////////////////////////////////// | 383 /////////////////////////////////////////////////////////////////////////////// |
351 // Getting the pixels | 384 // Getting the pixels |
352 /////////////////////////////////////////////////////////////////////////////// | 385 /////////////////////////////////////////////////////////////////////////////// |
353 | 386 |
354 static bool conversion_possible(const SkImageInfo& dst, const SkImageInfo& src)
{ | 387 static bool conversion_possible(const SkImageInfo& dst, const SkImageInfo& src)
{ |
355 // TODO: Support other conversions | 388 // TODO: Support other conversions |
356 if (dst.colorType() != src.colorType()) { | 389 if (dst.colorType() != src.colorType()) { |
357 return false; | 390 return false; |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
417 return kSuccess; | 450 return kSuccess; |
418 } | 451 } |
419 | 452 |
420 SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void*
dst, | 453 SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void*
dst, |
421 size_t rowBytes, const Options& options, | 454 size_t rowBytes, const Options& options, |
422 SkPMColor ctable[], int* ctableCount) { | 455 SkPMColor ctable[], int* ctableCount) { |
423 SkCodec::RewindState rewindState = this->rewindIfNeeded(); | 456 SkCodec::RewindState rewindState = this->rewindIfNeeded(); |
424 if (rewindState == kCouldNotRewind_RewindState) { | 457 if (rewindState == kCouldNotRewind_RewindState) { |
425 return kCouldNotRewind; | 458 return kCouldNotRewind; |
426 } else if (rewindState == kRewound_RewindState) { | 459 } else if (rewindState == kRewound_RewindState) { |
427 // TODO(scroggo): handle rewinds | 460 // This sets fPng_ptr and fInfo_ptr to NULL. If read_header succeeds, |
428 return kCouldNotRewind; | 461 // they will be repopulated, and if it fails, they will remain NULL. |
| 462 // Any future accesses to fPng_ptr and fInfo_ptr will come through this |
| 463 // function which will rewind and again attempt to reinitialize them. |
| 464 this->destroyReadStruct(); |
| 465 png_structp png_ptr; |
| 466 png_infop info_ptr; |
| 467 if (read_header(this->stream(), &png_ptr, &info_ptr, NULL)) { |
| 468 fPng_ptr = png_ptr; |
| 469 fInfo_ptr = info_ptr; |
| 470 } else { |
| 471 return kCouldNotRewind; |
| 472 } |
| 473 |
429 } | 474 } |
430 if (requestedInfo.dimensions() != this->getInfo().dimensions()) { | 475 if (requestedInfo.dimensions() != this->getInfo().dimensions()) { |
431 return kInvalidScale; | 476 return kInvalidScale; |
432 } | 477 } |
433 if (!conversion_possible(requestedInfo, this->getInfo())) { | 478 if (!conversion_possible(requestedInfo, this->getInfo())) { |
434 return kInvalidConversion; | 479 return kInvalidConversion; |
435 } | 480 } |
436 | 481 |
437 const Result result = this->initializeSwizzler(requestedInfo, dst, rowBytes, | 482 const Result result = this->initializeSwizzler(requestedInfo, dst, rowBytes, |
438 options); | 483 options); |
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
576 | 621 |
577 SkASSERT(fNumberPasses != INVALID_NUMBER_PASSES); | 622 SkASSERT(fNumberPasses != INVALID_NUMBER_PASSES); |
578 if (fNumberPasses > 1) { | 623 if (fNumberPasses > 1) { |
579 // We cannot efficiently do scanline decoding. | 624 // We cannot efficiently do scanline decoding. |
580 return NULL; | 625 return NULL; |
581 } | 626 } |
582 | 627 |
583 return SkNEW_ARGS(SkPngScanlineDecoder, (dstInfo, this)); | 628 return SkNEW_ARGS(SkPngScanlineDecoder, (dstInfo, this)); |
584 } | 629 } |
585 | 630 |
OLD | NEW |