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, int* bitDe
pthPtr) { | 217 png_infop* info_ptrp, SkImageInfo* imageInfo) { |
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 17 matching lines...) Expand all Loading... |
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; |
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 if (bitDepthPtr) { | |
256 *bitDepthPtr = bitDepth; | |
257 } | |
258 | |
259 // sanity check for size | 255 // sanity check for size |
260 { | 256 { |
261 int64_t size = sk_64_mul(origWidth, origHeight); | 257 int64_t size = sk_64_mul(origWidth, origHeight); |
262 // 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 |
263 if (size < 0 || size > (0x7FFFFFFF >> 2)) { | 259 if (size < 0 || size > (0x7FFFFFFF >> 2)) { |
264 return false; | 260 return false; |
265 } | 261 } |
266 } | 262 } |
267 | 263 |
268 // 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 |
269 if (bitDepth == 16) { | 265 if (bitDepth == 16) { |
270 png_set_strip_16(png_ptr); | 266 png_set_strip_16(png_ptr); |
271 } | 267 } |
272 #ifdef PNG_READ_PACK_SUPPORTED | 268 #ifdef PNG_READ_PACK_SUPPORTED |
273 // 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 |
274 // byte into separate bytes (useful for paletted and grayscale images). | 270 // byte into separate bytes (useful for paletted and grayscale images). |
275 if (bitDepth < 8) { | 271 if (bitDepth < 8) { |
276 png_set_packing(png_ptr); | 272 png_set_packing(png_ptr); |
277 } | 273 } |
278 #endif | 274 #endif |
279 // 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. |
280 if (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8) { | 276 if (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8) { |
281 png_set_expand_gray_1_2_4_to_8(png_ptr); | 277 png_set_expand_gray_1_2_4_to_8(png_ptr); |
282 } | 278 } |
283 | 279 |
284 // Now determine the default SkColorType and SkAlphaType and set required tr
ansforms | 280 |
| 281 // Now determine the default SkColorType and SkAlphaType. |
285 SkColorType skColorType; | 282 SkColorType skColorType; |
286 SkAlphaType skAlphaType; | 283 SkAlphaType skAlphaType; |
287 switch (colorType) { | 284 switch (colorType) { |
288 case PNG_COLOR_TYPE_PALETTE: | 285 case PNG_COLOR_TYPE_PALETTE: |
289 skColorType = kIndex_8_SkColorType; | 286 skColorType = kIndex_8_SkColorType; |
290 skAlphaType = has_transparency_in_palette(png_ptr, info_ptr) ? | 287 skAlphaType = has_transparency_in_palette(png_ptr, info_ptr) ? |
291 kUnpremul_SkAlphaType : kOpaque_SkAlphaType; | 288 kUnpremul_SkAlphaType : kOpaque_SkAlphaType; |
292 break; | 289 break; |
293 case PNG_COLOR_TYPE_RGB: | 290 case PNG_COLOR_TYPE_GRAY: |
294 if (has_transparency_in_palette(png_ptr, info_ptr)) { | 291 if (false) { |
295 //convert to RGBA with tranparency information in tRNS chunk if
it exists | 292 // FIXME: Is this the wrong default behavior? This means if the |
296 png_set_tRNS_to_alpha(png_ptr); | 293 // caller supplies the info we gave them, they'll get Alpha 8. |
| 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 { |
297 skAlphaType = kUnpremul_SkAlphaType; | 311 skAlphaType = kUnpremul_SkAlphaType; |
298 } else { | 312 } else { |
299 //convert to RGBA with Opaque Alpha | |
300 png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); | |
301 skAlphaType = kOpaque_SkAlphaType; | 313 skAlphaType = kOpaque_SkAlphaType; |
302 } | 314 } |
303 skColorType = kN32_SkColorType; | 315 skColorType = kN32_SkColorType; |
304 break; | 316 break; |
305 case PNG_COLOR_TYPE_GRAY: | 317 } |
306 if (has_transparency_in_palette(png_ptr, info_ptr)) { | 318 |
307 //FIXME: support gray with alpha as a color type | 319 { |
308 //convert to RGBA if there is transparentcy info in the tRNS chu
nk | 320 // FIXME: Again, this block needs to go into onGetPixels. |
309 png_set_tRNS_to_alpha(png_ptr); | 321 bool convertGrayToRGB = PNG_COLOR_TYPE_GRAY == colorType && skColorType
!= kAlpha_8_SkColorType; |
310 png_set_gray_to_rgb(png_ptr); | 322 |
311 skColorType = kN32_SkColorType; | 323 // Unless the user is requesting A8, convert a grayscale image into RGB. |
312 skAlphaType = kUnpremul_SkAlphaType; | 324 // GRAY_ALPHA will always be converted to RGB |
313 } else { | 325 if (convertGrayToRGB || colorType == PNG_COLOR_TYPE_GRAY_ALPHA) { |
314 skColorType = kGray_8_SkColorType; | |
315 skAlphaType = kOpaque_SkAlphaType; | |
316 } | |
317 break; | |
318 case PNG_COLOR_TYPE_GRAY_ALPHA: | |
319 //FIXME: support gray with alpha as a color type | |
320 //convert to RGBA | |
321 png_set_gray_to_rgb(png_ptr); | 326 png_set_gray_to_rgb(png_ptr); |
322 skColorType = kN32_SkColorType; | 327 } |
323 skAlphaType = kUnpremul_SkAlphaType; | 328 |
324 break; | 329 // Add filler (or alpha) byte (after each RGB triplet) if necessary. |
325 case PNG_COLOR_TYPE_RGBA: | 330 // FIXME: It seems like we could just use RGB as the SrcConfig here. |
326 skColorType = kN32_SkColorType; | 331 if (colorType == PNG_COLOR_TYPE_RGB || convertGrayToRGB) { |
327 skAlphaType = kUnpremul_SkAlphaType; | 332 png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); |
328 break; | 333 } |
329 default: | |
330 //all the color types have been covered above | |
331 SkASSERT(false); | |
332 } | 334 } |
333 | 335 |
334 // FIXME: Also need to check for sRGB (skbug.com/3471). | 336 // FIXME: Also need to check for sRGB (skbug.com/3471). |
335 | 337 |
336 if (imageInfo) { | 338 if (imageInfo) { |
337 *imageInfo = SkImageInfo::Make(origWidth, origHeight, skColorType, skAlp
haType); | 339 *imageInfo = SkImageInfo::Make(origWidth, origHeight, skColorType, |
| 340 skAlphaType); |
338 } | 341 } |
339 autoClean.detach(); | 342 autoClean.detach(); |
340 if (png_ptrp) { | 343 if (png_ptrp) { |
341 *png_ptrp = png_ptr; | 344 *png_ptrp = png_ptr; |
342 } | 345 } |
343 if (info_ptrp) { | 346 if (info_ptrp) { |
344 *info_ptrp = info_ptr; | 347 *info_ptrp = info_ptr; |
345 } | 348 } |
346 | |
347 return true; | 349 return true; |
348 } | 350 } |
349 | 351 |
350 SkCodec* SkPngCodec::NewFromStream(SkStream* stream) { | 352 SkCodec* SkPngCodec::NewFromStream(SkStream* stream) { |
351 SkAutoTDelete<SkStream> streamDeleter(stream); | 353 SkAutoTDelete<SkStream> streamDeleter(stream); |
352 png_structp png_ptr; | 354 png_structp png_ptr; |
353 png_infop info_ptr; | 355 png_infop info_ptr; |
354 SkImageInfo imageInfo; | 356 SkImageInfo imageInfo; |
355 int bitDepth; | 357 if (read_header(stream, &png_ptr, &info_ptr, &imageInfo)) { |
356 if (read_header(stream, &png_ptr, &info_ptr, &imageInfo, &bitDepth)) { | 358 return SkNEW_ARGS(SkPngCodec, (imageInfo, streamDeleter.detach(), png_pt
r, info_ptr)); |
357 return SkNEW_ARGS(SkPngCodec, (imageInfo, streamDeleter.detach(), | |
358 png_ptr, info_ptr, bitDepth)); | |
359 } | 359 } |
360 return NULL; | 360 return NULL; |
361 } | 361 } |
362 | 362 |
363 #define INVALID_NUMBER_PASSES -1 | 363 #define INVALID_NUMBER_PASSES -1 |
364 SkPngCodec::SkPngCodec(const SkImageInfo& info, SkStream* stream, | 364 SkPngCodec::SkPngCodec(const SkImageInfo& info, SkStream* stream, |
365 png_structp png_ptr, png_infop info_ptr, int bitDepth) | 365 png_structp png_ptr, png_infop info_ptr) |
366 : INHERITED(info, stream) | 366 : INHERITED(info, stream) |
367 , fPng_ptr(png_ptr) | 367 , fPng_ptr(png_ptr) |
368 , fInfo_ptr(info_ptr) | 368 , fInfo_ptr(info_ptr) |
369 , fSrcConfig(SkSwizzler::kUnknown) | 369 , fSrcConfig(SkSwizzler::kUnknown) |
370 , fNumberPasses(INVALID_NUMBER_PASSES) | 370 , fNumberPasses(INVALID_NUMBER_PASSES) |
371 , fReallyHasAlpha(false) | 371 , fReallyHasAlpha(false) |
372 , fBitDepth(bitDepth) | |
373 {} | 372 {} |
374 | 373 |
375 SkPngCodec::~SkPngCodec() { | 374 SkPngCodec::~SkPngCodec() { |
376 // First, ensure that the scanline decoder is left in a finished state. | 375 // First, ensure that the scanline decoder is left in a finished state. |
377 SkAutoTDelete<SkScanlineDecoder> decoder(this->detachScanlineDecoder()); | 376 SkAutoTDelete<SkScanlineDecoder> decoder(this->detachScanlineDecoder()); |
378 if (NULL != decoder) { | 377 if (NULL != decoder) { |
379 this->finish(); | 378 this->finish(); |
380 } | 379 } |
381 | 380 |
382 this->destroyReadStruct(); | 381 this->destroyReadStruct(); |
(...skipping 30 matching lines...) Expand all Loading... |
413 switch (dst.alphaType()) { | 412 switch (dst.alphaType()) { |
414 case kPremul_SkAlphaType: | 413 case kPremul_SkAlphaType: |
415 case kUnpremul_SkAlphaType: | 414 case kUnpremul_SkAlphaType: |
416 // The source is not opaque, so either of these is okay | 415 // The source is not opaque, so either of these is okay |
417 break; | 416 break; |
418 default: | 417 default: |
419 // We cannot decode a non-opaque image to opaque (or unknown) | 418 // We cannot decode a non-opaque image to opaque (or unknown) |
420 return false; | 419 return false; |
421 } | 420 } |
422 } | 421 } |
| 422 |
423 // Check for supported color types | 423 // Check for supported color types |
424 switch (dst.colorType()) { | 424 switch (dst.colorType()) { |
| 425 // Allow output to kN32 from any type of input |
425 case kN32_SkColorType: | 426 case kN32_SkColorType: |
426 return true; | 427 return true; |
427 default: | 428 default: |
428 return dst.colorType() == src.colorType(); | 429 return dst.colorType() == src.colorType(); |
429 } | 430 } |
430 } | 431 } |
431 | 432 |
432 SkCodec::Result SkPngCodec::initializeSwizzler(const SkImageInfo& requestedInfo, | 433 SkCodec::Result SkPngCodec::initializeSwizzler(const SkImageInfo& requestedInfo, |
433 void* dst, size_t rowBytes, | 434 void* dst, size_t rowBytes, |
434 const Options& options, | 435 const Options& options, |
435 SkPMColor ctable[], | 436 SkPMColor ctable[], |
436 int* ctableCount) { | 437 int* ctableCount) { |
437 // FIXME: Could we use the return value of setjmp to specify the type of | 438 // FIXME: Could we use the return value of setjmp to specify the type of |
438 // error? | 439 // error? |
439 if (setjmp(png_jmpbuf(fPng_ptr))) { | 440 if (setjmp(png_jmpbuf(fPng_ptr))) { |
440 SkCodecPrintf("setjmp long jump!\n"); | 441 SkCodecPrintf("setjmp long jump!\n"); |
441 return kInvalidInput; | 442 return kInvalidInput; |
442 } | 443 } |
443 fNumberPasses = png_set_interlace_handling(fPng_ptr); | 444 |
444 png_read_update_info(fPng_ptr, fInfo_ptr); | 445 // FIXME: We already retrieved this information. Store it in SkPngCodec? |
| 446 png_uint_32 origWidth, origHeight; |
| 447 int bitDepth, pngColorType, interlaceType; |
| 448 png_get_IHDR(fPng_ptr, fInfo_ptr, &origWidth, &origHeight, &bitDepth, |
| 449 &pngColorType, &interlaceType, int_p_NULL, int_p_NULL); |
| 450 |
| 451 fNumberPasses = (interlaceType != PNG_INTERLACE_NONE) ? |
| 452 png_set_interlace_handling(fPng_ptr) : 1; |
445 | 453 |
446 // Set to the default before calling decodePalette, which may change it. | 454 // Set to the default before calling decodePalette, which may change it. |
447 fReallyHasAlpha = false; | 455 fReallyHasAlpha = false; |
448 | 456 if (PNG_COLOR_TYPE_PALETTE == pngColorType) { |
449 //srcColorType was determined in readHeader() which determined png color typ
e | 457 fSrcConfig = SkSwizzler::kIndex; |
450 const SkColorType srcColorType = this->getInfo().colorType(); | 458 if (!this->decodePalette(kPremul_SkAlphaType == requestedInfo.alphaType(
), bitDepth, |
451 | 459 ctableCount)) { |
452 switch (srcColorType) { | 460 return kInvalidInput; |
453 case kIndex_8_SkColorType: | 461 } |
454 //decode palette to Skia format | 462 } else if (kAlpha_8_SkColorType == requestedInfo.colorType()) { |
455 fSrcConfig = SkSwizzler::kIndex; | 463 // Note: we check the destination, since otherwise we would have |
456 if (!this->decodePalette(kPremul_SkAlphaType == requestedInfo.alphaT
ype(), fBitDepth, | 464 // told png to upscale. |
457 ctableCount)) { | 465 SkASSERT(PNG_COLOR_TYPE_GRAY == pngColorType); |
458 return kInvalidInput; | 466 fSrcConfig = SkSwizzler::kGray; |
459 } | 467 } else if (this->getInfo().alphaType() == kOpaque_SkAlphaType) { |
460 break; | 468 fSrcConfig = SkSwizzler::kRGBX; |
461 case kGray_8_SkColorType: | 469 } else { |
462 fSrcConfig = SkSwizzler::kGray; | 470 fSrcConfig = SkSwizzler::kRGBA; |
463 break; | 471 } |
464 case kN32_SkColorType: | |
465 if (this->getInfo().alphaType() == kOpaque_SkAlphaType) { | |
466 fSrcConfig = SkSwizzler::kRGBX; | |
467 } else { | |
468 fSrcConfig = SkSwizzler::kRGBA; | |
469 } | |
470 break; | |
471 default: | |
472 //would have exited before now if the colorType was supported by png | |
473 SkASSERT(false); | |
474 } | |
475 | 472 |
476 // Copy the color table to the client if they request kIndex8 mode | 473 // Copy the color table to the client if they request kIndex8 mode |
477 copy_color_table(requestedInfo, fColorTable, ctable, ctableCount); | 474 copy_color_table(requestedInfo, fColorTable, ctable, ctableCount); |
478 | 475 |
479 // Create the swizzler. SkPngCodec retains ownership of the color table. | 476 // Create the swizzler. SkPngCodec retains ownership of the color table. |
480 const SkPMColor* colors = fColorTable ? fColorTable->readColors() : NULL; | 477 const SkPMColor* colors = fColorTable ? fColorTable->readColors() : NULL; |
481 fSwizzler.reset(SkSwizzler::CreateSwizzler(fSrcConfig, colors, requestedInfo
, | 478 fSwizzler.reset(SkSwizzler::CreateSwizzler(fSrcConfig, colors, requestedInfo
, |
482 dst, rowBytes, options.fZeroInitialized)); | 479 dst, rowBytes, options.fZeroInitialized)); |
483 if (!fSwizzler) { | 480 if (!fSwizzler) { |
484 // FIXME: CreateSwizzler could fail for another reason. | 481 // FIXME: CreateSwizzler could fail for another reason. |
485 return kUnimplemented; | 482 return kUnimplemented; |
486 } | 483 } |
| 484 |
| 485 // FIXME: Here is where we should likely insert some of the modifications |
| 486 // made in the factory. |
| 487 png_read_update_info(fPng_ptr, fInfo_ptr); |
| 488 |
487 return kSuccess; | 489 return kSuccess; |
488 } | 490 } |
489 | 491 |
490 | |
491 bool SkPngCodec::handleRewind() { | 492 bool SkPngCodec::handleRewind() { |
492 switch (this->rewindIfNeeded()) { | 493 switch (this->rewindIfNeeded()) { |
493 case kNoRewindNecessary_RewindState: | 494 case kNoRewindNecessary_RewindState: |
494 return true; | 495 return true; |
495 case kCouldNotRewind_RewindState: | 496 case kCouldNotRewind_RewindState: |
496 return false; | 497 return false; |
497 case kRewound_RewindState: { | 498 case kRewound_RewindState: { |
498 // This sets fPng_ptr and fInfo_ptr to NULL. If read_header | 499 // This sets fPng_ptr and fInfo_ptr to NULL. If read_header |
499 // succeeds, they will be repopulated, and if it fails, they will | 500 // succeeds, they will be repopulated, and if it fails, they will |
500 // remain NULL. Any future accesses to fPng_ptr and fInfo_ptr will | 501 // remain NULL. Any future accesses to fPng_ptr and fInfo_ptr will |
501 // come through this function which will rewind and again attempt | 502 // come through this function which will rewind and again attempt |
502 // to reinitialize them. | 503 // to reinitialize them. |
503 this->destroyReadStruct(); | 504 this->destroyReadStruct(); |
504 png_structp png_ptr; | 505 png_structp png_ptr; |
505 png_infop info_ptr; | 506 png_infop info_ptr; |
506 if (read_header(this->stream(), &png_ptr, &info_ptr, NULL, NULL)) { | 507 if (read_header(this->stream(), &png_ptr, &info_ptr, NULL)) { |
507 fPng_ptr = png_ptr; | 508 fPng_ptr = png_ptr; |
508 fInfo_ptr = info_ptr; | 509 fInfo_ptr = info_ptr; |
509 return true; | 510 return true; |
510 } | 511 } |
511 return false; | 512 return false; |
512 } | 513 } |
513 default: | 514 default: |
514 SkASSERT(false); | 515 SkASSERT(false); |
515 return false; | 516 return false; |
516 } | 517 } |
517 } | 518 } |
518 | 519 |
519 SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void*
dst, | 520 SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void*
dst, |
520 size_t rowBytes, const Options& options, | 521 size_t rowBytes, const Options& options, |
521 SkPMColor ctable[], int* ctableCount) { | 522 SkPMColor ctable[], int* ctableCount) { |
522 if (!conversion_possible(requestedInfo, this->getInfo())) { | |
523 return kInvalidConversion; | |
524 } | |
525 // Do not allow a regular decode if the caller has asked for a scanline deco
der | 523 // Do not allow a regular decode if the caller has asked for a scanline deco
der |
526 if (NULL != this->scanlineDecoder()) { | 524 if (NULL != this->scanlineDecoder()) { |
527 SkCodecPrintf("cannot getPixels() if a scanline decoder has been created
\n"); | 525 SkCodecPrintf("cannot getPixels() if a scanline decoder has been created
\n"); |
528 return kInvalidParameters; | 526 return kInvalidParameters; |
529 } | 527 } |
| 528 |
| 529 if (!this->handleRewind()) { |
| 530 return kCouldNotRewind; |
| 531 } |
530 if (requestedInfo.dimensions() != this->getInfo().dimensions()) { | 532 if (requestedInfo.dimensions() != this->getInfo().dimensions()) { |
531 return kInvalidScale; | 533 return kInvalidScale; |
532 } | 534 } |
533 if (!this->handleRewind()) { | 535 if (!conversion_possible(requestedInfo, this->getInfo())) { |
534 return kCouldNotRewind; | 536 return kInvalidConversion; |
535 } | 537 } |
536 | 538 |
537 // Note that ctable and ctableCount may be modified if there is a color tabl
e | 539 // Note that ctable and ctableCount may be modified if there is a color tabl
e |
538 const Result result = this->initializeSwizzler(requestedInfo, dst, rowBytes, | 540 const Result result = this->initializeSwizzler(requestedInfo, dst, rowBytes, |
539 options, ctable, ctableCount)
; | 541 options, ctable, ctableCount)
; |
| 542 |
540 if (result != kSuccess) { | 543 if (result != kSuccess) { |
541 return result; | 544 return result; |
542 } | 545 } |
| 546 |
543 // FIXME: Could we use the return value of setjmp to specify the type of | 547 // FIXME: Could we use the return value of setjmp to specify the type of |
544 // error? | 548 // error? |
545 if (setjmp(png_jmpbuf(fPng_ptr))) { | 549 if (setjmp(png_jmpbuf(fPng_ptr))) { |
546 SkCodecPrintf("setjmp long jump!\n"); | 550 SkCodecPrintf("setjmp long jump!\n"); |
547 return kInvalidInput; | 551 return kInvalidInput; |
548 } | 552 } |
549 | 553 |
550 SkASSERT(fNumberPasses != INVALID_NUMBER_PASSES); | 554 SkASSERT(fNumberPasses != INVALID_NUMBER_PASSES); |
551 SkAutoMalloc storage; | 555 SkAutoMalloc storage; |
552 if (fNumberPasses > 1) { | 556 if (fNumberPasses > 1) { |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
654 | 658 |
655 | 659 |
656 class SkPngInterlacedScanlineDecoder : public SkScanlineDecoder { | 660 class SkPngInterlacedScanlineDecoder : public SkScanlineDecoder { |
657 public: | 661 public: |
658 SkPngInterlacedScanlineDecoder(const SkImageInfo& dstInfo, SkPngCodec* codec
) | 662 SkPngInterlacedScanlineDecoder(const SkImageInfo& dstInfo, SkPngCodec* codec
) |
659 : INHERITED(dstInfo) | 663 : INHERITED(dstInfo) |
660 , fCodec(codec) | 664 , fCodec(codec) |
661 , fHasAlpha(false) | 665 , fHasAlpha(false) |
662 , fCurrentRow(0) | 666 , fCurrentRow(0) |
663 , fHeight(dstInfo.height()) | 667 , fHeight(dstInfo.height()) |
| 668 , fSrcRowBytes(dstInfo.minRowBytes()) |
664 , fRewindNeeded(false) | 669 , fRewindNeeded(false) |
665 { | 670 { |
666 fSrcRowBytes = dstInfo.width() * SkSwizzler::BytesPerPixel(fCodec->fSrcC
onfig); | |
667 fGarbageRow.reset(fSrcRowBytes); | 671 fGarbageRow.reset(fSrcRowBytes); |
668 fGarbageRowPtr = static_cast<uint8_t*>(fGarbageRow.get()); | 672 fGarbageRowPtr = static_cast<uint8_t*>(fGarbageRow.get()); |
669 } | 673 } |
670 | 674 |
671 SkImageGenerator::Result onGetScanlines(void* dst, int count, size_t dstRowB
ytes) override { | 675 SkImageGenerator::Result onGetScanlines(void* dst, int count, size_t dstRowB
ytes) override { |
672 //rewind stream if have previously called onGetScanlines, | 676 //rewind stream if have previously called onGetScanlines, |
673 //since we need entire progressive image to get scanlines | 677 //since we need entire progressive image to get scanlines |
674 if (fRewindNeeded) { | 678 if (fRewindNeeded) { |
675 if(false == fCodec->handleRewind()) { | 679 if(false == fCodec->handleRewind()) { |
676 return SkImageGenerator::kCouldNotRewind; | 680 return SkImageGenerator::kCouldNotRewind; |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
724 | 728 |
725 private: | 729 private: |
726 SkPngCodec* fCodec; // Unowned. | 730 SkPngCodec* fCodec; // Unowned. |
727 bool fHasAlpha; | 731 bool fHasAlpha; |
728 int fCurrentRow; | 732 int fCurrentRow; |
729 int fHeight; | 733 int fHeight; |
730 size_t fSrcRowBytes; | 734 size_t fSrcRowBytes; |
731 bool fRewindNeeded; | 735 bool fRewindNeeded; |
732 SkAutoMalloc fGarbageRow; | 736 SkAutoMalloc fGarbageRow; |
733 uint8_t* fGarbageRowPtr; | 737 uint8_t* fGarbageRowPtr; |
| 738 |
| 739 |
| 740 |
| 741 |
734 | 742 |
735 typedef SkScanlineDecoder INHERITED; | 743 typedef SkScanlineDecoder INHERITED; |
736 }; | 744 }; |
737 | 745 |
738 | 746 |
739 SkScanlineDecoder* SkPngCodec::onGetScanlineDecoder(const SkImageInfo& dstInfo, | 747 SkScanlineDecoder* SkPngCodec::onGetScanlineDecoder(const SkImageInfo& dstInfo, |
740 const Options& options, SkPMColor ctable[], int* ctableCount) { | 748 const Options& options, SkPMColor ctable[], int* ctableCount) { |
| 749 if (!this->handleRewind()) { |
| 750 return NULL; |
| 751 } |
| 752 |
| 753 // Check to see if scaling was requested. |
| 754 if (dstInfo.dimensions() != this->getInfo().dimensions()) { |
| 755 return NULL; |
| 756 } |
| 757 |
741 if (!conversion_possible(dstInfo, this->getInfo())) { | 758 if (!conversion_possible(dstInfo, this->getInfo())) { |
742 SkCodecPrintf("no conversion possible\n"); | 759 SkCodecPrintf("no conversion possible\n"); |
743 return NULL; | 760 return NULL; |
744 } | 761 } |
745 // Check to see if scaling was requested. | |
746 if (dstInfo.dimensions() != this->getInfo().dimensions()) { | |
747 return NULL; | |
748 } | |
749 if (!this->handleRewind()) { | |
750 return NULL; | |
751 } | |
752 | 762 |
753 // Note: We set dst to NULL since we do not know it yet. rowBytes is not nee
ded, | 763 // Note: We set dst to NULL since we do not know it yet. rowBytes is not nee
ded, |
754 // since we'll be manually updating the dstRow, but the SkSwizzler requires
it to | 764 // since we'll be manually updating the dstRow, but the SkSwizzler requires
it to |
755 // be at least dstInfo.minRowBytes. | 765 // be at least dstInfo.minRowBytes. |
756 if (this->initializeSwizzler(dstInfo, NULL, dstInfo.minRowBytes(), options,
ctable, | 766 if (this->initializeSwizzler(dstInfo, NULL, dstInfo.minRowBytes(), options,
ctable, |
757 ctableCount) != kSuccess) { | 767 ctableCount) != kSuccess) { |
758 SkCodecPrintf("failed to initialize the swizzler.\n"); | 768 SkCodecPrintf("failed to initialize the swizzler.\n"); |
759 return NULL; | 769 return NULL; |
760 } | 770 } |
761 | 771 |
762 SkASSERT(fNumberPasses != INVALID_NUMBER_PASSES); | 772 SkASSERT(fNumberPasses != INVALID_NUMBER_PASSES); |
763 if (fNumberPasses > 1) { | 773 if (fNumberPasses > 1) { |
764 // interlaced image | 774 // interlaced image |
765 return SkNEW_ARGS(SkPngInterlacedScanlineDecoder, (dstInfo, this)); | 775 return SkNEW_ARGS(SkPngInterlacedScanlineDecoder, (dstInfo, this)); |
766 } | 776 } |
767 | 777 |
768 return SkNEW_ARGS(SkPngScanlineDecoder, (dstInfo, this)); | 778 return SkNEW_ARGS(SkPngScanlineDecoder, (dstInfo, this)); |
769 } | 779 } |
770 | 780 |
OLD | NEW |