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

Side by Side Diff: src/images/SkImageDecoder_libpng.cpp

Issue 16410009: Add an option to create unpremultiplied bitmaps. (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: Respond to comments Created 7 years, 6 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 | Annotate | Revision Log
OLDNEW
1 1
2 /* 2 /*
3 * Copyright 2006 The Android Open Source Project 3 * Copyright 2006 The Android Open Source Project
4 * 4 *
5 * Use of this source code is governed by a BSD-style license that can be 5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file. 6 * found in the LICENSE file.
7 */ 7 */
8 8
9 9
10 #include "SkImageDecoder.h" 10 #include "SkImageDecoder.h"
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
73 #ifdef SK_BUILD_FOR_ANDROID 73 #ifdef SK_BUILD_FOR_ANDROID
74 virtual bool onBuildTileIndex(SkStream *stream, int *width, int *height) SK_ OVERRIDE; 74 virtual bool onBuildTileIndex(SkStream *stream, int *width, int *height) SK_ OVERRIDE;
75 virtual bool onDecodeSubset(SkBitmap* bitmap, const SkIRect& region) SK_OVER RIDE; 75 virtual bool onDecodeSubset(SkBitmap* bitmap, const SkIRect& region) SK_OVER RIDE;
76 #endif 76 #endif
77 virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE; 77 virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE;
78 78
79 private: 79 private:
80 SkPNGImageIndex* fImageIndex; 80 SkPNGImageIndex* fImageIndex;
81 81
82 bool onDecodeInit(SkStream* stream, png_structp *png_ptrp, png_infop *info_p trp); 82 bool onDecodeInit(SkStream* stream, png_structp *png_ptrp, png_infop *info_p trp);
83 bool decodePalette(png_structp png_ptr, png_infop info_ptr, bool *hasAlphap, 83 bool decodePalette(png_structp png_ptr, png_infop info_ptr,
84 bool *reallyHasAlphap, SkColorTable **colorTablep); 84 bool * SK_RESTRICT hasAlphap, bool *reallyHasAlphap,
85 SkColorTable **colorTablep);
85 bool getBitmapConfig(png_structp png_ptr, png_infop info_ptr, 86 bool getBitmapConfig(png_structp png_ptr, png_infop info_ptr,
86 SkBitmap::Config *config, bool *hasAlpha, 87 SkBitmap::Config *config, bool *hasAlpha,
87 bool *doDither, SkPMColor *theTranspColor); 88 bool *doDither, SkPMColor *theTranspColor);
88 89
89 typedef SkImageDecoder INHERITED; 90 typedef SkImageDecoder INHERITED;
90 }; 91 };
91 92
92 #ifndef png_jmpbuf 93 #ifndef png_jmpbuf
93 # define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) 94 # define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
94 #endif 95 #endif
(...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after
304 bool reuseBitmap = (rowptr != NULL); 305 bool reuseBitmap = (rowptr != NULL);
305 decodedBitmap->unlockPixels(); 306 decodedBitmap->unlockPixels();
306 if (reuseBitmap && (sampler.scaledWidth() != decodedBitmap->width() || 307 if (reuseBitmap && (sampler.scaledWidth() != decodedBitmap->width() ||
307 sampler.scaledHeight() != decodedBitmap->height())) { 308 sampler.scaledHeight() != decodedBitmap->height())) {
308 // Dimensions must match 309 // Dimensions must match
309 return false; 310 return false;
310 } 311 }
311 312
312 if (!reuseBitmap) { 313 if (!reuseBitmap) {
313 decodedBitmap->setConfig(config, sampler.scaledWidth(), 314 decodedBitmap->setConfig(config, sampler.scaledWidth(),
314 sampler.scaledHeight(), 0); 315 sampler.scaledHeight());
315 } 316 }
316 if (SkImageDecoder::kDecodeBounds_Mode == mode) { 317 if (SkImageDecoder::kDecodeBounds_Mode == mode) {
317 return true; 318 return true;
318 } 319 }
319 320
320 // from here down we are concerned with colortables and pixels 321 // from here down we are concerned with colortables and pixels
321 322
322 // we track if we actually see a non-opaque pixels, since sometimes a PNG se ts its colortype 323 // we track if we actually see a non-opaque pixels, since sometimes a PNG se ts its colortype
323 // to |= PNG_COLOR_MASK_ALPHA, but all of its pixels are in fact opaque. We care, since we 324 // to |= PNG_COLOR_MASK_ALPHA, but all of its pixels are in fact opaque. We care, since we
324 // draw lots faster if we can flag the bitmap has being opaque 325 // draw lots faster if we can flag the bitmap has being opaque
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
428 skip_src_rows(png_ptr, srcRow, origHeight - read); 429 skip_src_rows(png_ptr, srcRow, origHeight - read);
429 } 430 }
430 } 431 }
431 432
432 /* read rest of file, and get additional chunks in info_ptr - REQUIRED */ 433 /* read rest of file, and get additional chunks in info_ptr - REQUIRED */
433 png_read_end(png_ptr, info_ptr); 434 png_read_end(png_ptr, info_ptr);
434 435
435 if (0 != theTranspColor) { 436 if (0 != theTranspColor) {
436 reallyHasAlpha |= substituteTranspColor(decodedBitmap, theTranspColor); 437 reallyHasAlpha |= substituteTranspColor(decodedBitmap, theTranspColor);
437 } 438 }
439 if (reallyHasAlpha && this->getRequireUnpremultipliedColors() &&
440 SkBitmap::kARGB_8888_Config != decodedBitmap->config()) {
441 // If the caller wants an unpremultiplied bitmap, and we let them get
442 // away with a config other than 8888, and it has alpha after all,
443 // return false, since the result will have premultiplied colors.
444 return false;
445 }
438 decodedBitmap->setIsOpaque(!reallyHasAlpha); 446 decodedBitmap->setIsOpaque(!reallyHasAlpha);
439 if (reuseBitmap) { 447 if (reuseBitmap) {
440 decodedBitmap->notifyPixelsChanged(); 448 decodedBitmap->notifyPixelsChanged();
441 } 449 }
442 return true; 450 return true;
443 } 451 }
444 452
445 453
446 454
447 bool SkPNGImageDecoder::getBitmapConfig(png_structp png_ptr, png_infop info_ptr, 455 bool SkPNGImageDecoder::getBitmapConfig(png_structp png_ptr, png_infop info_ptr,
448 SkBitmap::Config *configp, bool *hasAlph ap, 456 SkBitmap::Config *configp, bool * SK_RES TRICT hasAlphap,
449 bool *doDitherp, SkPMColor *theTranspCol orp) { 457 bool *doDitherp, SkPMColor *theTranspCol orp) {
450 png_uint_32 origWidth, origHeight; 458 png_uint_32 origWidth, origHeight;
451 int bitDepth, colorType; 459 int bitDepth, colorType;
452 png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth, 460 png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth,
453 &colorType, int_p_NULL, int_p_NULL, int_p_NULL); 461 &colorType, int_p_NULL, int_p_NULL, int_p_NULL);
454 462
455 // check for sBIT chunk data, in case we should disable dithering because 463 // check for sBIT chunk data, in case we should disable dithering because
456 // our data is not truely 8bits per component 464 // our data is not truely 8bits per component
457 png_color_8p sig_bit; 465 png_color_8p sig_bit;
458 if (*doDitherp && png_get_sBIT(png_ptr, info_ptr, &sig_bit)) { 466 if (*doDitherp && png_get_sBIT(png_ptr, info_ptr, &sig_bit)) {
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
539 size.setMul(origWidth, origHeight); 547 size.setMul(origWidth, origHeight);
540 if (size.isNeg() || !size.is32()) { 548 if (size.isNeg() || !size.is32()) {
541 return false; 549 return false;
542 } 550 }
543 // now check that if we are 4-bytes per pixel, we also don't overflow 551 // now check that if we are 4-bytes per pixel, we also don't overflow
544 if (size.get32() > (0x7FFFFFFF >> 2)) { 552 if (size.get32() > (0x7FFFFFFF >> 2)) {
545 return false; 553 return false;
546 } 554 }
547 } 555 }
548 556
549 return this->chooseFromOneChoice(*configp, origWidth, origHeight); 557 if (!this->chooseFromOneChoice(*configp, origWidth, origHeight)) {
558 return false;
559 }
560
561 // If the image has alpha and the decoder wants unpremultiplied
562 // colors, the only supported config is 8888.
563 if (this->getRequireUnpremultipliedColors() && *hasAlphap) {
564 *configp = SkBitmap::kARGB_8888_Config;
565 }
566 return true;
550 } 567 }
551 568
569 typedef uint32_t (*PackColorProc)(U8CPU a, U8CPU r, U8CPU g, U8CPU b);
570
552 bool SkPNGImageDecoder::decodePalette(png_structp png_ptr, png_infop info_ptr, 571 bool SkPNGImageDecoder::decodePalette(png_structp png_ptr, png_infop info_ptr,
553 bool *hasAlphap, bool *reallyHasAlphap, 572 bool *hasAlphap, bool *reallyHasAlphap,
554 SkColorTable **colorTablep) { 573 SkColorTable **colorTablep) {
555 int numPalette; 574 int numPalette;
556 png_colorp palette; 575 png_colorp palette;
557 png_bytep trans; 576 png_bytep trans;
558 int numTrans; 577 int numTrans;
559 bool reallyHasAlpha = false; 578 bool reallyHasAlpha = false;
560 SkColorTable* colorTable = NULL; 579 SkColorTable* colorTable = NULL;
561 580
(...skipping 18 matching lines...) Expand all
580 colorTable->setFlags(colorTable->getFlags() | SkColorTable::kColorsAreOp aque_Flag); 599 colorTable->setFlags(colorTable->getFlags() | SkColorTable::kColorsAreOp aque_Flag);
581 } 600 }
582 // check for bad images that might make us crash 601 // check for bad images that might make us crash
583 if (numTrans > numPalette) { 602 if (numTrans > numPalette) {
584 numTrans = numPalette; 603 numTrans = numPalette;
585 } 604 }
586 605
587 int index = 0; 606 int index = 0;
588 int transLessThanFF = 0; 607 int transLessThanFF = 0;
589 608
609 // Choose which function to use to create the color table. If the final dest ination's
610 // config is unpremultiplied, the color table will store unpremultiplied col ors.
611 PackColorProc proc;
612 if (this->getRequireUnpremultipliedColors()) {
613 proc = &SkPackARGB32NoCheck;
614 } else {
615 proc = &SkPreMultiplyARGB;
616 }
590 for (; index < numTrans; index++) { 617 for (; index < numTrans; index++) {
591 transLessThanFF |= (int)*trans - 0xFF; 618 transLessThanFF |= (int)*trans - 0xFF;
592 *colorPtr++ = SkPreMultiplyARGB(*trans++, palette->red, palette->green, palette->blue); 619 *colorPtr++ = proc(*trans++, palette->red, palette->green, palette->blue );
reed1 2013/06/13 13:51:39 Is there a measurable perf-hit with this change (f
scroggo 2013/06/13 19:04:49 We don't actually use an inlineable function (thou
593 palette++; 620 palette++;
594 } 621 }
595 reallyHasAlpha |= (transLessThanFF < 0); 622 reallyHasAlpha |= (transLessThanFF < 0);
596 623
597 for (; index < numPalette; index++) { 624 for (; index < numPalette; index++) {
598 *colorPtr++ = SkPackARGB32(0xFF, palette->red, palette->green, palette-> blue); 625 *colorPtr++ = SkPackARGB32(0xFF, palette->red, palette->green, palette-> blue);
599 palette++; 626 palette++;
600 } 627 }
601 628
602 // see BUGGY IMAGE WORKAROUND comment above 629 // see BUGGY IMAGE WORKAROUND comment above
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
672 SkPMColor theTranspColor = 0; // 0 tells us not to try to match 699 SkPMColor theTranspColor = 0; // 0 tells us not to try to match
673 700
674 if (!getBitmapConfig(png_ptr, info_ptr, &config, &hasAlpha, &doDither, &theT ranspColor)) { 701 if (!getBitmapConfig(png_ptr, info_ptr, &config, &hasAlpha, &doDither, &theT ranspColor)) {
675 return false; 702 return false;
676 } 703 }
677 704
678 const int sampleSize = this->getSampleSize(); 705 const int sampleSize = this->getSampleSize();
679 SkScaledBitmapSampler sampler(origWidth, rect.height(), sampleSize); 706 SkScaledBitmapSampler sampler(origWidth, rect.height(), sampleSize);
680 707
681 SkBitmap decodedBitmap; 708 SkBitmap decodedBitmap;
682 decodedBitmap.setConfig(config, sampler.scaledWidth(), sampler.scaledHeight( ), 0); 709 decodedBitmap.setConfig(config, sampler.scaledWidth(), sampler.scaledHeight( ));
683 710
684 // from here down we are concerned with colortables and pixels 711 // from here down we are concerned with colortables and pixels
685 712
686 // we track if we actually see a non-opaque pixels, since sometimes a PNG se ts its colortype 713 // we track if we actually see a non-opaque pixels, since sometimes a PNG se ts its colortype
687 // to |= PNG_COLOR_MASK_ALPHA, but all of its pixels are in fact opaque. We care, since we 714 // to |= PNG_COLOR_MASK_ALPHA, but all of its pixels are in fact opaque. We care, since we
688 // draw lots faster if we can flag the bitmap has being opaque 715 // draw lots faster if we can flag the bitmap has being opaque
689 bool reallyHasAlpha = false; 716 bool reallyHasAlpha = false;
690 SkColorTable* colorTable = NULL; 717 SkColorTable* colorTable = NULL;
691 718
692 if (colorType == PNG_COLOR_TYPE_PALETTE) { 719 if (colorType == PNG_COLOR_TYPE_PALETTE) {
693 decodePalette(png_ptr, info_ptr, &hasAlpha, &reallyHasAlpha, &colorTable ); 720 decodePalette(png_ptr, info_ptr, config, &hasAlpha, &reallyHasAlpha, &co lorTable);
694 } 721 }
695 722
696 SkAutoUnref aur(colorTable); 723 SkAutoUnref aur(colorTable);
697 724
698 // Check ahead of time if the swap(dest, src) is possible. 725 // Check ahead of time if the swap(dest, src) is possible.
699 // If yes, then we will stick to AllocPixelRef since it's cheaper with the s wap happening. 726 // If yes, then we will stick to AllocPixelRef since it's cheaper with the s wap happening.
700 // If no, then we will use alloc to allocate pixels to prevent garbage colle ction. 727 // If no, then we will use alloc to allocate pixels to prevent garbage colle ction.
701 int w = rect.width() / sampleSize; 728 int w = rect.width() / sampleSize;
702 int h = rect.height() / sampleSize; 729 int h = rect.height() / sampleSize;
703 const bool swapOnly = (rect == region) && (w == decodedBitmap.width()) && 730 const bool swapOnly = (rect == region) && (w == decodedBitmap.width()) &&
(...skipping 433 matching lines...) Expand 10 before | Expand all | Expand 10 after
1137 return SkImageDecoder::kUnknown_Format; 1164 return SkImageDecoder::kUnknown_Format;
1138 } 1165 }
1139 1166
1140 SkImageEncoder* sk_libpng_efactory(SkImageEncoder::Type t) { 1167 SkImageEncoder* sk_libpng_efactory(SkImageEncoder::Type t) {
1141 return (SkImageEncoder::kPNG_Type == t) ? SkNEW(SkPNGImageEncoder) : NULL; 1168 return (SkImageEncoder::kPNG_Type == t) ? SkNEW(SkPNGImageEncoder) : NULL;
1142 } 1169 }
1143 1170
1144 static SkTRegistry<SkImageEncoder*, SkImageEncoder::Type> gEReg(sk_libpng_efacto ry); 1171 static SkTRegistry<SkImageEncoder*, SkImageEncoder::Type> gEReg(sk_libpng_efacto ry);
1145 static SkTRegistry<SkImageDecoder::Format, SkStream*> gFormatReg(get_format_png) ; 1172 static SkTRegistry<SkImageDecoder::Format, SkStream*> gFormatReg(get_format_png) ;
1146 static SkTRegistry<SkImageDecoder*, SkStream*> gDReg(sk_libpng_dfactory); 1173 static SkTRegistry<SkImageDecoder*, SkStream*> gDReg(sk_libpng_dfactory);
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698