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