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* bitDe pthPtr) { |
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 bitDepth, colorType; |
scroggo
2015/06/30 20:50:03
No need to create this variable (bitDepth). Instea
| |
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 bitDepthPtr = &bitDepth; | |
scroggo
2015/06/30 20:50:03
This is going to do the wrong thing. I believe you
| |
256 | |
255 // sanity check for size | 257 // sanity check for size |
256 { | 258 { |
257 int64_t size = sk_64_mul(origWidth, origHeight); | 259 int64_t size = sk_64_mul(origWidth, origHeight); |
258 // now check that if we are 4-bytes per pixel, we also don't overflow | 260 // now check that if we are 4-bytes per pixel, we also don't overflow |
259 if (size < 0 || size > (0x7FFFFFFF >> 2)) { | 261 if (size < 0 || size > (0x7FFFFFFF >> 2)) { |
260 return false; | 262 return false; |
261 } | 263 } |
262 } | 264 } |
263 | 265 |
264 // Tell libpng to strip 16 bit/color files down to 8 bits/color | 266 // Tell libpng to strip 16 bit/color files down to 8 bits/color |
265 if (bitDepth == 16) { | 267 if (bitDepth == 16) { |
266 png_set_strip_16(png_ptr); | 268 png_set_strip_16(png_ptr); |
267 } | 269 } |
268 #ifdef PNG_READ_PACK_SUPPORTED | 270 #ifdef PNG_READ_PACK_SUPPORTED |
269 // Extract multiple pixels with bit depths of 1, 2, and 4 from a single | 271 // 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). | 272 // byte into separate bytes (useful for paletted and grayscale images). |
271 if (bitDepth < 8) { | 273 if (bitDepth < 8) { |
272 png_set_packing(png_ptr); | 274 png_set_packing(png_ptr); |
273 } | 275 } |
274 #endif | 276 #endif |
275 // Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel. | 277 // Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel. |
276 if (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8) { | 278 if (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8) { |
277 png_set_expand_gray_1_2_4_to_8(png_ptr); | 279 png_set_expand_gray_1_2_4_to_8(png_ptr); |
278 } | 280 } |
279 | 281 |
280 | 282 // Now determine the default SkColorType and SkAlphaType and set required tr ansforms |
281 // Now determine the default SkColorType and SkAlphaType. | |
282 SkColorType skColorType; | 283 SkColorType skColorType; |
283 SkAlphaType skAlphaType; | 284 SkAlphaType skAlphaType; |
284 switch (colorType) { | 285 switch (colorType) { |
285 case PNG_COLOR_TYPE_PALETTE: | 286 case PNG_COLOR_TYPE_PALETTE: |
286 skColorType = kIndex_8_SkColorType; | 287 skColorType = kIndex_8_SkColorType; |
287 skAlphaType = has_transparency_in_palette(png_ptr, info_ptr) ? | 288 skAlphaType = has_transparency_in_palette(png_ptr, info_ptr) ? |
288 kUnpremul_SkAlphaType : kOpaque_SkAlphaType; | 289 kUnpremul_SkAlphaType : kOpaque_SkAlphaType; |
289 break; | 290 break; |
290 case PNG_COLOR_TYPE_GRAY: | 291 case PNG_COLOR_TYPE_RGB: |
291 if (false) { | 292 if (has_transparency_in_palette(png_ptr, info_ptr)) { |
292 // FIXME: Is this the wrong default behavior? This means if the | 293 //convert to RGBA with tranparency information in tRNS chunk if it exists |
293 // caller supplies the info we gave them, they'll get Alpha 8. | 294 png_set_tRNS_to_alpha(png_ptr); |
294 skColorType = kAlpha_8_SkColorType; | |
295 // FIXME: Strangely, the canonical type for Alpha 8 is Premul. | |
296 skAlphaType = kPremul_SkAlphaType; | |
297 } else { | |
298 skColorType = kN32_SkColorType; | |
299 skAlphaType = kOpaque_SkAlphaType; | |
300 } | |
301 break; | |
302 default: | |
303 // Note: This *almost* mimics the code in SkImageDecoder_libpng. | |
304 // has_transparency_in_palette makes an additional check - whether | |
305 // numTrans is greater than 0. Why does the other code not make that | |
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; | 295 skAlphaType = kUnpremul_SkAlphaType; |
312 } else { | 296 } else { |
297 //convert to RGBA with Opaque Alpha | |
298 png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); | |
313 skAlphaType = kOpaque_SkAlphaType; | 299 skAlphaType = kOpaque_SkAlphaType; |
314 } | 300 } |
315 skColorType = kN32_SkColorType; | 301 skColorType = kN32_SkColorType; |
316 break; | 302 break; |
317 } | 303 case PNG_COLOR_TYPE_GRAY: |
318 | 304 if (has_transparency_in_palette(png_ptr, info_ptr)) { |
319 { | 305 //FIXME: support gray with alpha as a color type |
320 // FIXME: Again, this block needs to go into onGetPixels. | 306 //convert to RGBA if there is transparentcy info in the tRNS chu nk |
321 bool convertGrayToRGB = PNG_COLOR_TYPE_GRAY == colorType && skColorType != kAlpha_8_SkColorType; | 307 png_set_tRNS_to_alpha(png_ptr); |
322 | 308 png_set_gray_to_rgb(png_ptr); |
323 // Unless the user is requesting A8, convert a grayscale image into RGB. | 309 skColorType = kN32_SkColorType; |
324 // GRAY_ALPHA will always be converted to RGB | 310 skAlphaType = kUnpremul_SkAlphaType; |
325 if (convertGrayToRGB || colorType == PNG_COLOR_TYPE_GRAY_ALPHA) { | 311 } else { |
312 skColorType = kGray_8_SkColorType; | |
313 skAlphaType = kOpaque_SkAlphaType; | |
314 } | |
315 break; | |
316 case PNG_COLOR_TYPE_GRAY_ALPHA: | |
317 //FIXME: support gray with alpha as a color type | |
318 //convert to RGBA | |
326 png_set_gray_to_rgb(png_ptr); | 319 png_set_gray_to_rgb(png_ptr); |
327 } | 320 skColorType = kN32_SkColorType; |
328 | 321 skAlphaType = kUnpremul_SkAlphaType; |
329 // Add filler (or alpha) byte (after each RGB triplet) if necessary. | 322 break; |
330 // FIXME: It seems like we could just use RGB as the SrcConfig here. | 323 case PNG_COLOR_TYPE_RGBA: |
331 if (colorType == PNG_COLOR_TYPE_RGB || convertGrayToRGB) { | 324 skColorType = kN32_SkColorType; |
332 png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); | 325 skAlphaType = kUnpremul_SkAlphaType; |
333 } | 326 break; |
327 default: | |
328 //all the color types have been covered above | |
329 SkASSERT(false); | |
334 } | 330 } |
335 | 331 |
336 // FIXME: Also need to check for sRGB (skbug.com/3471). | 332 // FIXME: Also need to check for sRGB (skbug.com/3471). |
337 | 333 |
338 if (imageInfo) { | 334 if (imageInfo) { |
339 *imageInfo = SkImageInfo::Make(origWidth, origHeight, skColorType, | 335 *imageInfo = SkImageInfo::Make(origWidth, origHeight, skColorType, skAlp haType); |
340 skAlphaType); | |
341 } | 336 } |
342 autoClean.detach(); | 337 autoClean.detach(); |
343 if (png_ptrp) { | 338 if (png_ptrp) { |
344 *png_ptrp = png_ptr; | 339 *png_ptrp = png_ptr; |
345 } | 340 } |
346 if (info_ptrp) { | 341 if (info_ptrp) { |
347 *info_ptrp = info_ptr; | 342 *info_ptrp = info_ptr; |
348 } | 343 } |
349 return true; | 344 return true; |
350 } | 345 } |
351 | 346 |
352 SkCodec* SkPngCodec::NewFromStream(SkStream* stream) { | 347 SkCodec* SkPngCodec::NewFromStream(SkStream* stream) { |
353 SkAutoTDelete<SkStream> streamDeleter(stream); | 348 SkAutoTDelete<SkStream> streamDeleter(stream); |
354 png_structp png_ptr; | 349 png_structp png_ptr; |
355 png_infop info_ptr; | 350 png_infop info_ptr; |
356 SkImageInfo imageInfo; | 351 SkImageInfo imageInfo; |
357 if (read_header(stream, &png_ptr, &info_ptr, &imageInfo)) { | 352 int bitDepth; |
358 return SkNEW_ARGS(SkPngCodec, (imageInfo, streamDeleter.detach(), png_pt r, info_ptr)); | 353 if (read_header(stream, &png_ptr, &info_ptr, &imageInfo, &bitDepth)) { |
354 return SkNEW_ARGS(SkPngCodec, (imageInfo, streamDeleter.detach(), | |
355 png_ptr, info_ptr, bitDepth)); | |
359 } | 356 } |
360 return NULL; | 357 return NULL; |
361 } | 358 } |
362 | 359 |
363 #define INVALID_NUMBER_PASSES -1 | 360 #define INVALID_NUMBER_PASSES -1 |
364 SkPngCodec::SkPngCodec(const SkImageInfo& info, SkStream* stream, | 361 SkPngCodec::SkPngCodec(const SkImageInfo& info, SkStream* stream, |
365 png_structp png_ptr, png_infop info_ptr) | 362 png_structp png_ptr, png_infop info_ptr, int bitDepth) |
366 : INHERITED(info, stream) | 363 : INHERITED(info, stream) |
367 , fPng_ptr(png_ptr) | 364 , fPng_ptr(png_ptr) |
368 , fInfo_ptr(info_ptr) | 365 , fInfo_ptr(info_ptr) |
369 , fSrcConfig(SkSwizzler::kUnknown) | 366 , fSrcConfig(SkSwizzler::kUnknown) |
370 , fNumberPasses(INVALID_NUMBER_PASSES) | 367 , fNumberPasses(INVALID_NUMBER_PASSES) |
371 , fReallyHasAlpha(false) | 368 , fReallyHasAlpha(false) |
369 , fBitDepth(bitDepth) | |
372 {} | 370 {} |
373 | 371 |
374 SkPngCodec::~SkPngCodec() { | 372 SkPngCodec::~SkPngCodec() { |
375 this->destroyReadStruct(); | 373 this->destroyReadStruct(); |
376 } | 374 } |
377 | 375 |
378 void SkPngCodec::destroyReadStruct() { | 376 void SkPngCodec::destroyReadStruct() { |
379 if (fPng_ptr) { | 377 if (fPng_ptr) { |
380 // We will never have a NULL fInfo_ptr with a non-NULL fPng_ptr | 378 // We will never have a NULL fInfo_ptr with a non-NULL fPng_ptr |
381 SkASSERT(fInfo_ptr); | 379 SkASSERT(fInfo_ptr); |
(...skipping 24 matching lines...) Expand all Loading... | |
406 switch (dst.alphaType()) { | 404 switch (dst.alphaType()) { |
407 case kPremul_SkAlphaType: | 405 case kPremul_SkAlphaType: |
408 case kUnpremul_SkAlphaType: | 406 case kUnpremul_SkAlphaType: |
409 // The source is not opaque, so either of these is okay | 407 // The source is not opaque, so either of these is okay |
410 break; | 408 break; |
411 default: | 409 default: |
412 // We cannot decode a non-opaque image to opaque (or unknown) | 410 // We cannot decode a non-opaque image to opaque (or unknown) |
413 return false; | 411 return false; |
414 } | 412 } |
415 } | 413 } |
416 | |
417 // Check for supported color types | 414 // Check for supported color types |
418 switch (dst.colorType()) { | 415 switch (dst.colorType()) { |
419 // Allow output to kN32 from any type of input | 416 case kRGBA_8888_SkColorType: |
420 case kN32_SkColorType: | 417 return true; |
418 case kBGRA_8888_SkColorType: | |
421 return true; | 419 return true; |
422 default: | 420 default: |
423 return dst.colorType() == src.colorType(); | 421 return dst.colorType() == src.colorType(); |
424 } | 422 } |
425 } | 423 } |
426 | 424 |
427 SkCodec::Result SkPngCodec::initializeSwizzler(const SkImageInfo& requestedInfo, | 425 SkCodec::Result SkPngCodec::initializeSwizzler(const SkImageInfo& requestedInfo, |
428 void* dst, size_t rowBytes, | 426 void* dst, size_t rowBytes, |
429 const Options& options, | 427 const Options& options, |
430 SkPMColor ctable[], | 428 SkPMColor ctable[], |
431 int* ctableCount) { | 429 int* ctableCount) { |
432 // FIXME: Could we use the return value of setjmp to specify the type of | 430 // FIXME: Could we use the return value of setjmp to specify the type of |
433 // error? | 431 // error? |
434 if (setjmp(png_jmpbuf(fPng_ptr))) { | 432 if (setjmp(png_jmpbuf(fPng_ptr))) { |
435 SkCodecPrintf("setjmp long jump!\n"); | 433 SkCodecPrintf("setjmp long jump!\n"); |
436 return kInvalidInput; | 434 return kInvalidInput; |
437 } | 435 } |
438 | 436 |
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. | 437 // Set to the default before calling decodePalette, which may change it. |
449 fReallyHasAlpha = false; | 438 fReallyHasAlpha = false; |
450 if (PNG_COLOR_TYPE_PALETTE == pngColorType) { | 439 |
451 fSrcConfig = SkSwizzler::kIndex; | 440 //srcColorType was determined in readHeader() which determined png color typ e |
452 if (!this->decodePalette(kPremul_SkAlphaType == requestedInfo.alphaType( ), bitDepth, | 441 const SkColorType srcColorType = this->getInfo().colorType(); |
453 ctableCount)) { | 442 const SkColorType dstColorType = requestedInfo.colorType(); |
454 return kInvalidInput; | 443 //set swizzler fSrcConfig to dstColorType, as libbpng will convert from |
scroggo
2015/06/30 20:50:03
nit: Maybe specify that libpng will do the convers
| |
455 } | 444 //srcColorType to dstColorType. Swizzler still needed for premultiplyin g |
scroggo
2015/06/30 20:50:04
The swizzler is only needed in one case: the clien
| |
456 } else if (kAlpha_8_SkColorType == requestedInfo.colorType()) { | 445 switch (dstColorType) { |
scroggo
2015/06/30 20:50:03
nit: This (and the comments above) should line up
| |
457 // Note: we check the destination, since otherwise we would have | 446 case kIndex_8_SkColorType: |
458 // told png to upscale. | 447 //decode palette to Skia format |
459 SkASSERT(PNG_COLOR_TYPE_GRAY == pngColorType); | 448 fSrcConfig = SkSwizzler::kIndex; |
460 fSrcConfig = SkSwizzler::kGray; | 449 if (!this->decodePalette(kPremul_SkAlphaType == requestedInfo.alphaT ype(), fBitDepth, |
461 } else if (this->getInfo().alphaType() == kOpaque_SkAlphaType) { | 450 ctableCount)) { |
462 fSrcConfig = SkSwizzler::kRGBX; | 451 return kInvalidInput; |
463 } else { | 452 } |
464 fSrcConfig = SkSwizzler::kRGBA; | 453 break; |
465 } | 454 case kGray_8_SkColorType: |
455 fSrcConfig = SkSwizzler::kGray; | |
456 break; | |
457 case kRGBA_8888_SkColorType: | |
458 if (this->getInfo().alphaType() == kOpaque_SkAlphaType) { | |
459 fSrcConfig = SkSwizzler::kRGBX; | |
460 } else { | |
461 fSrcConfig = SkSwizzler::kRGBA; | |
462 } | |
463 default: | |
464 //dstColorType == kBGRA_8888_SkColorType | |
scroggo
2015/06/30 20:50:03
Again, I think it would be better to make this a c
| |
465 if (this->getInfo().alphaType() == kOpaque_SkAlphaType) { | |
466 fSrcConfig = SkSwizzler::kBGRX; | |
467 } else { | |
468 fSrcConfig = SkSwizzler::kBGRA; | |
469 } | |
470 } | |
466 | 471 |
467 // Copy the color table to the client if they request kIndex8 mode | 472 // Copy the color table to the client if they request kIndex8 mode |
468 copy_color_table(requestedInfo, fColorTable, ctable, ctableCount); | 473 copy_color_table(requestedInfo, fColorTable, ctable, ctableCount); |
469 | 474 |
470 // Create the swizzler. SkPngCodec retains ownership of the color table. | 475 // Create the swizzler. SkPngCodec retains ownership of the color table. |
471 const SkPMColor* colors = fColorTable ? fColorTable->readColors() : NULL; | 476 const SkPMColor* colors = fColorTable ? fColorTable->readColors() : NULL; |
472 fSwizzler.reset(SkSwizzler::CreateSwizzler(fSrcConfig, colors, requestedInfo , | 477 fSwizzler.reset(SkSwizzler::CreateSwizzler(fSrcConfig, colors, requestedInfo , |
473 dst, rowBytes, options.fZeroInitialized)); | 478 dst, rowBytes, options.fZeroInitialized)); |
474 if (!fSwizzler) { | 479 if (!fSwizzler) { |
475 // FIXME: CreateSwizzler could fail for another reason. | 480 // FIXME: CreateSwizzler could fail for another reason. |
476 return kUnimplemented; | 481 return kUnimplemented; |
477 } | 482 } |
478 | |
479 // FIXME: Here is where we should likely insert some of the modifications | |
480 // made in the factory. | |
481 png_read_update_info(fPng_ptr, fInfo_ptr); | |
482 | |
483 return kSuccess; | 483 return kSuccess; |
484 } | 484 } |
485 | 485 |
486 bool SkPngCodec::handleRewind() { | 486 SkCodec::Result SkPngCodec::setDataFormat(const SkImageInfo& requestedInfo) { |
487 if (setjmp(png_jmpbuf(fPng_ptr))) { | |
488 SkCodecPrintf("setjmp long jump in SkPngCodec::setDataFormat()\n"); | |
489 return kInvalidInput; | |
490 } | |
491 | |
492 fNumberPasses = png_set_interlace_handling(fPng_ptr); | |
493 | |
494 //srcColorType was determined in readHeader() which determined png color ty pe | |
495 const SkColorType srcColorType = this->getInfo().colorType(); | |
496 const SkColorType dstColorType = requestedInfo.colorType(); | |
497 if (kRGBA_8888_SkColorType == dstColorType || kBGRA_8888_SkColorType == dstC olorType) { | |
498 if (kIndex_8_SkColorType == srcColorType) { | |
499 //convert paletted images to RGBA | |
500 png_set_palette_to_rgb(fPng_ptr); | |
501 if (png_get_valid(fPng_ptr, fInfo_ptr, PNG_INFO_tRNS)) { | |
scroggo
2015/06/30 20:50:03
Should this call has_transparency_in_palette, too?
| |
502 png_set_tRNS_to_alpha(fPng_ptr); | |
503 } else { | |
504 png_set_filler(fPng_ptr, 0xff, PNG_FILLER_AFTER); | |
505 } | |
506 } else if (kGray_8_SkColorType == srcColorType) { | |
507 //convert from Gray to RGBA (need to add filler for alpha as gray ha s no alpha) | |
508 png_set_gray_to_rgb(fPng_ptr); | |
509 png_set_filler(fPng_ptr, 0xff, PNG_FILLER_AFTER); | |
510 } | |
511 if (kBGRA_8888_SkColorType == dstColorType) { | |
512 //convert RGBA to BGRA | |
513 png_set_bgr(fPng_ptr); | |
514 } | |
515 } | |
516 png_read_update_info(fPng_ptr, fInfo_ptr); | |
517 return kSuccess; | |
518 } | |
519 | |
520 bool SkPngCodec::handleRewind(const SkImageInfo& requestedInfo) { | |
487 switch (this->rewindIfNeeded()) { | 521 switch (this->rewindIfNeeded()) { |
488 case kNoRewindNecessary_RewindState: | 522 case kNoRewindNecessary_RewindState: |
523 //set transforms needed for requestedInfo format | |
524 if (kSuccess != this->setDataFormat(requestedInfo)) { | |
525 return false; | |
526 } | |
489 return true; | 527 return true; |
490 case kCouldNotRewind_RewindState: | 528 case kCouldNotRewind_RewindState: |
491 return false; | 529 return false; |
492 case kRewound_RewindState: { | 530 case kRewound_RewindState: { |
493 // This sets fPng_ptr and fInfo_ptr to NULL. If read_header | 531 // This sets fPng_ptr and fInfo_ptr to NULL. If read_header |
494 // succeeds, they will be repopulated, and if it fails, they will | 532 // succeeds, they will be repopulated, and if it fails, they will |
495 // remain NULL. Any future accesses to fPng_ptr and fInfo_ptr will | 533 // remain NULL. Any future accesses to fPng_ptr and fInfo_ptr will |
496 // come through this function which will rewind and again attempt | 534 // come through this function which will rewind and again attempt |
497 // to reinitialize them. | 535 // to reinitialize them. |
498 this->destroyReadStruct(); | 536 this->destroyReadStruct(); |
499 png_structp png_ptr; | 537 png_structp png_ptr; |
500 png_infop info_ptr; | 538 png_infop info_ptr; |
501 if (read_header(this->stream(), &png_ptr, &info_ptr, NULL)) { | 539 if (read_header(this->stream(), &png_ptr, &info_ptr, NULL, NULL)) { |
502 fPng_ptr = png_ptr; | 540 fPng_ptr = png_ptr; |
503 fInfo_ptr = info_ptr; | 541 fInfo_ptr = info_ptr; |
542 //set transforms needed for requestedInfo format | |
543 if (kSuccess != this->setDataFormat(requestedInfo)) { | |
544 return false; | |
545 } | |
504 return true; | 546 return true; |
505 } | 547 } |
506 return false; | 548 return false; |
507 } | 549 } |
508 default: | 550 default: |
509 SkASSERT(false); | 551 SkASSERT(false); |
510 return false; | 552 return false; |
511 } | 553 } |
512 } | 554 } |
513 | 555 |
514 SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void* dst, | 556 SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void* dst, |
515 size_t rowBytes, const Options& options, | 557 size_t rowBytes, const Options& options, |
516 SkPMColor ctable[], int* ctableCount) { | 558 SkPMColor ctable[], int* ctableCount) { |
517 if (!this->handleRewind()) { | 559 if (!conversion_possible(requestedInfo, this->getInfo())) { |
518 return kCouldNotRewind; | 560 return kInvalidConversion; |
519 } | 561 } |
520 if (requestedInfo.dimensions() != this->getInfo().dimensions()) { | 562 if (requestedInfo.dimensions() != this->getInfo().dimensions()) { |
521 return kInvalidScale; | 563 return kInvalidScale; |
522 } | 564 } |
523 if (!conversion_possible(requestedInfo, this->getInfo())) { | 565 if (!this->handleRewind(requestedInfo)) { |
524 return kInvalidConversion; | 566 return kCouldNotRewind; |
525 } | 567 } |
526 | 568 |
527 // Note that ctable and ctableCount may be modified if there is a color tabl e | 569 // Note that ctable and ctableCount may be modified if there is a color tabl e |
528 const Result result = this->initializeSwizzler(requestedInfo, dst, rowBytes, | 570 const Result result = this->initializeSwizzler(requestedInfo, dst, rowBytes, |
529 options, ctable, ctableCount) ; | 571 options, ctable, ctableCount) ; |
530 | |
531 if (result != kSuccess) { | 572 if (result != kSuccess) { |
532 return result; | 573 return result; |
533 } | 574 } |
534 | |
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 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
650 | 690 |
651 | 691 |
652 class SkPngInterlacedScanlineDecoder : public SkScanlineDecoder { | 692 class SkPngInterlacedScanlineDecoder : public SkScanlineDecoder { |
653 public: | 693 public: |
654 SkPngInterlacedScanlineDecoder(const SkImageInfo& dstInfo, SkPngCodec* codec ) | 694 SkPngInterlacedScanlineDecoder(const SkImageInfo& dstInfo, SkPngCodec* codec ) |
655 : INHERITED(dstInfo) | 695 : INHERITED(dstInfo) |
656 , fCodec(codec) | 696 , fCodec(codec) |
657 , fHasAlpha(false) | 697 , fHasAlpha(false) |
658 , fCurrentRow(0) | 698 , fCurrentRow(0) |
659 , fHeight(dstInfo.height()) | 699 , fHeight(dstInfo.height()) |
660 , fSrcRowBytes(dstInfo.minRowBytes()) | |
661 , fRewindNeeded(false) | 700 , fRewindNeeded(false) |
662 { | 701 { |
702 fSrcRowBytes = dstInfo.width() * SkSwizzler::BytesPerPixel(fCodec->fSrcC onfig); | |
663 fGarbageRow.reset(fSrcRowBytes); | 703 fGarbageRow.reset(fSrcRowBytes); |
664 fGarbageRowPtr = static_cast<uint8_t*>(fGarbageRow.get()); | 704 fGarbageRowPtr = static_cast<uint8_t*>(fGarbageRow.get()); |
665 } | 705 } |
666 | 706 |
667 SkImageGenerator::Result onGetScanlines(void* dst, int count, size_t dstRowB ytes) override { | 707 SkImageGenerator::Result onGetScanlines(void* dst, int count, size_t dstRowB ytes) override { |
668 //rewind stream if have previously called onGetScanlines, | 708 //rewind stream if have previously called onGetScanlines, |
669 //since we need entire progressive image to get scanlines | 709 //since we need entire progressive image to get scanlines |
710 //need to reset transforms in setDataFormat if stream is rewound | |
670 if (fRewindNeeded) { | 711 if (fRewindNeeded) { |
671 if(false == fCodec->handleRewind()) { | 712 if(false == fCodec->handleRewind(this->dstInfo())) { |
672 return SkImageGenerator::kCouldNotRewind; | 713 return SkImageGenerator::kCouldNotRewind; |
673 } | 714 } |
674 } else { | 715 } else { |
675 fRewindNeeded = true; | 716 fRewindNeeded = true; |
676 } | 717 } |
677 if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) { | 718 if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) { |
678 SkCodecPrintf("setjmp long jump!\n"); | 719 SkCodecPrintf("setjmp long jump!\n"); |
679 return SkImageGenerator::kInvalidInput; | 720 return SkImageGenerator::kInvalidInput; |
680 } | 721 } |
681 const int number_passes = png_set_interlace_handling(fCodec->fPng_ptr); | 722 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++) { | 744 for (int y = 0; y < count; y++) { |
704 fCodec->fSwizzler->setDstRow(dst); | 745 fCodec->fSwizzler->setDstRow(dst); |
705 fHasAlpha |= !SkSwizzler::IsOpaque(fCodec->fSwizzler->next(srcRow)); | 746 fHasAlpha |= !SkSwizzler::IsOpaque(fCodec->fSwizzler->next(srcRow)); |
706 dst = SkTAddOffset<void>(dst, dstRowBytes); | 747 dst = SkTAddOffset<void>(dst, dstRowBytes); |
707 srcRow += fSrcRowBytes; | 748 srcRow += fSrcRowBytes; |
708 } | 749 } |
709 fCurrentRow += count; | 750 fCurrentRow += count; |
710 return SkImageGenerator::kSuccess; | 751 return SkImageGenerator::kSuccess; |
711 } | 752 } |
712 | 753 |
713 SkImageGenerator::Result onSkipScanlines(int count) override { | 754 SkImageGenerator::Result onSkipScanlines(int count) override { |
714 //when ongetScanlines is called it will skip to fCurrentRow | 755 //when ongetScanlines is called it will skip to fCurrentRow |
715 fCurrentRow += count; | 756 fCurrentRow += count; |
716 return SkImageGenerator::kSuccess; | 757 return SkImageGenerator::kSuccess; |
717 } | 758 } |
718 | 759 |
719 void onFinish() override { | 760 void onFinish() override { |
720 fCodec->finish(); | 761 fCodec->finish(); |
721 } | 762 } |
722 | 763 |
723 bool onReallyHasAlpha() const override { return fHasAlpha; } | 764 bool onReallyHasAlpha() const override { return fHasAlpha; } |
724 | 765 |
725 private: | 766 private: |
726 SkPngCodec* fCodec; // Unowned. | 767 SkPngCodec* fCodec; // Unowned. |
727 bool fHasAlpha; | 768 bool fHasAlpha; |
728 int fCurrentRow; | 769 int fCurrentRow; |
729 int fHeight; | 770 int fHeight; |
730 size_t fSrcRowBytes; | 771 size_t fSrcRowBytes; |
731 bool fRewindNeeded; | 772 bool fRewindNeeded; |
732 SkAutoMalloc fGarbageRow; | 773 SkAutoMalloc fGarbageRow; |
733 uint8_t* fGarbageRowPtr; | 774 uint8_t* fGarbageRowPtr; |
734 | |
735 | |
736 | |
737 | |
738 | |
739 typedef SkScanlineDecoder INHERITED; | 775 typedef SkScanlineDecoder INHERITED; |
740 }; | 776 }; |
741 | 777 |
742 | 778 |
743 SkScanlineDecoder* SkPngCodec::onGetScanlineDecoder(const SkImageInfo& dstInfo, | 779 SkScanlineDecoder* SkPngCodec::onGetScanlineDecoder(const SkImageInfo& dstInfo, |
744 const Options& options, SkPMColor ctable[], int* ctableCount) { | 780 const Options& options, SkPMColor ctable[], int* ctableCount) { |
745 if (!this->handleRewind()) { | 781 if (!conversion_possible(dstInfo, this->getInfo())) { |
782 SkCodecPrintf("no conversion possible\n"); | |
746 return NULL; | 783 return NULL; |
747 } | 784 } |
748 | |
749 // Check to see if scaling was requested. | 785 // Check to see if scaling was requested. |
750 if (dstInfo.dimensions() != this->getInfo().dimensions()) { | 786 if (dstInfo.dimensions() != this->getInfo().dimensions()) { |
751 return NULL; | 787 return NULL; |
752 } | 788 } |
753 | 789 if (!this->handleRewind(dstInfo)) { |
754 if (!conversion_possible(dstInfo, this->getInfo())) { | |
755 SkCodecPrintf("no conversion possible\n"); | |
756 return NULL; | 790 return NULL; |
757 } | 791 } |
758 | 792 |
759 // Note: We set dst to NULL since we do not know it yet. rowBytes is not nee ded, | 793 // Note: We set dst to NULL since we do not know it yet. rowBytes is not nee ded, |
760 // since we'll be manually updating the dstRow, but the SkSwizzler requires it to | 794 // since we'll be manually updating the dstRow, but the SkSwizzler requires it to |
761 // be at least dstInfo.minRowBytes. | 795 // be at least dstInfo.minRowBytes. |
762 if (this->initializeSwizzler(dstInfo, NULL, dstInfo.minRowBytes(), options, ctable, | 796 if (this->initializeSwizzler(dstInfo, NULL, dstInfo.minRowBytes(), options, ctable, |
763 ctableCount) != kSuccess) { | 797 ctableCount) != kSuccess) { |
764 SkCodecPrintf("failed to initialize the swizzler.\n"); | 798 SkCodecPrintf("failed to initialize the swizzler.\n"); |
765 return NULL; | 799 return NULL; |
766 } | 800 } |
767 | 801 |
768 SkASSERT(fNumberPasses != INVALID_NUMBER_PASSES); | 802 SkASSERT(fNumberPasses != INVALID_NUMBER_PASSES); |
769 if (fNumberPasses > 1) { | 803 if (fNumberPasses > 1) { |
770 // interlaced image | 804 // interlaced image |
771 return SkNEW_ARGS(SkPngInterlacedScanlineDecoder, (dstInfo, this)); | 805 return SkNEW_ARGS(SkPngInterlacedScanlineDecoder, (dstInfo, this)); |
772 } | 806 } |
773 | 807 |
774 return SkNEW_ARGS(SkPngScanlineDecoder, (dstInfo, this)); | 808 return SkNEW_ARGS(SkPngScanlineDecoder, (dstInfo, this)); |
775 } | 809 } |
776 | 810 |
OLD | NEW |