Chromium Code Reviews| 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 "SkColorPriv.h" | 9 #include "SkColorPriv.h" |
| 10 #include "SkColorTable.h" | 10 #include "SkColorTable.h" |
| 11 #include "SkBitmap.h" | 11 #include "SkBitmap.h" |
| 12 #include "SkMath.h" | 12 #include "SkMath.h" |
| 13 #include "SkScanlineDecoder.h" | |
| 13 #include "SkSize.h" | 14 #include "SkSize.h" |
| 14 #include "SkStream.h" | 15 #include "SkStream.h" |
| 15 #include "SkSwizzler.h" | 16 #include "SkSwizzler.h" |
| 16 | 17 |
| 17 /////////////////////////////////////////////////////////////////////////////// | 18 /////////////////////////////////////////////////////////////////////////////// |
| 18 // Helper macros | 19 // Helper macros |
| 19 /////////////////////////////////////////////////////////////////////////////// | 20 /////////////////////////////////////////////////////////////////////////////// |
| 20 | 21 |
| 21 #ifndef png_jmpbuf | 22 #ifndef png_jmpbuf |
| 22 # define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) | 23 # define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 106 png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL); | 107 png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL); |
| 107 return num_trans > 0; | 108 return num_trans > 0; |
| 108 } | 109 } |
| 109 | 110 |
| 110 // Method for coverting to either an SkPMColor or a similarly packed | 111 // Method for coverting to either an SkPMColor or a similarly packed |
| 111 // unpremultiplied color. | 112 // unpremultiplied color. |
| 112 typedef uint32_t (*PackColorProc)(U8CPU a, U8CPU r, U8CPU g, U8CPU b); | 113 typedef uint32_t (*PackColorProc)(U8CPU a, U8CPU r, U8CPU g, U8CPU b); |
| 113 | 114 |
| 114 // Note: SkColorTable claims to store SkPMColors, which is not necessarily | 115 // Note: SkColorTable claims to store SkPMColors, which is not necessarily |
| 115 // the case here. | 116 // the case here. |
| 116 SkColorTable* decode_palette(png_structp png_ptr, png_infop info_ptr, | 117 bool SkPngCodec::decodePalette(bool premultiply) { |
| 117 bool premultiply, SkAlphaType* outAlphaType) { | |
| 118 SkASSERT(outAlphaType != NULL); | |
| 119 int numPalette; | 118 int numPalette; |
| 120 png_colorp palette; | 119 png_colorp palette; |
| 121 png_bytep trans; | 120 png_bytep trans; |
| 122 | 121 |
| 123 if (!png_get_PLTE(png_ptr, info_ptr, &palette, &numPalette)) { | 122 if (!png_get_PLTE(fPng_ptr, fInfo_ptr, &palette, &numPalette)) { |
| 124 return NULL; | 123 return false; |
| 125 } | 124 } |
| 126 | 125 |
| 127 /* BUGGY IMAGE WORKAROUND | 126 /* BUGGY IMAGE WORKAROUND |
| 128 | 127 |
| 129 We hit some images (e.g. fruit_.png) who contain bytes that are == color table_count | 128 We hit some images (e.g. fruit_.png) who contain bytes that are == color table_count |
| 130 which is a problem since we use the byte as an index. To work around thi s we grow | 129 which is a problem since we use the byte as an index. To work around thi s we grow |
| 131 the colortable by 1 (if its < 256) and duplicate the last color into tha t slot. | 130 the colortable by 1 (if its < 256) and duplicate the last color into tha t slot. |
| 132 */ | 131 */ |
| 133 const int colorCount = numPalette + (numPalette < 256); | 132 const int colorCount = numPalette + (numPalette < 256); |
| 134 // Note: These are not necessarily SkPMColors. | 133 // Note: These are not necessarily SkPMColors. |
| 135 SkPMColor colorStorage[256]; // worst-case storage | 134 SkPMColor colorStorage[256]; // worst-case storage |
| 136 SkPMColor* colorPtr = colorStorage; | 135 SkPMColor* colorPtr = colorStorage; |
| 137 | 136 |
| 138 int numTrans; | 137 int numTrans; |
| 139 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { | 138 if (png_get_valid(fPng_ptr, fInfo_ptr, PNG_INFO_tRNS)) { |
| 140 png_get_tRNS(png_ptr, info_ptr, &trans, &numTrans, NULL); | 139 png_get_tRNS(fPng_ptr, fInfo_ptr, &trans, &numTrans, NULL); |
| 141 } else { | 140 } else { |
| 142 numTrans = 0; | 141 numTrans = 0; |
| 143 } | 142 } |
| 144 | 143 |
| 145 // check for bad images that might make us crash | 144 // check for bad images that might make us crash |
| 146 if (numTrans > numPalette) { | 145 if (numTrans > numPalette) { |
| 147 numTrans = numPalette; | 146 numTrans = numPalette; |
| 148 } | 147 } |
| 149 | 148 |
| 150 int index = 0; | 149 int index = 0; |
| 151 int transLessThanFF = 0; | 150 int transLessThanFF = 0; |
| 152 | 151 |
| 153 // Choose which function to use to create the color table. If the final dest ination's | 152 // Choose which function to use to create the color table. If the final dest ination's |
| 154 // colortype is unpremultiplied, the color table will store unpremultiplied colors. | 153 // colortype is unpremultiplied, the color table will store unpremultiplied colors. |
| 155 PackColorProc proc; | 154 PackColorProc proc; |
| 156 if (premultiply) { | 155 if (premultiply) { |
| 157 proc = &SkPreMultiplyARGB; | 156 proc = &SkPreMultiplyARGB; |
| 158 } else { | 157 } else { |
| 159 proc = &SkPackARGB32NoCheck; | 158 proc = &SkPackARGB32NoCheck; |
| 160 } | 159 } |
| 161 for (; index < numTrans; index++) { | 160 for (; index < numTrans; index++) { |
| 162 transLessThanFF |= (int)*trans - 0xFF; | 161 transLessThanFF |= (int)*trans - 0xFF; |
| 163 *colorPtr++ = proc(*trans++, palette->red, palette->green, palette->blue ); | 162 *colorPtr++ = proc(*trans++, palette->red, palette->green, palette->blue ); |
| 164 palette++; | 163 palette++; |
| 165 } | 164 } |
| 166 | 165 |
| 167 if (transLessThanFF < 0) { | 166 fReallyHasAlpha = transLessThanFF < 0; |
| 168 *outAlphaType = premultiply ? kPremul_SkAlphaType : kUnpremul_SkAlphaTyp e; | |
| 169 } else { | |
| 170 *outAlphaType = kOpaque_SkAlphaType; | |
| 171 } | |
| 172 | 167 |
| 173 for (; index < numPalette; index++) { | 168 for (; index < numPalette; index++) { |
| 174 *colorPtr++ = SkPackARGB32(0xFF, palette->red, palette->green, palette-> blue); | 169 *colorPtr++ = SkPackARGB32(0xFF, palette->red, palette->green, palette-> blue); |
| 175 palette++; | 170 palette++; |
| 176 } | 171 } |
| 177 | 172 |
| 178 // see BUGGY IMAGE WORKAROUND comment above | 173 // see BUGGY IMAGE WORKAROUND comment above |
| 179 if (numPalette < 256) { | 174 if (numPalette < 256) { |
| 180 *colorPtr = colorPtr[-1]; | 175 *colorPtr = colorPtr[-1]; |
| 181 } | 176 } |
| 182 | 177 |
| 183 return SkNEW_ARGS(SkColorTable, (colorStorage, colorCount)); | 178 fColorTable.reset(SkNEW_ARGS(SkColorTable, (colorStorage, colorCount))); |
| 179 return true; | |
| 184 } | 180 } |
| 185 | 181 |
| 186 /////////////////////////////////////////////////////////////////////////////// | 182 /////////////////////////////////////////////////////////////////////////////// |
| 187 // Creation | 183 // Creation |
| 188 /////////////////////////////////////////////////////////////////////////////// | 184 /////////////////////////////////////////////////////////////////////////////// |
| 189 | 185 |
| 190 #define PNG_BYTES_TO_CHECK 4 | 186 #define PNG_BYTES_TO_CHECK 4 |
| 191 | 187 |
| 192 bool SkPngCodec::IsPng(SkStream* stream) { | 188 bool SkPngCodec::IsPng(SkStream* stream) { |
| 193 char buf[PNG_BYTES_TO_CHECK]; | 189 char buf[PNG_BYTES_TO_CHECK]; |
| (...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 325 | 321 |
| 326 // FIXME: Also need to check for sRGB (skbug.com/3471). | 322 // FIXME: Also need to check for sRGB (skbug.com/3471). |
| 327 | 323 |
| 328 SkImageInfo info = SkImageInfo::Make(origWidth, origHeight, skColorType, | 324 SkImageInfo info = SkImageInfo::Make(origWidth, origHeight, skColorType, |
| 329 skAlphaType); | 325 skAlphaType); |
| 330 SkCodec* codec = SkNEW_ARGS(SkPngCodec, (info, stream, png_ptr, info_ptr)); | 326 SkCodec* codec = SkNEW_ARGS(SkPngCodec, (info, stream, png_ptr, info_ptr)); |
| 331 autoClean.detach(); | 327 autoClean.detach(); |
| 332 return codec; | 328 return codec; |
| 333 } | 329 } |
| 334 | 330 |
| 331 #define INVALID_NUMBER_PASSES -1 | |
| 335 SkPngCodec::SkPngCodec(const SkImageInfo& info, SkStream* stream, | 332 SkPngCodec::SkPngCodec(const SkImageInfo& info, SkStream* stream, |
| 336 png_structp png_ptr, png_infop info_ptr) | 333 png_structp png_ptr, png_infop info_ptr) |
| 337 : INHERITED(info, stream) | 334 : INHERITED(info, stream) |
| 338 , fPng_ptr(png_ptr) | 335 , fPng_ptr(png_ptr) |
| 339 , fInfo_ptr(info_ptr) {} | 336 , fInfo_ptr(info_ptr) |
| 337 , fSc(SkSwizzler::kUnknown) | |
| 338 , fNumberPasses(INVALID_NUMBER_PASSES) | |
| 339 , fReallyHasAlpha(false) | |
| 340 {} | |
| 340 | 341 |
| 341 SkPngCodec::~SkPngCodec() { | 342 SkPngCodec::~SkPngCodec() { |
| 342 png_destroy_read_struct(&fPng_ptr, &fInfo_ptr, png_infopp_NULL); | 343 png_destroy_read_struct(&fPng_ptr, &fInfo_ptr, png_infopp_NULL); |
| 343 } | 344 } |
| 344 | 345 |
| 345 /////////////////////////////////////////////////////////////////////////////// | 346 /////////////////////////////////////////////////////////////////////////////// |
| 346 // Getting the pixels | 347 // Getting the pixels |
| 347 /////////////////////////////////////////////////////////////////////////////// | 348 /////////////////////////////////////////////////////////////////////////////// |
| 348 | 349 |
| 349 static bool premul_and_unpremul(SkAlphaType A, SkAlphaType B) { | 350 static bool premul_and_unpremul(SkAlphaType A, SkAlphaType B) { |
| 350 return kPremul_SkAlphaType == A && kUnpremul_SkAlphaType == B; | 351 return kPremul_SkAlphaType == A && kUnpremul_SkAlphaType == B; |
| 351 } | 352 } |
| 352 | 353 |
| 353 static bool conversion_possible(const SkImageInfo& A, const SkImageInfo& B) { | 354 static bool conversion_possible(const SkImageInfo& A, const SkImageInfo& B) { |
| 354 // TODO: Support other conversions | 355 // TODO: Support other conversions |
| 355 if (A.colorType() != B.colorType()) { | 356 if (A.colorType() != B.colorType()) { |
| 356 return false; | 357 return false; |
| 357 } | 358 } |
| 358 if (A.profileType() != B.profileType()) { | 359 if (A.profileType() != B.profileType()) { |
| 359 return false; | 360 return false; |
| 360 } | 361 } |
| 361 if (A.alphaType() == B.alphaType()) { | 362 if (A.alphaType() == B.alphaType()) { |
| 362 return true; | 363 return true; |
| 363 } | 364 } |
| 364 return premul_and_unpremul(A.alphaType(), B.alphaType()) | 365 return premul_and_unpremul(A.alphaType(), B.alphaType()) |
| 365 || premul_and_unpremul(B.alphaType(), A.alphaType()); | 366 || premul_and_unpremul(B.alphaType(), A.alphaType()); |
| 366 } | 367 } |
| 367 | 368 |
| 368 SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void* dst, | 369 SkCodec::Result SkPngCodec::initializeSwizzler(const SkImageInfo& requestedInfo, void* dst, |
| 369 size_t rowBytes, SkPMColor ctable[], | 370 size_t rowBytes) { |
| 370 int* ctableCount) { | |
| 371 if (!this->rewindIfNeeded()) { | |
| 372 return kCouldNotRewind; | |
| 373 } | |
| 374 if (requestedInfo.dimensions() != this->getOriginalInfo().dimensions()) { | |
| 375 return kInvalidScale; | |
| 376 } | |
| 377 if (!conversion_possible(requestedInfo, this->getOriginalInfo())) { | |
| 378 return kInvalidConversion; | |
| 379 } | |
| 380 | |
| 381 SkBitmap decodedBitmap; | |
| 382 // If installPixels would have failed, getPixels should have failed before | |
| 383 // calling onGetPixels. | |
| 384 SkAssertResult(decodedBitmap.installPixels(requestedInfo, dst, rowBytes)); | |
| 385 | |
| 386 // Initialize all non-trivial objects before setjmp. | |
| 387 SkAutoTUnref<SkColorTable> colorTable; | |
| 388 SkAutoTDelete<SkSwizzler> swizzler; | |
| 389 SkAutoMalloc storage; // Scratch memory for pre-swizzled r ows. | |
| 390 | |
| 391 // FIXME: Could we use the return value of setjmp to specify the type of | 371 // FIXME: Could we use the return value of setjmp to specify the type of |
| 392 // error? | 372 // error? |
| 393 if (setjmp(png_jmpbuf(fPng_ptr))) { | 373 if (setjmp(png_jmpbuf(fPng_ptr))) { |
| 394 SkDebugf("setjmp long jump!\n"); | 374 SkDebugf("setjmp long jump!\n"); |
| 395 return kInvalidInput; | 375 return kInvalidInput; |
| 396 } | 376 } |
| 397 | 377 |
| 398 // FIXME: We already retrieved this information. Store it in SkPngCodec? | 378 // FIXME: We already retrieved this information. Store it in SkPngCodec? |
| 399 png_uint_32 origWidth, origHeight; | 379 png_uint_32 origWidth, origHeight; |
| 400 int bitDepth, pngColorType, interlaceType; | 380 int bitDepth, pngColorType, interlaceType; |
| 401 png_get_IHDR(fPng_ptr, fInfo_ptr, &origWidth, &origHeight, &bitDepth, | 381 png_get_IHDR(fPng_ptr, fInfo_ptr, &origWidth, &origHeight, &bitDepth, |
| 402 &pngColorType, &interlaceType, int_p_NULL, int_p_NULL); | 382 &pngColorType, &interlaceType, int_p_NULL, int_p_NULL); |
| 403 | 383 |
| 404 const int numberPasses = (interlaceType != PNG_INTERLACE_NONE) ? | 384 fNumberPasses = (interlaceType != PNG_INTERLACE_NONE) ? |
| 405 png_set_interlace_handling(fPng_ptr) : 1; | 385 png_set_interlace_handling(fPng_ptr) : 1; |
| 406 | 386 |
| 407 SkSwizzler::SrcConfig sc; | 387 // Set to the default before calling decodePalette, which may change it. |
| 408 bool reallyHasAlpha = false; | 388 fReallyHasAlpha = false; |
| 409 if (PNG_COLOR_TYPE_PALETTE == pngColorType) { | 389 if (PNG_COLOR_TYPE_PALETTE == pngColorType) { |
| 410 sc = SkSwizzler::kIndex; | 390 fSc = SkSwizzler::kIndex; |
| 411 SkAlphaType at = requestedInfo.alphaType(); | 391 if (!this->decodePalette(kPremul_SkAlphaType == requestedInfo.alphaType( ))) { |
| 412 colorTable.reset(decode_palette(fPng_ptr, fInfo_ptr, | |
| 413 kPremul_SkAlphaType == at, | |
| 414 &at)); | |
| 415 if (!colorTable) { | |
| 416 return kInvalidInput; | 392 return kInvalidInput; |
| 417 } | 393 } |
| 418 | |
| 419 reallyHasAlpha = (at != kOpaque_SkAlphaType); | |
| 420 | |
| 421 if (at != requestedInfo.alphaType()) { | |
| 422 // It turns out the image is opaque. | |
| 423 SkASSERT(kOpaque_SkAlphaType == at); | |
| 424 } | |
| 425 } else if (kAlpha_8_SkColorType == requestedInfo.colorType()) { | 394 } else if (kAlpha_8_SkColorType == requestedInfo.colorType()) { |
| 426 // Note: we check the destination, since otherwise we would have | 395 // Note: we check the destination, since otherwise we would have |
| 427 // told png to upscale. | 396 // told png to upscale. |
| 428 SkASSERT(PNG_COLOR_TYPE_GRAY == pngColorType); | 397 SkASSERT(PNG_COLOR_TYPE_GRAY == pngColorType); |
| 429 sc = SkSwizzler::kGray; | 398 fSc = SkSwizzler::kGray; |
| 430 } else if (this->getOriginalInfo().alphaType() == kOpaque_SkAlphaType) { | 399 } else if (this->getOriginalInfo().alphaType() == kOpaque_SkAlphaType) { |
| 431 sc = SkSwizzler::kRGBX; | 400 fSc = SkSwizzler::kRGBX; |
| 432 } else { | 401 } else { |
| 433 sc = SkSwizzler::kRGBA; | 402 fSc = SkSwizzler::kRGBA; |
| 434 } | 403 } |
| 435 const SkPMColor* colors = colorTable ? colorTable->readColors() : NULL; | 404 const SkPMColor* colors = fColorTable ? fColorTable->readColors() : NULL; |
| 436 // TODO: Support skipZeroes. | 405 // TODO: Support skipZeroes. |
| 437 swizzler.reset(SkSwizzler::CreateSwizzler(sc, colors, requestedInfo, | 406 fSwizzler.reset(SkSwizzler::CreateSwizzler(fSc, colors, requestedInfo, |
| 438 dst, rowBytes, false)); | 407 dst, rowBytes, false)); |
| 439 if (!swizzler) { | 408 if (!fSwizzler) { |
| 440 // FIXME: CreateSwizzler could fail for another reason. | 409 // FIXME: CreateSwizzler could fail for another reason. |
| 441 return kUnimplemented; | 410 return kUnimplemented; |
| 442 } | 411 } |
| 443 | 412 |
| 444 // FIXME: Here is where we should likely insert some of the modifications | 413 // FIXME: Here is where we should likely insert some of the modifications |
| 445 // made in the factory. | 414 // made in the factory. |
| 446 png_read_update_info(fPng_ptr, fInfo_ptr); | 415 png_read_update_info(fPng_ptr, fInfo_ptr); |
| 447 | 416 |
| 448 if (numberPasses > 1) { | 417 return kSuccess; |
| 418 } | |
| 419 | |
| 420 SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void* dst, | |
| 421 size_t rowBytes, SkPMColor ctable[], | |
| 422 int* ctableCount) { | |
| 423 if (!this->rewindIfNeeded()) { | |
| 424 return kCouldNotRewind; | |
| 425 } | |
| 426 if (requestedInfo.dimensions() != this->getOriginalInfo().dimensions()) { | |
| 427 return kInvalidScale; | |
| 428 } | |
| 429 if (!conversion_possible(requestedInfo, this->getOriginalInfo())) { | |
| 430 return kInvalidConversion; | |
| 431 } | |
| 432 | |
| 433 const Result result = this->initializeSwizzler(requestedInfo, dst, rowBytes) ; | |
| 434 if (result != kSuccess) { | |
| 435 return result; | |
| 436 } | |
| 437 | |
| 438 // FIXME: Could we use the return value of setjmp to specify the type of | |
| 439 // error? | |
| 440 if (setjmp(png_jmpbuf(fPng_ptr))) { | |
| 441 SkDebugf("setjmp long jump!\n"); | |
| 442 return kInvalidInput; | |
| 443 } | |
| 444 | |
| 445 SkASSERT(fNumberPasses != INVALID_NUMBER_PASSES); | |
| 446 SkAutoMalloc storage; | |
| 447 if (fNumberPasses > 1) { | |
| 449 const int width = requestedInfo.width(); | 448 const int width = requestedInfo.width(); |
| 450 const int height = requestedInfo.height(); | 449 const int height = requestedInfo.height(); |
| 451 const int bpp = SkSwizzler::BytesPerPixel(sc); | 450 const int bpp = SkSwizzler::BytesPerPixel(fSc); |
| 452 const size_t rowBytes = width * bpp; | 451 const size_t rowBytes = width * bpp; |
| 453 | 452 |
| 454 storage.reset(width * height * bpp); | 453 storage.reset(width * height * bpp); |
| 455 uint8_t* const base = static_cast<uint8_t*>(storage.get()); | 454 uint8_t* const base = static_cast<uint8_t*>(storage.get()); |
| 456 | 455 |
| 457 for (int i = 0; i < numberPasses; i++) { | 456 for (int i = 0; i < fNumberPasses; i++) { |
| 458 uint8_t* row = base; | 457 uint8_t* row = base; |
| 459 for (int y = 0; y < height; y++) { | 458 for (int y = 0; y < height; y++) { |
| 460 uint8_t* bmRow = row; | 459 uint8_t* bmRow = row; |
| 461 png_read_rows(fPng_ptr, &bmRow, png_bytepp_NULL, 1); | 460 png_read_rows(fPng_ptr, &bmRow, png_bytepp_NULL, 1); |
| 462 row += rowBytes; | 461 row += rowBytes; |
| 463 } | 462 } |
| 464 } | 463 } |
| 465 | 464 |
| 466 // Now swizzle it. | 465 // Now swizzle it. |
| 467 uint8_t* row = base; | 466 uint8_t* row = base; |
| 468 for (int y = 0; y < height; y++) { | 467 for (int y = 0; y < height; y++) { |
| 469 reallyHasAlpha |= swizzler->next(row); | 468 fReallyHasAlpha |= fSwizzler->next(row); |
| 470 row += rowBytes; | 469 row += rowBytes; |
| 471 } | 470 } |
| 472 } else { | 471 } else { |
| 473 storage.reset(requestedInfo.width() * SkSwizzler::BytesPerPixel(sc)); | 472 storage.reset(requestedInfo.width() * SkSwizzler::BytesPerPixel(fSc)); |
| 474 uint8_t* srcRow = static_cast<uint8_t*>(storage.get()); | 473 uint8_t* srcRow = static_cast<uint8_t*>(storage.get()); |
| 475 for (int y = 0; y < requestedInfo.height(); y++) { | 474 for (int y = 0; y < requestedInfo.height(); y++) { |
| 476 png_read_rows(fPng_ptr, &srcRow, png_bytepp_NULL, 1); | 475 png_read_rows(fPng_ptr, &srcRow, png_bytepp_NULL, 1); |
| 477 reallyHasAlpha |= swizzler->next(srcRow); | 476 fReallyHasAlpha |= fSwizzler->next(srcRow); |
| 478 } | 477 } |
| 479 } | 478 } |
| 480 | 479 |
| 480 // FIXME: do we need substituteTranspColor? Note that we cannot do it for | |
| 481 // scanline decoding, but we could do it here. Alternatively, we could do | |
| 482 // it as we go, instead of in post-processing like SkPNGImageDecoder. | |
| 483 | |
| 484 return this->finish(); | |
| 485 } | |
| 486 | |
| 487 SkImageGenerator::Result SkPngCodec::finish() { | |
| 488 // FIXME: Maybe these should return incomplete? | |
| 489 if (setjmp(png_jmpbuf(fPng_ptr))) { | |
| 490 SkDebugf("setjmp long jump!\n"); | |
| 491 return kInvalidInput; | |
| 492 } | |
| 481 /* read rest of file, and get additional chunks in info_ptr - REQUIRED */ | 493 /* read rest of file, and get additional chunks in info_ptr - REQUIRED */ |
| 482 png_read_end(fPng_ptr, fInfo_ptr); | 494 png_read_end(fPng_ptr, fInfo_ptr); |
| 483 | 495 |
| 484 // FIXME: do we need substituteTranspColor? | |
| 485 | |
| 486 if (reallyHasAlpha && requestedInfo.alphaType() != kOpaque_SkAlphaType) { | |
| 487 // FIXME: We want to alert the caller. Is this the right way? | |
| 488 SkImageInfo* modInfo = const_cast<SkImageInfo*>(&requestedInfo); | |
| 489 *modInfo = requestedInfo.makeAlphaType(kOpaque_SkAlphaType); | |
| 490 } | |
| 491 return kSuccess; | 496 return kSuccess; |
| 492 } | 497 } |
| 498 | |
| 499 class SkPngScanlineDecoder : public SkScanlineDecoder { | |
| 500 public: | |
| 501 // FIXME: Need to support subsets... | |
| 502 SkPngScanlineDecoder(const SkImageInfo& origInfo, const SkImageInfo& dstInfo , | |
| 503 SkPngCodec* codec) | |
| 504 // FIXME: Does SkScanlineDecoder need origInfo? Maybe for subsets? | |
| 505 : INHERITED(origInfo, dstInfo) | |
| 506 , fDstInfo(dstInfo) | |
| 507 , fCodec(codec) | |
| 508 , fHasAlpha(false) | |
| 509 { | |
| 510 fStorage.reset(dstInfo.width() * SkSwizzler::BytesPerPixel(fCodec->fSc)) ; | |
| 511 fSrcRow = static_cast<uint8_t*>(fStorage.get()); | |
| 512 } | |
| 513 | |
| 514 SkImageGenerator::Result onGetNextScanline(void* dst) SK_OVERRIDE { | |
|
reed1
2015/03/19 15:31:39
Is it easy to override the N-scanlines method here
scroggo
2015/03/19 17:59:19
Yes.
| |
| 515 // FIXME: Could we use the return value of setjmp to specify the type of | |
| 516 // error? | |
| 517 if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) { | |
| 518 SkDebugf("setjmp long jump!\n"); | |
| 519 return SkImageGenerator::kInvalidInput; | |
| 520 } | |
| 521 | |
| 522 png_read_rows(fCodec->fPng_ptr, &fSrcRow, png_bytepp_NULL, 1); | |
| 523 fCodec->fSwizzler->setDstRow(dst); | |
| 524 fHasAlpha |= fCodec->fSwizzler->next(fSrcRow); | |
| 525 return SkImageGenerator::kSuccess; | |
| 526 } | |
| 527 | |
| 528 SkImageGenerator::Result onFinish() SK_OVERRIDE { | |
| 529 return fCodec->finish(); | |
| 530 } | |
| 531 | |
| 532 bool onReallyHasAlpha() const SK_OVERRIDE { return fHasAlpha; } | |
| 533 | |
| 534 private: | |
| 535 const SkImageInfo& fDstInfo; | |
| 536 SkPngCodec* fCodec; // Unowned. | |
| 537 bool fHasAlpha; | |
| 538 SkAutoMalloc fStorage; | |
| 539 uint8_t* fSrcRow; | |
| 540 | |
| 541 typedef SkScanlineDecoder INHERITED; | |
| 542 }; | |
| 543 | |
| 544 SkScanlineDecoder* SkPngCodec::onGetScanlineDecoder(const SkImageInfo& dstInfo, | |
| 545 const SkIRect& origSubset) { | |
| 546 // Check to see if scaling was requested. | |
| 547 if (dstInfo.dimensions() != origSubset.size()) { | |
| 548 SkDebugf("Scaling not supported: dimensions: %d %d\toriginal: %d %d\n", | |
| 549 dstInfo.width(), dstInfo.height(), | |
| 550 origSubset.width(), origSubset.height()); | |
| 551 return NULL; | |
| 552 } | |
| 553 | |
| 554 if (!conversion_possible(dstInfo, this->getOriginalInfo())) { | |
| 555 SkDebugf("no conversion possible\n"); | |
| 556 return NULL; | |
| 557 } | |
| 558 | |
| 559 // Note: We set dst to NULL since we do not know it yet. rowBytes is not nee ded, | |
| 560 // since we'll be manually updating the dstRow, but the SkSwizzler requires it to | |
| 561 // be at least dstInfo.minRowBytes. | |
| 562 if (this->initializeSwizzler(dstInfo, NULL, dstInfo.minRowBytes()) != kSucce ss) { | |
| 563 SkDebugf("failed to initialize the swizzler.\n"); | |
| 564 return NULL; | |
| 565 } | |
| 566 | |
| 567 SkASSERT(fNumberPasses != INVALID_NUMBER_PASSES); | |
| 568 if (fNumberPasses > 1) { | |
| 569 // We cannot efficiently do scanline decoding. | |
| 570 return NULL; | |
| 571 } | |
| 572 | |
| 573 return SkNEW_ARGS(SkPngScanlineDecoder, (this->getOriginalInfo(), dstInfo, t his)); | |
| 574 } | |
| 575 | |
| OLD | NEW |