| 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 |