Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(113)

Side by Side Diff: src/codec/SkCodec_libpng.cpp

Issue 1212373006: Swizzling, except for premultiplying, done using libpng transforms (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/codec/SkCodec_libpng.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/codec/SkCodec_libpng.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698