1 /* 2 * Copyright 2015 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "SkCodecPriv.h" 9 #include "SkColorPriv.h" 10 #include "SkColorTable.h" 11 #include "SkBitmap.h" 12 #include "SkMath.h" 13 #include "SkOpts.h" 14 #include "SkPngCodec.h" 15 #include "SkSize.h" 16 #include "SkStream.h" 17 #include "SkSwizzler.h" 18 #include "SkTemplates.h" 19 #include "SkUtils.h" 20 21 /////////////////////////////////////////////////////////////////////////////// 22 // Callback functions 23 /////////////////////////////////////////////////////////////////////////////// 24 25 static void sk_error_fn(png_structp png_ptr, png_const_charp msg) { 26 SkCodecPrintf("------ png error %s\n", msg); 27 longjmp(png_jmpbuf(png_ptr), 1); 28 } 29 30 void sk_warning_fn(png_structp, png_const_charp msg) { 31 SkCodecPrintf("----- png warning %s\n", msg); 32 } 33 34 static void sk_read_fn(png_structp png_ptr, png_bytep data, 35 png_size_t length) { 36 SkStream* stream = static_cast<SkStream*>(png_get_io_ptr(png_ptr)); 37 const size_t bytes = stream->read(data, length); 38 if (bytes != length) { 39 // FIXME: We want to report the fact that the stream was truncated. 40 // One way to do that might be to pass a enum to longjmp so setjmp can 41 // specify the failure. 42 png_error(png_ptr, "Read Error!"); 43 } 44 } 45 46 #ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED 47 static int sk_read_user_chunk(png_structp png_ptr, png_unknown_chunkp chunk) { 48 SkPngChunkReader* chunkReader = (SkPngChunkReader*)png_get_user_chunk_ptr(png_ptr); 49 // readChunk() returning true means continue decoding 50 return chunkReader->readChunk((const char*)chunk->name, chunk->data, chunk->size) ? 1 : -1; 51 } 52 #endif 53 54 /////////////////////////////////////////////////////////////////////////////// 55 // Helpers 56 /////////////////////////////////////////////////////////////////////////////// 57 58 class AutoCleanPng : public SkNoncopyable { 59 public: 60 AutoCleanPng(png_structp png_ptr) 61 : fPng_ptr(png_ptr) 62 , fInfo_ptr(nullptr) {} 63 64 ~AutoCleanPng() { 65 // fInfo_ptr will never be non-nullptr unless fPng_ptr is. 66 if (fPng_ptr) { 67 png_infopp info_pp = fInfo_ptr ? &fInfo_ptr : nullptr; 68 png_destroy_read_struct(&fPng_ptr, info_pp, nullptr); 69 } 70 } 71 72 void setInfoPtr(png_infop info_ptr) { 73 SkASSERT(nullptr == fInfo_ptr); 74 fInfo_ptr = info_ptr; 75 } 76 77 void detach() { 78 fPng_ptr = nullptr; 79 fInfo_ptr = nullptr; 80 } 81 82 private: 83 png_structp fPng_ptr; 84 png_infop fInfo_ptr; 85 }; 86 #define AutoCleanPng(...) SK_REQUIRE_LOCAL_VAR(AutoCleanPng) 87 88 // Method for coverting to either an SkPMColor or a similarly packed 89 // unpremultiplied color. 90 typedef uint32_t (*PackColorProc)(U8CPU a, U8CPU r, U8CPU g, U8CPU b); 91 92 // Note: SkColorTable claims to store SkPMColors, which is not necessarily 93 // the case here. 94 // TODO: If we add support for non-native swizzles, we'll need to handle that here. 95 bool SkPngCodec::decodePalette(bool premultiply, int* ctableCount) { 96 97 int numColors; 98 png_color* palette; 99 if (!png_get_PLTE(fPng_ptr, fInfo_ptr, &palette, &numColors)) { 100 return false; 101 } 102 103 // Note: These are not necessarily SkPMColors. 104 SkPMColor colorPtr[256]; 105 106 png_bytep alphas; 107 int numColorsWithAlpha = 0; 108 if (png_get_tRNS(fPng_ptr, fInfo_ptr, &alphas, &numColorsWithAlpha, nullptr)) { 109 // Choose which function to use to create the color table. If the final destination's 110 // colortype is unpremultiplied, the color table will store unpremultiplied colors. 111 PackColorProc proc; 112 if (premultiply) { 113 proc = &SkPremultiplyARGBInline; 114 } else { 115 proc = &SkPackARGB32NoCheck; 116 } 117 118 for (int i = 0; i < numColorsWithAlpha; i++) { 119 // We don't have a function in SkOpts that combines a set of alphas with a set 120 // of RGBs. We could write one, but it's hardly worth it, given that this 121 // is such a small fraction of the total decode time. 122 colorPtr[i] = proc(alphas[i], palette->red, palette->green, palette->blue); 123 palette++; 124 } 125 } 126 127 if (numColorsWithAlpha < numColors) { 128 // The optimized code depends on a 3-byte png_color struct with the colors 129 // in RGB order. These checks make sure it is safe to use. 130 static_assert(3 == sizeof(png_color), "png_color struct has changed. Opts are broken."); 131 #ifdef SK_DEBUG 132 SkASSERT(&palette->red < &palette->green); 133 SkASSERT(&palette->green < &palette->blue); 134 #endif 135 136 #ifdef SK_PMCOLOR_IS_RGBA 137 SkOpts::RGB_to_RGB1(colorPtr + numColorsWithAlpha, palette, numColors - numColorsWithAlpha); 138 #else 139 SkOpts::RGB_to_BGR1(colorPtr + numColorsWithAlpha, palette, numColors - numColorsWithAlpha); 140 #endif 141 } 142 143 // Pad the color table with the last color in the table (or black) in the case that 144 // invalid pixel indices exceed the number of colors in the table. 145 const int maxColors = 1 << fBitDepth; 146 if (numColors < maxColors) { 147 SkPMColor lastColor = numColors > 0 ? colorPtr[numColors - 1] : SK_ColorBLACK; 148 sk_memset32(colorPtr + numColors, lastColor, maxColors - numColors); 149 } 150 151 // Set the new color count. 152 if (ctableCount != nullptr) { 153 *ctableCount = maxColors; 154 } 155 156 fColorTable.reset(new SkColorTable(colorPtr, maxColors)); 157 return true; 158 } 159 160 /////////////////////////////////////////////////////////////////////////////// 161 // Creation 162 /////////////////////////////////////////////////////////////////////////////// 163 164 bool SkPngCodec::IsPng(const char* buf, size_t bytesRead) { 165 return !png_sig_cmp((png_bytep) buf, (png_size_t)0, bytesRead); 166 } 167 168 // Reads the header and initializes the output fields, if not NULL. 169 // 170 // @param stream Input data. Will be read to get enough information to properly 171 // setup the codec. 172 // @param chunkReader SkPngChunkReader, for reading unknown chunks. May be NULL. 173 // If not NULL, png_ptr will hold an *unowned* pointer to it. The caller is 174 // expected to continue to own it for the lifetime of the png_ptr. 175 // @param png_ptrp Optional output variable. If non-NULL, will be set to a new 176 // png_structp on success. 177 // @param info_ptrp Optional output variable. If non-NULL, will be set to a new 178 // png_infop on success; 179 // @param imageInfo Optional output variable. If non-NULL, will be set to 180 // reflect the properties of the encoded image on success. 181 // @param bitDepthPtr Optional output variable. If non-NULL, will be set to the 182 // bit depth of the encoded image on success. 183 // @param numberPassesPtr Optional output variable. If non-NULL, will be set to 184 // the number_passes of the encoded image on success. 185 // @return true on success, in which case the caller is responsible for calling 186 // png_destroy_read_struct(png_ptrp, info_ptrp). 187 // If it returns false, the passed in fields (except stream) are unchanged. 188 static bool read_header(SkStream* stream, SkPngChunkReader* chunkReader, 189 png_structp* png_ptrp, png_infop* info_ptrp, 190 SkImageInfo* imageInfo, int* bitDepthPtr, int* numberPassesPtr) { 191 // The image is known to be a PNG. Decode enough to know the SkImageInfo. 192 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, 193 sk_error_fn, sk_warning_fn); 194 if (!png_ptr) { 195 return false; 196 } 197 198 AutoCleanPng autoClean(png_ptr); 199 200 png_infop info_ptr = png_create_info_struct(png_ptr); 201 if (info_ptr == nullptr) { 202 return false; 203 } 204 205 autoClean.setInfoPtr(info_ptr); 206 207 // FIXME: Could we use the return value of setjmp to specify the type of 208 // error? 209 if (setjmp(png_jmpbuf(png_ptr))) { 210 return false; 211 } 212 213 png_set_read_fn(png_ptr, static_cast<void*>(stream), sk_read_fn); 214 215 #ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED 216 // Hookup our chunkReader so we can see any user-chunks the caller may be interested in. 217 // This needs to be installed before we read the png header. Android may store ninepatch 218 // chunks in the header. 219 if (chunkReader) { 220 png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*)"", 0); 221 png_set_read_user_chunk_fn(png_ptr, (png_voidp) chunkReader, sk_read_user_chunk); 222 } 223 #endif 224 225 // The call to png_read_info() gives us all of the information from the 226 // PNG file before the first IDAT (image data chunk). 227 png_read_info(png_ptr, info_ptr); 228 png_uint_32 origWidth, origHeight; 229 int bitDepth, encodedColorType; 230 png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth, 231 &encodedColorType, nullptr, nullptr, nullptr); 232 233 if (bitDepthPtr) { 234 *bitDepthPtr = bitDepth; 235 } 236 237 // Tell libpng to strip 16 bit/color files down to 8 bits/color. 238 // TODO: Should we handle this in SkSwizzler? Could this also benefit 239 // RAW decodes? 240 if (bitDepth == 16) { 241 SkASSERT(PNG_COLOR_TYPE_PALETTE != encodedColorType); 242 png_set_strip_16(png_ptr); 243 } 244 245 // Now determine the default colorType and alphaType and set the required transforms. 246 // Often, we depend on SkSwizzler to perform any transforms that we need. However, we 247 // still depend on libpng for many of the rare and PNG-specific cases. 248 SkColorType colorType = kUnknown_SkColorType; 249 SkAlphaType alphaType = kUnknown_SkAlphaType; 250 switch (encodedColorType) { 251 case PNG_COLOR_TYPE_PALETTE: 252 // Extract multiple pixels with bit depths of 1, 2, and 4 from a single 253 // byte into separate bytes (useful for paletted and grayscale images). 254 if (bitDepth < 8) { 255 // TODO: Should we use SkSwizzler here? 256 png_set_packing(png_ptr); 257 } 258 259 colorType = kIndex_8_SkColorType; 260 // Set the alpha type depending on if a transparency chunk exists. 261 alphaType = png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) ? 262 kUnpremul_SkAlphaType : kOpaque_SkAlphaType; 263 break; 264 case PNG_COLOR_TYPE_RGB: 265 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { 266 // Convert to RGBA if transparency chunk exists. 267 png_set_tRNS_to_alpha(png_ptr); 268 alphaType = kUnpremul_SkAlphaType; 269 } else { 270 alphaType = kOpaque_SkAlphaType; 271 } 272 colorType = kN32_SkColorType; 273 break; 274 case PNG_COLOR_TYPE_GRAY: 275 // Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel. 276 if (bitDepth < 8) { 277 // TODO: Should we use SkSwizzler here? 278 png_set_expand_gray_1_2_4_to_8(png_ptr); 279 } 280 281 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { 282 png_set_tRNS_to_alpha(png_ptr); 283 284 // We will recommend kN32 here since we do not support kGray 285 // with alpha. 286 colorType = kN32_SkColorType; 287 alphaType = kUnpremul_SkAlphaType; 288 } else { 289 colorType = kGray_8_SkColorType; 290 alphaType = kOpaque_SkAlphaType; 291 } 292 break; 293 case PNG_COLOR_TYPE_GRAY_ALPHA: 294 // We will recommend kN32 here since we do not support anything 295 // similar to GRAY_ALPHA. 296 colorType = kN32_SkColorType; 297 alphaType = kUnpremul_SkAlphaType; 298 break; 299 case PNG_COLOR_TYPE_RGBA: 300 colorType = kN32_SkColorType; 301 alphaType = kUnpremul_SkAlphaType; 302 break; 303 default: 304 // All the color types have been covered above. 305 SkASSERT(false); 306 } 307 308 int numberPasses = png_set_interlace_handling(png_ptr); 309 if (numberPassesPtr) { 310 *numberPassesPtr = numberPasses; 311 } 312 313 SkColorProfileType profileType = kLinear_SkColorProfileType; 314 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_sRGB)) { 315 profileType = kSRGB_SkColorProfileType; 316 } 317 318 if (imageInfo) { 319 *imageInfo = SkImageInfo::Make(origWidth, origHeight, colorType, alphaType, profileType); 320 } 321 autoClean.detach(); 322 if (png_ptrp) { 323 *png_ptrp = png_ptr; 324 } 325 if (info_ptrp) { 326 *info_ptrp = info_ptr; 327 } 328 329 return true; 330 } 331 332 SkPngCodec::SkPngCodec(const SkImageInfo& info, SkStream* stream, SkPngChunkReader* chunkReader, 333 png_structp png_ptr, png_infop info_ptr, int bitDepth, int numberPasses) 334 : INHERITED(info, stream) 335 , fPngChunkReader(SkSafeRef(chunkReader)) 336 , fPng_ptr(png_ptr) 337 , fInfo_ptr(info_ptr) 338 , fSrcConfig(SkSwizzler::kUnknown) 339 , fNumberPasses(numberPasses) 340 , fBitDepth(bitDepth) 341 {} 342 343 SkPngCodec::~SkPngCodec() { 344 this->destroyReadStruct(); 345 } 346 347 void SkPngCodec::destroyReadStruct() { 348 if (fPng_ptr) { 349 // We will never have a nullptr fInfo_ptr with a non-nullptr fPng_ptr 350 SkASSERT(fInfo_ptr); 351 png_destroy_read_struct(&fPng_ptr, &fInfo_ptr, nullptr); 352 fPng_ptr = nullptr; 353 fInfo_ptr = nullptr; 354 } 355 } 356 357 /////////////////////////////////////////////////////////////////////////////// 358 // Getting the pixels 359 /////////////////////////////////////////////////////////////////////////////// 360 361 SkCodec::Result SkPngCodec::initializeSwizzler(const SkImageInfo& requestedInfo, 362 const Options& options, 363 SkPMColor ctable[], 364 int* ctableCount) { 365 // FIXME: Could we use the return value of setjmp to specify the type of 366 // error? 367 if (setjmp(png_jmpbuf(fPng_ptr))) { 368 SkCodecPrintf("setjmp long jump!\n"); 369 return kInvalidInput; 370 } 371 png_read_update_info(fPng_ptr, fInfo_ptr); 372 373 // suggestedColorType was determined in read_header() based on the encodedColorType 374 const SkColorType suggestedColorType = this->getInfo().colorType(); 375 376 switch (suggestedColorType) { 377 case kIndex_8_SkColorType: 378 //decode palette to Skia format 379 fSrcConfig = SkSwizzler::kIndex; 380 if (!this->decodePalette(kPremul_SkAlphaType == requestedInfo.alphaType(), 381 ctableCount)) { 382 return kInvalidInput; 383 } 384 break; 385 case kGray_8_SkColorType: 386 fSrcConfig = SkSwizzler::kGray; 387 break; 388 case kN32_SkColorType: { 389 const uint8_t encodedColorType = png_get_color_type(fPng_ptr, fInfo_ptr); 390 if (PNG_COLOR_TYPE_GRAY_ALPHA == encodedColorType || 391 PNG_COLOR_TYPE_GRAY == encodedColorType) { 392 // If encodedColorType is GRAY, there must be a transparent chunk. 393 // Otherwise, suggestedColorType would be kGray. We have already 394 // instructed libpng to convert the transparent chunk to alpha, 395 // so we can treat both GRAY and GRAY_ALPHA as kGrayAlpha. 396 SkASSERT(encodedColorType == PNG_COLOR_TYPE_GRAY_ALPHA || 397 png_get_valid(fPng_ptr, fInfo_ptr, PNG_INFO_tRNS)); 398 399 fSrcConfig = SkSwizzler::kGrayAlpha; 400 } else { 401 if (this->getInfo().alphaType() == kOpaque_SkAlphaType) { 402 fSrcConfig = SkSwizzler::kRGB; 403 } else { 404 fSrcConfig = SkSwizzler::kRGBA; 405 } 406 } 407 break; 408 } 409 default: 410 // We will always recommend one of the above colorTypes. 411 SkASSERT(false); 412 } 413 414 // Copy the color table to the client if they request kIndex8 mode 415 copy_color_table(requestedInfo, fColorTable, ctable, ctableCount); 416 417 // Create the swizzler. SkPngCodec retains ownership of the color table. 418 const SkPMColor* colors = get_color_ptr(fColorTable.get()); 419 fSwizzler.reset(SkSwizzler::CreateSwizzler(fSrcConfig, colors, requestedInfo, options)); 420 SkASSERT(fSwizzler); 421 422 return kSuccess; 423 } 424 425 426 bool SkPngCodec::onRewind() { 427 // This sets fPng_ptr and fInfo_ptr to nullptr. If read_header 428 // succeeds, they will be repopulated, and if it fails, they will 429 // remain nullptr. Any future accesses to fPng_ptr and fInfo_ptr will 430 // come through this function which will rewind and again attempt 431 // to reinitialize them. 432 this->destroyReadStruct(); 433 434 png_structp png_ptr; 435 png_infop info_ptr; 436 if (!read_header(this->stream(), fPngChunkReader.get(), &png_ptr, &info_ptr, 437 nullptr, nullptr, nullptr)) { 438 return false; 439 } 440 441 fPng_ptr = png_ptr; 442 fInfo_ptr = info_ptr; 443 return true; 444 } 445 446 SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void* dst, 447 size_t dstRowBytes, const Options& options, 448 SkPMColor ctable[], int* ctableCount, 449 int* rowsDecoded) { 450 if (!conversion_possible(requestedInfo, this->getInfo())) { 451 return kInvalidConversion; 452 } 453 if (options.fSubset) { 454 // Subsets are not supported. 455 return kUnimplemented; 456 } 457 458 // Note that ctable and ctableCount may be modified if there is a color table 459 const Result result = this->initializeSwizzler(requestedInfo, options, ctable, ctableCount); 460 if (result != kSuccess) { 461 return result; 462 } 463 464 const int width = requestedInfo.width(); 465 const int height = requestedInfo.height(); 466 const int bpp = SkSwizzler::BytesPerPixel(fSrcConfig); 467 const size_t srcRowBytes = width * bpp; 468 469 // FIXME: Could we use the return value of setjmp to specify the type of 470 // error? 471 int row = 0; 472 // This must be declared above the call to setjmp to avoid memory leaks on incomplete images. 473 SkAutoTMalloc<uint8_t> storage; 474 if (setjmp(png_jmpbuf(fPng_ptr))) { 475 // Assume that any error that occurs while reading rows is caused by an incomplete input. 476 if (fNumberPasses > 1) { 477 // FIXME (msarett): Handle incomplete interlaced pngs. 478 return (row == height) ? kSuccess : kInvalidInput; 479 } 480 // FIXME: We do a poor job on incomplete pngs compared to other decoders (ex: Chromium, 481 // Ubuntu Image Viewer). This is because we use the default buffer size in libpng (8192 482 // bytes), and if we can't fill the buffer, we immediately fail. 483 // For example, if we try to read 8192 bytes, and the image (incorrectly) only contains 484 // half that, which may have been enough to contain a non-zero number of lines, we fail 485 // when we could have decoded a few more lines and then failed. 486 // The read function that we provide for libpng has no way of indicating that we have 487 // made a partial read. 488 // Making our buffer size smaller improves our incomplete decodes, but what impact does 489 // it have on regular decode performance? Should we investigate using a different API 490 // instead of png_read_row? Chromium uses png_process_data. 491 *rowsDecoded = row; 492 return (row == height) ? kSuccess : kIncompleteInput; 493 } 494 495 // FIXME: We could split these out based on subclass. 496 void* dstRow = dst; 497 if (fNumberPasses > 1) { 498 storage.reset(height * srcRowBytes); 499 uint8_t* const base = storage.get(); 500 501 for (int i = 0; i < fNumberPasses; i++) { 502 uint8_t* srcRow = base; 503 for (int y = 0; y < height; y++) { 504 png_read_row(fPng_ptr, srcRow, nullptr); 505 srcRow += srcRowBytes; 506 } 507 } 508 509 // Now swizzle it. 510 uint8_t* srcRow = base; 511 for (; row < height; row++) { 512 fSwizzler->swizzle(dstRow, srcRow); 513 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); 514 srcRow += srcRowBytes; 515 } 516 } else { 517 storage.reset(srcRowBytes); 518 uint8_t* srcRow = storage.get(); 519 for (; row < height; row++) { 520 png_read_row(fPng_ptr, srcRow, nullptr); 521 fSwizzler->swizzle(dstRow, srcRow); 522 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); 523 } 524 } 525 526 // read rest of file, and get additional comment and time chunks in info_ptr 527 png_read_end(fPng_ptr, fInfo_ptr); 528 529 return kSuccess; 530 } 531 532 uint32_t SkPngCodec::onGetFillValue(SkColorType colorType) const { 533 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); 534 if (colorPtr) { 535 return get_color_table_fill_value(colorType, colorPtr, 0); 536 } 537 return INHERITED::onGetFillValue(colorType); 538 } 539 540 // Subclass of SkPngCodec which supports scanline decoding 541 class SkPngScanlineDecoder : public SkPngCodec { 542 public: 543 SkPngScanlineDecoder(const SkImageInfo& srcInfo, SkStream* stream, 544 SkPngChunkReader* chunkReader, png_structp png_ptr, png_infop info_ptr, int bitDepth) 545 : INHERITED(srcInfo, stream, chunkReader, png_ptr, info_ptr, bitDepth, 1) 546 , fSrcRow(nullptr) 547 {} 548 549 Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& options, 550 SkPMColor ctable[], int* ctableCount) override { 551 if (!conversion_possible(dstInfo, this->getInfo())) { 552 return kInvalidConversion; 553 } 554 555 const Result result = this->initializeSwizzler(dstInfo, options, ctable, 556 ctableCount); 557 if (result != kSuccess) { 558 return result; 559 } 560 561 fStorage.reset(this->getInfo().width() * SkSwizzler::BytesPerPixel(this->srcConfig())); 562 fSrcRow = fStorage.get(); 563 564 return kSuccess; 565 } 566 567 int onGetScanlines(void* dst, int count, size_t rowBytes) override { 568 // Assume that an error in libpng indicates an incomplete input. 569 int row = 0; 570 if (setjmp(png_jmpbuf(this->png_ptr()))) { 571 SkCodecPrintf("setjmp long jump!\n"); 572 return row; 573 } 574 575 void* dstRow = dst; 576 for (; row < count; row++) { 577 png_read_row(this->png_ptr(), fSrcRow, nullptr); 578 this->swizzler()->swizzle(dstRow, fSrcRow); 579 dstRow = SkTAddOffset<void>(dstRow, rowBytes); 580 } 581 582 return row; 583 } 584 585 bool onSkipScanlines(int count) override { 586 // Assume that an error in libpng indicates an incomplete input. 587 if (setjmp(png_jmpbuf(this->png_ptr()))) { 588 SkCodecPrintf("setjmp long jump!\n"); 589 return false; 590 } 591 592 for (int row = 0; row < count; row++) { 593 png_read_row(this->png_ptr(), fSrcRow, nullptr); 594 } 595 return true; 596 } 597 598 private: 599 SkAutoTMalloc<uint8_t> fStorage; 600 uint8_t* fSrcRow; 601 602 typedef SkPngCodec INHERITED; 603 }; 604 605 606 class SkPngInterlacedScanlineDecoder : public SkPngCodec { 607 public: 608 SkPngInterlacedScanlineDecoder(const SkImageInfo& srcInfo, SkStream* stream, 609 SkPngChunkReader* chunkReader, png_structp png_ptr, png_infop info_ptr, 610 int bitDepth, int numberPasses) 611 : INHERITED(srcInfo, stream, chunkReader, png_ptr, info_ptr, bitDepth, numberPasses) 612 , fHeight(-1) 613 , fCanSkipRewind(false) 614 { 615 SkASSERT(numberPasses != 1); 616 } 617 618 Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& options, 619 SkPMColor ctable[], int* ctableCount) override { 620 if (!conversion_possible(dstInfo, this->getInfo())) { 621 return kInvalidConversion; 622 } 623 624 const Result result = this->initializeSwizzler(dstInfo, options, ctable, 625 ctableCount); 626 if (result != kSuccess) { 627 return result; 628 } 629 630 fHeight = dstInfo.height(); 631 // FIXME: This need not be called on a second call to onStartScanlineDecode. 632 fSrcRowBytes = this->getInfo().width() * SkSwizzler::BytesPerPixel(this->srcConfig()); 633 fGarbageRow.reset(fSrcRowBytes); 634 fGarbageRowPtr = static_cast<uint8_t*>(fGarbageRow.get()); 635 fCanSkipRewind = true; 636 637 return SkCodec::kSuccess; 638 } 639 640 int onGetScanlines(void* dst, int count, size_t dstRowBytes) override { 641 // rewind stream if have previously called onGetScanlines, 642 // since we need entire progressive image to get scanlines 643 if (fCanSkipRewind) { 644 // We already rewound in onStartScanlineDecode, so there is no reason to rewind. 645 // Next time onGetScanlines is called, we will need to rewind. 646 fCanSkipRewind = false; 647 } else { 648 // rewindIfNeeded resets fCurrScanline, since it assumes that start 649 // needs to be called again before scanline decoding. PNG scanline 650 // decoding is the exception, since it needs to rewind between 651 // calls to getScanlines. Keep track of fCurrScanline, to undo the 652 // reset. 653 const int currScanline = this->nextScanline(); 654 // This method would never be called if currScanline is -1 655 SkASSERT(currScanline != -1); 656 657 if (!this->rewindIfNeeded()) { 658 return kCouldNotRewind; 659 } 660 this->updateCurrScanline(currScanline); 661 } 662 663 if (setjmp(png_jmpbuf(this->png_ptr()))) { 664 SkCodecPrintf("setjmp long jump!\n"); 665 // FIXME (msarett): Returning 0 is pessimistic. If we can complete a single pass, 666 // we may be able to report that all of the memory has been initialized. Even if we 667 // fail on the first pass, we can still report than some scanlines are initialized. 668 return 0; 669 } 670 SkAutoTMalloc<uint8_t> storage(count * fSrcRowBytes); 671 uint8_t* storagePtr = storage.get(); 672 uint8_t* srcRow; 673 const int startRow = this->nextScanline(); 674 for (int i = 0; i < this->numberPasses(); i++) { 675 // read rows we planned to skip into garbage row 676 for (int y = 0; y < startRow; y++){ 677 png_read_row(this->png_ptr(), fGarbageRowPtr, nullptr); 678 } 679 // read rows we care about into buffer 680 srcRow = storagePtr; 681 for (int y = 0; y < count; y++) { 682 png_read_row(this->png_ptr(), srcRow, nullptr); 683 srcRow += fSrcRowBytes; 684 } 685 // read rows we don't want into garbage buffer 686 for (int y = 0; y < fHeight - startRow - count; y++) { 687 png_read_row(this->png_ptr(), fGarbageRowPtr, nullptr); 688 } 689 } 690 //swizzle the rows we care about 691 srcRow = storagePtr; 692 void* dstRow = dst; 693 for (int y = 0; y < count; y++) { 694 this->swizzler()->swizzle(dstRow, srcRow); 695 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); 696 srcRow += fSrcRowBytes; 697 } 698 699 return count; 700 } 701 702 bool onSkipScanlines(int count) override { 703 // The non-virtual version will update fCurrScanline. 704 return true; 705 } 706 707 SkScanlineOrder onGetScanlineOrder() const override { 708 return kNone_SkScanlineOrder; 709 } 710 711 private: 712 int fHeight; 713 size_t fSrcRowBytes; 714 SkAutoMalloc fGarbageRow; 715 uint8_t* fGarbageRowPtr; 716 // FIXME: This imitates behavior in SkCodec::rewindIfNeeded. That function 717 // is called whenever some action is taken that reads the stream and 718 // therefore the next call will require a rewind. So it modifies a boolean 719 // to note that the *next* time it is called a rewind is needed. 720 // SkPngInterlacedScanlineDecoder has an extra wrinkle - calling 721 // onStartScanlineDecode followed by onGetScanlines does *not* require a 722 // rewind. Since rewindIfNeeded does not have this flexibility, we need to 723 // add another layer. 724 bool fCanSkipRewind; 725 726 typedef SkPngCodec INHERITED; 727 }; 728 729 SkCodec* SkPngCodec::NewFromStream(SkStream* stream, SkPngChunkReader* chunkReader) { 730 SkAutoTDelete<SkStream> streamDeleter(stream); 731 png_structp png_ptr; 732 png_infop info_ptr; 733 SkImageInfo imageInfo; 734 int bitDepth; 735 int numberPasses; 736 737 if (!read_header(stream, chunkReader, &png_ptr, &info_ptr, &imageInfo, &bitDepth, 738 &numberPasses)) { 739 return nullptr; 740 } 741 742 if (1 == numberPasses) { 743 return new SkPngScanlineDecoder(imageInfo, streamDeleter.detach(), chunkReader, 744 png_ptr, info_ptr, bitDepth); 745 } 746 747 return new SkPngInterlacedScanlineDecoder(imageInfo, streamDeleter.detach(), chunkReader, 748 png_ptr, info_ptr, bitDepth, numberPasses); 749 } 750