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 "SkCodecPriv.h" | 9 #include "SkCodecPriv.h" |
| 10 #include "SkColorPriv.h" | 10 #include "SkColorPriv.h" |
| (...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 207 } | 207 } |
| 208 return true; | 208 return true; |
| 209 } | 209 } |
| 210 | 210 |
| 211 // Reads the header, and initializes the passed in fields, if not NULL (except | 211 // Reads the header, and initializes the passed in fields, if not NULL (except |
| 212 // stream, which is passed to the read function). | 212 // stream, which is passed to the read function). |
| 213 // Returns true on success, in which case the caller is responsible for calling | 213 // Returns true on success, in which case the caller is responsible for calling |
| 214 // png_destroy_read_struct. If it returns false, the passed in fields (except | 214 // png_destroy_read_struct. If it returns false, the passed in fields (except |
| 215 // stream) are unchanged. | 215 // stream) are unchanged. |
| 216 static bool read_header(SkStream* stream, png_structp* png_ptrp, | 216 static bool read_header(SkStream* stream, png_structp* png_ptrp, |
| 217 png_infop* info_ptrp, SkImageInfo* imageInfo) { | 217 png_infop* info_ptrp, SkImageInfo* imageInfo, int bitDep th) { |
|
scroggo
2015/06/30 15:38:37
I believe you want this to be an int* rather than
emmaleer
2015/06/30 20:13:41
Done.
| |
| 218 // The image is known to be a PNG. Decode enough to know the SkImageInfo. | 218 // The image is known to be a PNG. Decode enough to know the SkImageInfo. |
| 219 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, | 219 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, |
| 220 sk_error_fn, sk_warning_fn); | 220 sk_error_fn, sk_warning_fn); |
| 221 if (!png_ptr) { | 221 if (!png_ptr) { |
| 222 return false; | 222 return false; |
| 223 } | 223 } |
| 224 | 224 |
| 225 AutoCleanPng autoClean(png_ptr); | 225 AutoCleanPng autoClean(png_ptr); |
| 226 | 226 |
| 227 png_infop info_ptr = png_create_info_struct(png_ptr); | 227 png_infop info_ptr = png_create_info_struct(png_ptr); |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 241 | 241 |
| 242 // FIXME: This is where the old code hooks up the Peeker. Does it need to | 242 // FIXME: This is where the old code hooks up the Peeker. Does it need to |
| 243 // be set this early? (i.e. where are the user chunks? early in the stream, | 243 // be set this early? (i.e. where are the user chunks? early in the stream, |
| 244 // potentially?) | 244 // potentially?) |
| 245 // If it does, we need to figure out a way to set it here. | 245 // If it does, we need to figure out a way to set it here. |
| 246 | 246 |
| 247 // The call to png_read_info() gives us all of the information from the | 247 // The call to png_read_info() gives us all of the information from the |
| 248 // PNG file before the first IDAT (image data chunk). | 248 // PNG file before the first IDAT (image data chunk). |
| 249 png_read_info(png_ptr, info_ptr); | 249 png_read_info(png_ptr, info_ptr); |
| 250 png_uint_32 origWidth, origHeight; | 250 png_uint_32 origWidth, origHeight; |
| 251 int bitDepth, colorType; | 251 int colorType; |
| 252 png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth, | 252 png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth, |
| 253 &colorType, int_p_NULL, int_p_NULL, int_p_NULL); | 253 &colorType, int_p_NULL, int_p_NULL, int_p_NULL); |
| 254 | 254 |
| 255 // sanity check for size | 255 // sanity check for size |
| 256 { | 256 { |
| 257 int64_t size = sk_64_mul(origWidth, origHeight); | 257 int64_t size = sk_64_mul(origWidth, origHeight); |
| 258 // now check that if we are 4-bytes per pixel, we also don't overflow | 258 // now check that if we are 4-bytes per pixel, we also don't overflow |
| 259 if (size < 0 || size > (0x7FFFFFFF >> 2)) { | 259 if (size < 0 || size > (0x7FFFFFFF >> 2)) { |
| 260 return false; | 260 return false; |
| 261 } | 261 } |
| 262 } | 262 } |
| 263 | 263 |
| 264 // Tell libpng to strip 16 bit/color files down to 8 bits/color | 264 // Tell libpng to strip 16 bit/color files down to 8 bits/color |
| 265 if (bitDepth == 16) { | 265 if (bitDepth == 16) { |
| 266 png_set_strip_16(png_ptr); | 266 png_set_strip_16(png_ptr); |
| 267 } | 267 } |
| 268 #ifdef PNG_READ_PACK_SUPPORTED | 268 #ifdef PNG_READ_PACK_SUPPORTED |
| 269 // Extract multiple pixels with bit depths of 1, 2, and 4 from a single | 269 // Extract multiple pixels with bit depths of 1, 2, and 4 from a single |
| 270 // byte into separate bytes (useful for paletted and grayscale images). | 270 // byte into separate bytes (useful for paletted and grayscale images). |
| 271 if (bitDepth < 8) { | 271 if (bitDepth < 8) { |
| 272 png_set_packing(png_ptr); | 272 png_set_packing(png_ptr); |
| 273 } | 273 } |
| 274 #endif | 274 #endif |
| 275 // Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel. | 275 // Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel. |
| 276 if (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8) { | 276 if (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8) { |
| 277 png_set_expand_gray_1_2_4_to_8(png_ptr); | 277 png_set_expand_gray_1_2_4_to_8(png_ptr); |
| 278 } | 278 } |
| 279 | 279 |
| 280 | 280 // Now determine the default SkColorType and SkAlphaType and set required tr ansforms |
| 281 // Now determine the default SkColorType and SkAlphaType. | |
| 282 SkColorType skColorType; | 281 SkColorType skColorType; |
| 283 SkAlphaType skAlphaType; | 282 SkAlphaType skAlphaType; |
| 284 switch (colorType) { | 283 switch (colorType) { |
| 285 case PNG_COLOR_TYPE_PALETTE: | 284 case PNG_COLOR_TYPE_PALETTE: |
| 286 skColorType = kIndex_8_SkColorType; | 285 skColorType = kIndex_8_SkColorType; |
| 287 skAlphaType = has_transparency_in_palette(png_ptr, info_ptr) ? | 286 skAlphaType = has_transparency_in_palette(png_ptr, info_ptr) ? |
| 288 kUnpremul_SkAlphaType : kOpaque_SkAlphaType; | 287 kUnpremul_SkAlphaType : kOpaque_SkAlphaType; |
| 289 break; | 288 break; |
| 289 case PNG_COLOR_TYPE_RGB: | |
| 290 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { | |
|
scroggo
2015/06/30 15:38:38
In other places, we also check to see whether the
emmaleer
2015/06/30 20:13:40
Yes, I think it's important to make that check. I'
| |
| 291 //convert to RGBA with tranparency information in tRNS chunk if it exists | |
| 292 png_set_tRNS_to_alpha(png_ptr); | |
| 293 skAlphaType = kUnpremul_SkAlphaType; | |
| 294 } else { | |
| 295 //convert to RGBA with Opaque Alpha | |
| 296 png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); | |
| 297 skAlphaType = kOpaque_SkAlphaType; | |
| 298 } | |
| 299 skColorType = kRGBA_8888_SkColorType; | |
|
scroggo
2015/06/30 15:38:38
Interesting. I assume you chose RGBA because that
emmaleer
2015/06/30 20:13:40
Changed to N32
| |
| 300 break; | |
| 290 case PNG_COLOR_TYPE_GRAY: | 301 case PNG_COLOR_TYPE_GRAY: |
| 291 if (false) { | 302 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { |
| 292 // FIXME: Is this the wrong default behavior? This means if the | 303 //convert to RGBA if there is transparency information in the tR NS chunk |
|
scroggo
2015/06/30 15:38:37
Maybe this should be a FIXME; if we supported gray
emmaleer
2015/06/30 20:13:41
Acknowledged.
| |
| 293 // caller supplies the info we gave them, they'll get Alpha 8. | 304 png_set_tRNS_to_alpha(png_ptr); |
| 294 skColorType = kAlpha_8_SkColorType; | 305 png_set_gray_to_rgb(png_ptr); |
| 295 // FIXME: Strangely, the canonical type for Alpha 8 is Premul. | 306 skColorType = kRGBA_8888_SkColorType; |
| 296 skAlphaType = kPremul_SkAlphaType; | 307 skAlphaType = kUnpremul_SkAlphaType; |
| 297 } else { | 308 } else { |
| 298 skColorType = kN32_SkColorType; | 309 skColorType = kGray_8_SkColorType; |
| 299 skAlphaType = kOpaque_SkAlphaType; | 310 skAlphaType = kOpaque_SkAlphaType; |
| 300 } | 311 } |
| 301 break; | 312 break; |
| 313 case PNG_COLOR_TYPE_GRAY_ALPHA: | |
| 314 //convert to RGBA as GreyAlpha is not a Skia color type | |
|
scroggo
2015/06/30 15:38:37
Maybe add a similar FIXME here.
(Also nit: I don'
emmaleer
2015/06/30 20:13:41
Acknowledged.
| |
| 315 png_set_gray_to_rgb(png_ptr); | |
|
scroggo
2015/06/30 15:38:38
Do we need to also call png_set_tRNS_to_alpha here
emmaleer
2015/06/30 20:13:41
No, as PNG_COLOR_TYPE_GRAY_ALPHA has an alpha chan
| |
| 316 skColorType = kRGBA_8888_SkColorType; | |
| 317 skAlphaType = kUnpremul_SkAlphaType; | |
| 318 break; | |
| 302 default: | 319 default: |
| 303 // Note: This *almost* mimics the code in SkImageDecoder_libpng. | 320 //colorType = PNG_COLOR_TYPE_RGBA |
|
scroggo
2015/06/30 15:38:37
Is this the only colorType left? (If so, I think i
emmaleer
2015/06/30 20:13:41
Yes, this is the last color type. Okay, I have don
| |
| 304 // has_transparency_in_palette makes an additional check - whether | 321 skColorType = kRGBA_8888_SkColorType; |
| 305 // numTrans is greater than 0. Why does the other code not make that | 322 skAlphaType = kUnpremul_SkAlphaType; |
| 306 // check? | |
| 307 if (has_transparency_in_palette(png_ptr, info_ptr) | |
| 308 || PNG_COLOR_TYPE_RGB_ALPHA == colorType | |
| 309 || PNG_COLOR_TYPE_GRAY_ALPHA == colorType) | |
| 310 { | |
| 311 skAlphaType = kUnpremul_SkAlphaType; | |
| 312 } else { | |
| 313 skAlphaType = kOpaque_SkAlphaType; | |
| 314 } | |
| 315 skColorType = kN32_SkColorType; | |
| 316 break; | 323 break; |
| 317 } | 324 } |
| 318 | 325 |
| 319 { | |
| 320 // FIXME: Again, this block needs to go into onGetPixels. | |
| 321 bool convertGrayToRGB = PNG_COLOR_TYPE_GRAY == colorType && skColorType != kAlpha_8_SkColorType; | |
| 322 | |
| 323 // Unless the user is requesting A8, convert a grayscale image into RGB. | |
| 324 // GRAY_ALPHA will always be converted to RGB | |
| 325 if (convertGrayToRGB || colorType == PNG_COLOR_TYPE_GRAY_ALPHA) { | |
| 326 png_set_gray_to_rgb(png_ptr); | |
| 327 } | |
| 328 | |
| 329 // Add filler (or alpha) byte (after each RGB triplet) if necessary. | |
| 330 // FIXME: It seems like we could just use RGB as the SrcConfig here. | |
| 331 if (colorType == PNG_COLOR_TYPE_RGB || convertGrayToRGB) { | |
| 332 png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); | |
| 333 } | |
| 334 } | |
| 335 | |
| 336 // FIXME: Also need to check for sRGB (skbug.com/3471). | 326 // FIXME: Also need to check for sRGB (skbug.com/3471). |
| 337 | 327 |
| 338 if (imageInfo) { | 328 if (imageInfo) { |
| 339 *imageInfo = SkImageInfo::Make(origWidth, origHeight, skColorType, | 329 *imageInfo = SkImageInfo::Make(origWidth, origHeight, skColorType, skAlp haType); |
| 340 skAlphaType); | |
| 341 } | 330 } |
| 342 autoClean.detach(); | 331 autoClean.detach(); |
| 343 if (png_ptrp) { | 332 if (png_ptrp) { |
| 344 *png_ptrp = png_ptr; | 333 *png_ptrp = png_ptr; |
| 345 } | 334 } |
| 346 if (info_ptrp) { | 335 if (info_ptrp) { |
| 347 *info_ptrp = info_ptr; | 336 *info_ptrp = info_ptr; |
| 348 } | 337 } |
| 349 return true; | 338 return true; |
| 350 } | 339 } |
| 351 | 340 |
| 352 SkCodec* SkPngCodec::NewFromStream(SkStream* stream) { | 341 SkCodec* SkPngCodec::NewFromStream(SkStream* stream) { |
| 353 SkAutoTDelete<SkStream> streamDeleter(stream); | 342 SkAutoTDelete<SkStream> streamDeleter(stream); |
| 354 png_structp png_ptr; | 343 png_structp png_ptr; |
| 355 png_infop info_ptr; | 344 png_infop info_ptr; |
| 356 SkImageInfo imageInfo; | 345 SkImageInfo imageInfo; |
| 357 if (read_header(stream, &png_ptr, &info_ptr, &imageInfo)) { | 346 int bitDepth; |
| 358 return SkNEW_ARGS(SkPngCodec, (imageInfo, streamDeleter.detach(), png_pt r, info_ptr)); | 347 if (read_header(stream, &png_ptr, &info_ptr, &imageInfo, bitDepth)) { |
|
scroggo
2015/06/30 15:38:38
Since the function takes an int, this does not mod
emmaleer
2015/06/30 20:13:41
Acknowledged.
| |
| 348 return SkNEW_ARGS(SkPngCodec, (imageInfo, streamDeleter.detach(), | |
| 349 png_ptr, info_ptr, bitDepth)); | |
| 359 } | 350 } |
| 360 return NULL; | 351 return NULL; |
| 361 } | 352 } |
| 362 | 353 |
| 363 #define INVALID_NUMBER_PASSES -1 | 354 #define INVALID_NUMBER_PASSES -1 |
| 364 SkPngCodec::SkPngCodec(const SkImageInfo& info, SkStream* stream, | 355 SkPngCodec::SkPngCodec(const SkImageInfo& info, SkStream* stream, |
| 365 png_structp png_ptr, png_infop info_ptr) | 356 png_structp png_ptr, png_infop info_ptr, int bitDepth) |
| 366 : INHERITED(info, stream) | 357 : INHERITED(info, stream) |
| 367 , fPng_ptr(png_ptr) | 358 , fPng_ptr(png_ptr) |
| 368 , fInfo_ptr(info_ptr) | 359 , fInfo_ptr(info_ptr) |
| 369 , fSrcConfig(SkSwizzler::kUnknown) | 360 , fSrcConfig(SkSwizzler::kUnknown) |
| 370 , fNumberPasses(INVALID_NUMBER_PASSES) | 361 , fNumberPasses(INVALID_NUMBER_PASSES) |
| 371 , fReallyHasAlpha(false) | 362 , fReallyHasAlpha(false) |
| 363 , fBitDepth(bitDepth) | |
| 372 {} | 364 {} |
| 373 | 365 |
| 374 SkPngCodec::~SkPngCodec() { | 366 SkPngCodec::~SkPngCodec() { |
| 375 this->destroyReadStruct(); | 367 this->destroyReadStruct(); |
| 376 } | 368 } |
| 377 | 369 |
| 378 void SkPngCodec::destroyReadStruct() { | 370 void SkPngCodec::destroyReadStruct() { |
| 379 if (fPng_ptr) { | 371 if (fPng_ptr) { |
| 380 // We will never have a NULL fInfo_ptr with a non-NULL fPng_ptr | 372 // We will never have a NULL fInfo_ptr with a non-NULL fPng_ptr |
| 381 SkASSERT(fInfo_ptr); | 373 SkASSERT(fInfo_ptr); |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 406 switch (dst.alphaType()) { | 398 switch (dst.alphaType()) { |
| 407 case kPremul_SkAlphaType: | 399 case kPremul_SkAlphaType: |
| 408 case kUnpremul_SkAlphaType: | 400 case kUnpremul_SkAlphaType: |
| 409 // The source is not opaque, so either of these is okay | 401 // The source is not opaque, so either of these is okay |
| 410 break; | 402 break; |
| 411 default: | 403 default: |
| 412 // We cannot decode a non-opaque image to opaque (or unknown) | 404 // We cannot decode a non-opaque image to opaque (or unknown) |
| 413 return false; | 405 return false; |
| 414 } | 406 } |
| 415 } | 407 } |
| 416 | |
| 417 // Check for supported color types | 408 // Check for supported color types |
| 418 switch (dst.colorType()) { | 409 switch (dst.colorType()) { |
| 419 // Allow output to kN32 from any type of input | 410 // Allow output to RGBA from any type of input |
|
reed1
2015/06/30 13:51:01
not sure either of these comments are needed (also
emmaleer
2015/06/30 20:13:40
I removed the unneeded comments
In the enum in SkI
scroggo
2015/06/30 20:50:03
I think Mike's comment about ordering is actually
| |
| 420 case kN32_SkColorType: | 411 case kRGBA_8888_SkColorType: |
| 412 return true; | |
| 413 // Allow output to GBRA from any type of input | |
| 414 case kBGRA_8888_SkColorType: | |
| 421 return true; | 415 return true; |
| 422 default: | 416 default: |
| 423 return dst.colorType() == src.colorType(); | 417 return dst.colorType() == src.colorType(); |
| 424 } | 418 } |
| 425 } | 419 } |
| 426 | 420 |
| 427 SkCodec::Result SkPngCodec::initializeSwizzler(const SkImageInfo& requestedInfo, | 421 SkCodec::Result SkPngCodec::initializeSwizzler(const SkImageInfo& requestedInfo, |
| 428 void* dst, size_t rowBytes, | 422 void* dst, size_t rowBytes, |
| 429 const Options& options, | 423 const Options& options, |
| 430 SkPMColor ctable[], | 424 SkPMColor ctable[], |
| 431 int* ctableCount) { | 425 int* ctableCount) { |
| 432 // FIXME: Could we use the return value of setjmp to specify the type of | 426 // FIXME: Could we use the return value of setjmp to specify the type of |
| 433 // error? | 427 // error? |
| 434 if (setjmp(png_jmpbuf(fPng_ptr))) { | 428 if (setjmp(png_jmpbuf(fPng_ptr))) { |
| 435 SkCodecPrintf("setjmp long jump!\n"); | 429 SkCodecPrintf("setjmp long jump!\n"); |
| 436 return kInvalidInput; | 430 return kInvalidInput; |
| 437 } | 431 } |
| 438 | 432 |
| 439 // FIXME: We already retrieved this information. Store it in SkPngCodec? | |
| 440 png_uint_32 origWidth, origHeight; | |
| 441 int bitDepth, pngColorType, interlaceType; | |
| 442 png_get_IHDR(fPng_ptr, fInfo_ptr, &origWidth, &origHeight, &bitDepth, | |
| 443 &pngColorType, &interlaceType, int_p_NULL, int_p_NULL); | |
| 444 | |
| 445 fNumberPasses = (interlaceType != PNG_INTERLACE_NONE) ? | |
| 446 png_set_interlace_handling(fPng_ptr) : 1; | |
| 447 | |
| 448 // Set to the default before calling decodePalette, which may change it. | 433 // Set to the default before calling decodePalette, which may change it. |
| 449 fReallyHasAlpha = false; | 434 fReallyHasAlpha = false; |
| 450 if (PNG_COLOR_TYPE_PALETTE == pngColorType) { | 435 |
| 451 fSrcConfig = SkSwizzler::kIndex; | 436 //srcColorType was determined in readHeader() which determined png color typ e |
| 452 if (!this->decodePalette(kPremul_SkAlphaType == requestedInfo.alphaType( ), bitDepth, | 437 int srcColorType = this->getInfo().colorType(); |
|
scroggo
2015/06/30 15:38:37
Why do you store these as ints instead of SkColorT
emmaleer
2015/06/30 20:13:40
Changed to const SkColorType
| |
| 453 ctableCount)) { | 438 int dstColorType = requestedInfo.colorType(); |
| 454 return kInvalidInput; | 439 switch (dstColorType) { |
|
scroggo
2015/06/30 15:38:37
nit: this should line up with the line before it.
emmaleer
2015/06/30 20:13:40
I switch on dstColorType, since libpng will conver
| |
| 455 } | 440 case kIndex_8_SkColorType: |
| 456 } else if (kAlpha_8_SkColorType == requestedInfo.colorType()) { | 441 //decode palette to Skia format |
| 457 // Note: we check the destination, since otherwise we would have | 442 fSrcConfig = SkSwizzler::kIndex; |
| 458 // told png to upscale. | 443 if (!this->decodePalette(kPremul_SkAlphaType == requestedInfo.alphaT ype(), fBitDepth, |
| 459 SkASSERT(PNG_COLOR_TYPE_GRAY == pngColorType); | 444 ctableCount)) { |
| 460 fSrcConfig = SkSwizzler::kGray; | 445 return kInvalidInput; |
| 461 } else if (this->getInfo().alphaType() == kOpaque_SkAlphaType) { | 446 } |
| 462 fSrcConfig = SkSwizzler::kRGBX; | 447 break; |
| 463 } else { | 448 case kGray_8_SkColorType: |
| 464 fSrcConfig = SkSwizzler::kRGBA; | 449 fSrcConfig = SkSwizzler::kGray; |
| 465 } | 450 break; |
| 451 case kRGBA_8888_SkColorType: | |
| 452 if (this->getInfo().alphaType() == kOpaque_SkAlphaType) { | |
| 453 fSrcConfig = SkSwizzler::kRGBX; | |
| 454 } else { | |
| 455 fSrcConfig = SkSwizzler::kRGBA; | |
| 456 } | |
| 457 default: | |
| 458 //dstColorType == kBGRA_8888_SkColorType | |
| 459 if (this->getInfo().alphaType() == kOpaque_SkAlphaType) { | |
| 460 fSrcConfig = SkSwizzler::kBGRX; | |
| 461 } else { | |
| 462 fSrcConfig = SkSwizzler::kBGRA; | |
| 463 } | |
| 464 } | |
| 466 | 465 |
| 467 // Copy the color table to the client if they request kIndex8 mode | 466 // Copy the color table to the client if they request kIndex8 mode |
| 468 copy_color_table(requestedInfo, fColorTable, ctable, ctableCount); | 467 copy_color_table(requestedInfo, fColorTable, ctable, ctableCount); |
| 469 | 468 |
| 470 // Create the swizzler. SkPngCodec retains ownership of the color table. | 469 // Create the swizzler. SkPngCodec retains ownership of the color table. |
| 471 const SkPMColor* colors = fColorTable ? fColorTable->readColors() : NULL; | 470 const SkPMColor* colors = fColorTable ? fColorTable->readColors() : NULL; |
| 472 fSwizzler.reset(SkSwizzler::CreateSwizzler(fSrcConfig, colors, requestedInfo , | 471 fSwizzler.reset(SkSwizzler::CreateSwizzler(fSrcConfig, colors, requestedInfo , |
| 473 dst, rowBytes, options.fZeroInitialized)); | 472 dst, rowBytes, options.fZeroInitialized)); |
| 474 if (!fSwizzler) { | 473 if (!fSwizzler) { |
| 475 // FIXME: CreateSwizzler could fail for another reason. | 474 // FIXME: CreateSwizzler could fail for another reason. |
| 476 return kUnimplemented; | 475 return kUnimplemented; |
| 477 } | 476 } |
| 478 | 477 |
| 479 // FIXME: Here is where we should likely insert some of the modifications | 478 // FIXME: Here is where we should likely insert some of the modifications |
|
scroggo
2015/06/30 15:38:37
I think this FIXME has been resolved?
emmaleer
2015/06/30 20:13:41
Acknowledged.
| |
| 480 // made in the factory. | 479 // made in the factory. |
| 481 png_read_update_info(fPng_ptr, fInfo_ptr); | |
| 482 | 480 |
| 483 return kSuccess; | 481 return kSuccess; |
| 484 } | 482 } |
| 485 | 483 |
| 486 bool SkPngCodec::handleRewind() { | 484 SkCodec::Result SkPngCodec::setDataFormat(const SkImageInfo& requestedInfo) { |
| 485 if (setjmp(png_jmpbuf(fPng_ptr))) { | |
| 486 SkCodecPrintf("setjmp long jump!\n"); | |
|
scroggo
2015/06/30 15:38:37
I know this is the same message that is printed el
emmaleer
2015/06/30 20:13:41
Acknowledged.
| |
| 487 return kInvalidInput; | |
| 488 } | |
| 489 | |
| 490 fNumberPasses = png_set_interlace_handling(fPng_ptr); | |
| 491 | |
| 492 //srcColorType was determined in readHeader() which determined png color ty pe | |
| 493 int srcColorType = this->getInfo().colorType(); | |
|
scroggo
2015/06/30 15:38:37
Again, I think these should be SkColorType instead
emmaleer
2015/06/30 20:13:40
Acknowledged.
| |
| 494 int dstColorType = requestedInfo.colorType(); | |
| 495 if (kRGBA_8888_SkColorType == dstColorType || kBGRA_8888_SkColorType == dstC olorType) { | |
| 496 //dstColorType either equals kRGBA_8888_SkColorType or kBGRA_8888_Sk ColorType | |
|
scroggo
2015/06/30 15:38:37
This seems to just add nothing new to the line abo
emmaleer
2015/06/30 20:13:41
Acknowledged.
| |
| 497 if (kIndex_8_SkColorType == srcColorType) { | |
|
scroggo
2015/06/30 15:38:37
nit: This should only be indented 4 spaces from th
emmaleer
2015/06/30 20:13:41
Acknowledged.
| |
| 498 //convert paletted images to RGBA | |
| 499 png_set_palette_to_rgb(fPng_ptr); | |
| 500 if (png_get_valid(fPng_ptr, fInfo_ptr, PNG_INFO_tRNS)) { | |
| 501 png_set_tRNS_to_alpha(fPng_ptr); | |
| 502 } else { | |
| 503 png_set_filler(fPng_ptr, 0xff, PNG_FILLER_AFTER); | |
| 504 } | |
| 505 } else if (kGray_8_SkColorType == srcColorType) { | |
| 506 //convert from Gray to RGBA (need to add filler for alpha as gra y has no alpha) | |
| 507 png_set_gray_to_rgb(fPng_ptr); | |
| 508 png_set_filler(fPng_ptr, 0xff, PNG_FILLER_AFTER); | |
| 509 } | |
| 510 if (kBGRA_8888_SkColorType == dstColorType) { | |
| 511 //convert RGBA to BGRA | |
| 512 png_set_bgr(fPng_ptr); | |
| 513 } | |
| 514 } | |
| 515 png_read_update_info(fPng_ptr, fInfo_ptr); | |
| 516 return kSuccess; | |
| 517 } | |
| 518 | |
| 519 bool SkPngCodec::handleRewind(const SkImageInfo& requestedInfo) { | |
| 487 switch (this->rewindIfNeeded()) { | 520 switch (this->rewindIfNeeded()) { |
| 488 case kNoRewindNecessary_RewindState: | 521 case kNoRewindNecessary_RewindState: |
| 522 //set transforms needed for requestedInfo format | |
| 523 if (kSuccess != setDataFormat(requestedInfo)) { | |
|
scroggo
2015/06/30 15:38:38
nit: this->setDataFormat
emmaleer
2015/06/30 20:13:40
Acknowledged.
| |
| 524 return false; | |
|
scroggo
2015/06/30 15:38:37
Interestingly, we've changed the nature of the err
emmaleer
2015/06/30 20:13:40
I think it's important to return the correct resul
| |
| 525 } | |
| 489 return true; | 526 return true; |
| 490 case kCouldNotRewind_RewindState: | 527 case kCouldNotRewind_RewindState: |
| 491 return false; | 528 return false; |
| 492 case kRewound_RewindState: { | 529 case kRewound_RewindState: { |
| 493 // This sets fPng_ptr and fInfo_ptr to NULL. If read_header | 530 // This sets fPng_ptr and fInfo_ptr to NULL. If read_header |
| 494 // succeeds, they will be repopulated, and if it fails, they will | 531 // succeeds, they will be repopulated, and if it fails, they will |
| 495 // remain NULL. Any future accesses to fPng_ptr and fInfo_ptr will | 532 // remain NULL. Any future accesses to fPng_ptr and fInfo_ptr will |
| 496 // come through this function which will rewind and again attempt | 533 // come through this function which will rewind and again attempt |
| 497 // to reinitialize them. | 534 // to reinitialize them. |
| 498 this->destroyReadStruct(); | 535 this->destroyReadStruct(); |
| 499 png_structp png_ptr; | 536 png_structp png_ptr; |
| 500 png_infop info_ptr; | 537 png_infop info_ptr; |
| 501 if (read_header(this->stream(), &png_ptr, &info_ptr, NULL)) { | 538 if (read_header(this->stream(), &png_ptr, &info_ptr, NULL, NULL)) { |
| 502 fPng_ptr = png_ptr; | 539 fPng_ptr = png_ptr; |
| 503 fInfo_ptr = info_ptr; | 540 fInfo_ptr = info_ptr; |
| 541 //set transforms needed for requestedInfo format | |
| 542 if (kSuccess != setDataFormat(requestedInfo)) { | |
|
scroggo
2015/06/30 15:38:37
this->setDataFormat
emmaleer
2015/06/30 20:13:40
Acknowledged.
| |
| 543 return false; | |
| 544 } | |
| 504 return true; | 545 return true; |
| 505 } | 546 } |
| 506 return false; | 547 return false; |
| 507 } | 548 } |
| 508 default: | 549 default: |
| 509 SkASSERT(false); | 550 SkASSERT(false); |
| 510 return false; | 551 return false; |
| 511 } | 552 } |
| 512 } | 553 } |
| 513 | 554 |
| 514 SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void* dst, | 555 SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void* dst, |
| 515 size_t rowBytes, const Options& options, | 556 size_t rowBytes, const Options& options, |
| 516 SkPMColor ctable[], int* ctableCount) { | 557 SkPMColor ctable[], int* ctableCount) { |
| 517 if (!this->handleRewind()) { | 558 if (!this->handleRewind(requestedInfo)) { |
|
scroggo
2015/06/30 15:38:38
I notice that setDataFormat never cares if it sees
emmaleer
2015/06/30 20:13:41
I changed it so that conversion_possible is called
| |
| 518 return kCouldNotRewind; | 559 return kCouldNotRewind; |
| 519 } | 560 } |
| 520 if (requestedInfo.dimensions() != this->getInfo().dimensions()) { | 561 if (requestedInfo.dimensions() != this->getInfo().dimensions()) { |
| 521 return kInvalidScale; | 562 return kInvalidScale; |
| 522 } | 563 } |
| 523 if (!conversion_possible(requestedInfo, this->getInfo())) { | 564 if (!conversion_possible(requestedInfo, this->getInfo())) { |
| 524 return kInvalidConversion; | 565 return kInvalidConversion; |
| 525 } | 566 } |
| 526 | 567 |
| 527 // Note that ctable and ctableCount may be modified if there is a color tabl e | 568 // Note that ctable and ctableCount may be modified if there is a color tabl e |
| 528 const Result result = this->initializeSwizzler(requestedInfo, dst, rowBytes, | 569 const Result result = this->initializeSwizzler(requestedInfo, dst, rowBytes, |
| 529 options, ctable, ctableCount) ; | 570 options, ctable, ctableCount) ; |
| 530 | |
| 531 if (result != kSuccess) { | 571 if (result != kSuccess) { |
| 532 return result; | 572 return result; |
| 533 } | 573 } |
| 534 | 574 |
|
scroggo
2015/06/30 15:38:38
It looks like you added some whitespace?
emmaleer
2015/06/30 20:13:41
Acknowledged.
| |
| 535 // FIXME: Could we use the return value of setjmp to specify the type of | 575 // FIXME: Could we use the return value of setjmp to specify the type of |
| 536 // error? | 576 // error? |
| 537 if (setjmp(png_jmpbuf(fPng_ptr))) { | 577 if (setjmp(png_jmpbuf(fPng_ptr))) { |
| 538 SkCodecPrintf("setjmp long jump!\n"); | 578 SkCodecPrintf("setjmp long jump!\n"); |
| 539 return kInvalidInput; | 579 return kInvalidInput; |
| 540 } | 580 } |
| 541 | 581 |
| 542 SkASSERT(fNumberPasses != INVALID_NUMBER_PASSES); | 582 SkASSERT(fNumberPasses != INVALID_NUMBER_PASSES); |
| 543 SkAutoMalloc storage; | 583 SkAutoMalloc storage; |
| 544 if (fNumberPasses > 1) { | 584 if (fNumberPasses > 1) { |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 590 /* read rest of file, and get additional chunks in info_ptr - REQUIRED */ | 630 /* read rest of file, and get additional chunks in info_ptr - REQUIRED */ |
| 591 png_read_end(fPng_ptr, fInfo_ptr); | 631 png_read_end(fPng_ptr, fInfo_ptr); |
| 592 } | 632 } |
| 593 | 633 |
| 594 class SkPngScanlineDecoder : public SkScanlineDecoder { | 634 class SkPngScanlineDecoder : public SkScanlineDecoder { |
| 595 public: | 635 public: |
| 596 SkPngScanlineDecoder(const SkImageInfo& dstInfo, SkPngCodec* codec) | 636 SkPngScanlineDecoder(const SkImageInfo& dstInfo, SkPngCodec* codec) |
| 597 : INHERITED(dstInfo) | 637 : INHERITED(dstInfo) |
| 598 , fCodec(codec) | 638 , fCodec(codec) |
| 599 , fHasAlpha(false) | 639 , fHasAlpha(false) |
| 640 , fSrcRowBytes(dstInfo.minRowBytes()) | |
|
scroggo
2015/06/30 15:38:37
Why do we need to store this? It seems like we onl
emmaleer
2015/06/30 20:13:40
I removed this
| |
| 600 { | 641 { |
| 601 fStorage.reset(dstInfo.width() * SkSwizzler::BytesPerPixel(fCodec->fSrcC onfig)); | 642 fStorage.reset(dstInfo.width() * fSrcRowBytes); |
|
scroggo
2015/06/30 15:38:37
I don't think this is what you want. minRowBytes()
emmaleer
2015/06/30 20:13:41
Yes, this is wrong. I changed this back to using
| |
| 602 fSrcRow = static_cast<uint8_t*>(fStorage.get()); | 643 fSrcRow = static_cast<uint8_t*>(fStorage.get()); |
| 603 } | 644 } |
| 604 | 645 |
| 605 SkImageGenerator::Result onGetScanlines(void* dst, int count, size_t rowByte s) override { | 646 SkImageGenerator::Result onGetScanlines(void* dst, int count, size_t rowByte s) override { |
| 606 if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) { | 647 if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) { |
| 607 SkCodecPrintf("setjmp long jump!\n"); | 648 SkCodecPrintf("setjmp long jump!\n"); |
| 608 return SkImageGenerator::kInvalidInput; | 649 return SkImageGenerator::kInvalidInput; |
| 609 } | 650 } |
| 610 | 651 |
| 611 for (int i = 0; i < count; i++) { | 652 for (int i = 0; i < count; i++) { |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 637 fCodec->finish(); | 678 fCodec->finish(); |
| 638 } | 679 } |
| 639 | 680 |
| 640 bool onReallyHasAlpha() const override { return fHasAlpha; } | 681 bool onReallyHasAlpha() const override { return fHasAlpha; } |
| 641 | 682 |
| 642 private: | 683 private: |
| 643 SkPngCodec* fCodec; // Unowned. | 684 SkPngCodec* fCodec; // Unowned. |
| 644 bool fHasAlpha; | 685 bool fHasAlpha; |
| 645 SkAutoMalloc fStorage; | 686 SkAutoMalloc fStorage; |
| 646 uint8_t* fSrcRow; | 687 uint8_t* fSrcRow; |
| 688 size_t fSrcRowBytes; | |
| 647 | 689 |
| 648 typedef SkScanlineDecoder INHERITED; | 690 typedef SkScanlineDecoder INHERITED; |
| 649 }; | 691 }; |
| 650 | 692 |
| 651 | 693 |
| 652 class SkPngInterlacedScanlineDecoder : public SkScanlineDecoder { | 694 class SkPngInterlacedScanlineDecoder : public SkScanlineDecoder { |
| 653 public: | 695 public: |
| 654 SkPngInterlacedScanlineDecoder(const SkImageInfo& dstInfo, SkPngCodec* codec ) | 696 SkPngInterlacedScanlineDecoder(const SkImageInfo& dstInfo, SkPngCodec* codec ) |
| 655 : INHERITED(dstInfo) | 697 : INHERITED(dstInfo) |
| 656 , fCodec(codec) | 698 , fCodec(codec) |
| 657 , fHasAlpha(false) | 699 , fHasAlpha(false) |
| 658 , fCurrentRow(0) | 700 , fCurrentRow(0) |
| 659 , fHeight(dstInfo.height()) | 701 , fHeight(dstInfo.height()) |
| 660 , fSrcRowBytes(dstInfo.minRowBytes()) | 702 , fSrcRowBytes(dstInfo.minRowBytes()) |
| 661 , fRewindNeeded(false) | 703 , fRewindNeeded(false) |
| 704 , fDstInfo(dstInfo) | |
| 662 { | 705 { |
| 663 fGarbageRow.reset(fSrcRowBytes); | 706 fGarbageRow.reset(fSrcRowBytes); |
| 664 fGarbageRowPtr = static_cast<uint8_t*>(fGarbageRow.get()); | 707 fGarbageRowPtr = static_cast<uint8_t*>(fGarbageRow.get()); |
| 665 } | 708 } |
| 666 | 709 |
| 667 SkImageGenerator::Result onGetScanlines(void* dst, int count, size_t dstRowB ytes) override { | 710 SkImageGenerator::Result onGetScanlines(void* dst, int count, size_t dstRowByte s) override { |
|
scroggo
2015/06/30 15:38:38
This should be indented 4 spaces.
emmaleer
2015/06/30 20:13:41
Acknowledged.
| |
| 668 //rewind stream if have previously called onGetScanlines, | 711 //rewind stream if have previously called onGetScanlines, |
| 669 //since we need entire progressive image to get scanlines | 712 //since we need entire progressive image to get scanlines |
| 713 //need to reset transforms in setDataFormat if stream is rewound | |
| 670 if (fRewindNeeded) { | 714 if (fRewindNeeded) { |
| 671 if(false == fCodec->handleRewind()) { | 715 if(false == fCodec->handleRewind(fDstInfo)) { |
|
scroggo
2015/06/30 15:38:38
Alternatively, you could use this->dstInfo(), whic
emmaleer
2015/06/30 20:13:41
Acknowledged.
| |
| 672 return SkImageGenerator::kCouldNotRewind; | 716 return SkImageGenerator::kCouldNotRewind; |
| 673 } | 717 } |
| 674 } else { | 718 } else { |
| 675 fRewindNeeded = true; | 719 fRewindNeeded = true; |
| 676 } | 720 } |
| 677 if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) { | 721 if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) { |
| 678 SkCodecPrintf("setjmp long jump!\n"); | 722 SkCodecPrintf("setjmp long jump!\n"); |
| 679 return SkImageGenerator::kInvalidInput; | 723 return SkImageGenerator::kInvalidInput; |
| 680 } | 724 } |
| 681 const int number_passes = png_set_interlace_handling(fCodec->fPng_ptr); | 725 const int number_passes = png_set_interlace_handling(fCodec->fPng_ptr); |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 703 for (int y = 0; y < count; y++) { | 747 for (int y = 0; y < count; y++) { |
| 704 fCodec->fSwizzler->setDstRow(dst); | 748 fCodec->fSwizzler->setDstRow(dst); |
| 705 fHasAlpha |= !SkSwizzler::IsOpaque(fCodec->fSwizzler->next(srcRow)); | 749 fHasAlpha |= !SkSwizzler::IsOpaque(fCodec->fSwizzler->next(srcRow)); |
| 706 dst = SkTAddOffset<void>(dst, dstRowBytes); | 750 dst = SkTAddOffset<void>(dst, dstRowBytes); |
| 707 srcRow += fSrcRowBytes; | 751 srcRow += fSrcRowBytes; |
| 708 } | 752 } |
| 709 fCurrentRow += count; | 753 fCurrentRow += count; |
| 710 return SkImageGenerator::kSuccess; | 754 return SkImageGenerator::kSuccess; |
| 711 } | 755 } |
| 712 | 756 |
| 713 SkImageGenerator::Result onSkipScanlines(int count) override { | 757 SkImageGenerator::Result onSkipScanlines(int count) override { |
|
scroggo
2015/06/30 15:38:37
More added whitespace?
| |
| 714 //when ongetScanlines is called it will skip to fCurrentRow | 758 //when ongetScanlines is called it will skip to fCurrentRow |
| 715 fCurrentRow += count; | 759 fCurrentRow += count; |
| 716 return SkImageGenerator::kSuccess; | 760 return SkImageGenerator::kSuccess; |
| 717 } | 761 } |
| 718 | 762 |
| 719 void onFinish() override { | 763 void onFinish() override { |
| 720 fCodec->finish(); | 764 fCodec->finish(); |
| 721 } | 765 } |
| 722 | 766 |
| 723 bool onReallyHasAlpha() const override { return fHasAlpha; } | 767 bool onReallyHasAlpha() const override { return fHasAlpha; } |
| 724 | 768 |
| 725 private: | 769 private: |
| 726 SkPngCodec* fCodec; // Unowned. | 770 SkPngCodec* fCodec; // Unowned. |
| 727 bool fHasAlpha; | 771 bool fHasAlpha; |
| 728 int fCurrentRow; | 772 int fCurrentRow; |
| 729 int fHeight; | 773 int fHeight; |
| 730 size_t fSrcRowBytes; | 774 size_t fSrcRowBytes; |
| 731 bool fRewindNeeded; | 775 bool fRewindNeeded; |
| 732 SkAutoMalloc fGarbageRow; | 776 SkAutoMalloc fGarbageRow; |
| 733 uint8_t* fGarbageRowPtr; | 777 uint8_t* fGarbageRowPtr; |
| 734 | 778 const SkImageInfo& fDstInfo; |
| 735 | |
| 736 | |
| 737 | |
| 738 | |
| 739 typedef SkScanlineDecoder INHERITED; | 779 typedef SkScanlineDecoder INHERITED; |
| 740 }; | 780 }; |
| 741 | 781 |
| 742 | 782 |
| 743 SkScanlineDecoder* SkPngCodec::onGetScanlineDecoder(const SkImageInfo& dstInfo, | 783 SkScanlineDecoder* SkPngCodec::onGetScanlineDecoder(const SkImageInfo& dstInfo, |
| 744 const Options& options, SkPMColor ctable[], int* ctableCount) { | 784 const Options& options, SkPMColor ctable[], int* ctableCount) { |
| 745 if (!this->handleRewind()) { | 785 if (!this->handleRewind(dstInfo)) { |
| 746 return NULL; | 786 return NULL; |
| 747 } | 787 } |
| 748 | 788 |
| 749 // Check to see if scaling was requested. | 789 // Check to see if scaling was requested. |
| 750 if (dstInfo.dimensions() != this->getInfo().dimensions()) { | 790 if (dstInfo.dimensions() != this->getInfo().dimensions()) { |
| 751 return NULL; | 791 return NULL; |
| 752 } | 792 } |
| 753 | 793 |
| 754 if (!conversion_possible(dstInfo, this->getInfo())) { | 794 if (!conversion_possible(dstInfo, this->getInfo())) { |
| 755 SkCodecPrintf("no conversion possible\n"); | 795 SkCodecPrintf("no conversion possible\n"); |
| 756 return NULL; | 796 return NULL; |
| 757 } | 797 } |
| 758 | 798 |
| 759 // Note: We set dst to NULL since we do not know it yet. rowBytes is not nee ded, | 799 // Note: We set dst to NULL since we do not know it yet. rowBytes is not need ed, |
|
scroggo
2015/06/30 15:38:37
nit: 4 space indent.
emmaleer
2015/06/30 20:13:41
Acknowledged.
| |
| 760 // since we'll be manually updating the dstRow, but the SkSwizzler requires it to | 800 // since we'll be manually updating the dstRow, but the SkSwizzler requires it to |
| 761 // be at least dstInfo.minRowBytes. | 801 // be at least dstInfo.minRowBytes. |
| 762 if (this->initializeSwizzler(dstInfo, NULL, dstInfo.minRowBytes(), options, ctable, | 802 if (this->initializeSwizzler(dstInfo, NULL, dstInfo.minRowBytes(), options, ctable, |
| 763 ctableCount) != kSuccess) { | 803 ctableCount) != kSuccess) { |
| 764 SkCodecPrintf("failed to initialize the swizzler.\n"); | 804 SkCodecPrintf("failed to initialize the swizzler.\n"); |
| 765 return NULL; | 805 return NULL; |
| 766 } | 806 } |
| 767 | 807 |
| 768 SkASSERT(fNumberPasses != INVALID_NUMBER_PASSES); | 808 SkASSERT(fNumberPasses != INVALID_NUMBER_PASSES); |
| 769 if (fNumberPasses > 1) { | 809 if (fNumberPasses > 1) { |
| 770 // interlaced image | 810 // interlaced image |
| 771 return SkNEW_ARGS(SkPngInterlacedScanlineDecoder, (dstInfo, this)); | 811 return SkNEW_ARGS(SkPngInterlacedScanlineDecoder, (dstInfo, this)); |
| 772 } | 812 } |
| 773 | 813 |
| 774 return SkNEW_ARGS(SkPngScanlineDecoder, (dstInfo, this)); | 814 return SkNEW_ARGS(SkPngScanlineDecoder, (dstInfo, this)); |
| 775 } | 815 } |
| 776 | 816 |
| OLD | NEW |