Index: src/images/SkPNGImageEncoder.cpp |
diff --git a/src/images/SkPNGImageEncoder.cpp b/src/images/SkPNGImageEncoder.cpp |
index 3925f29be7bc90c1ad4ff04827697cb4277dc631..69a53fb2a4671d87eaf7fc2284105c0d84a346b8 100644 |
--- a/src/images/SkPNGImageEncoder.cpp |
+++ b/src/images/SkPNGImageEncoder.cpp |
@@ -103,70 +103,66 @@ static int computeBitDepth(int colorCount) { |
#endif |
} |
-/* Pack palette[] with the corresponding colors, and if hasAlpha is true, also |
- pack trans[] and return the number of trans[] entries written. If hasAlpha |
- is false, the return value will always be 0. |
- |
- Note: this routine takes care of unpremultiplying the RGB values when we |
- have alpha in the colortable, since png doesn't support premul colors |
+/* Pack palette[] with the corresponding colors, and if the image has alpha, also |
+ pack trans[] and return the number of alphas[] entries written. If the image is |
+ opaque, the return value will always be 0. |
*/ |
-static inline int pack_palette(SkColorTable* ctable, |
- png_color* SK_RESTRICT palette, |
- png_byte* SK_RESTRICT trans, SkAlphaType alphaType) { |
- const SkPMColor* SK_RESTRICT colors = ctable ? ctable->readColors() : nullptr; |
- const int ctCount = ctable->count(); |
- int i, num_trans = 0; |
- |
+static inline int pack_palette(SkColorTable* ctable, png_color* SK_RESTRICT palette, |
+ png_byte* SK_RESTRICT alphas, SkAlphaType alphaType) { |
+ const SkPMColor* SK_RESTRICT colors = ctable->readColors(); |
+ const int count = ctable->count(); |
+ int numWithAlpha = 0; |
if (kOpaque_SkAlphaType != alphaType) { |
- /* first see if we have some number of fully opaque at the end of the |
- ctable. PNG allows num_trans < num_palette, but all of the trans |
- entries must come first in the palette. If I was smarter, I'd |
- reorder the indices and ctable so that all non-opaque colors came |
- first in the palette. But, since that would slow down the encode, |
- I'm leaving the indices and ctable order as is, and just looking |
- at the tail of the ctable for opaqueness. |
- */ |
- num_trans = ctCount; |
- for (i = ctCount - 1; i >= 0; --i) { |
- if (SkGetPackedA32(colors[i]) != 0xFF) { |
- break; |
- } |
- num_trans -= 1; |
- } |
- |
- if (kPremul_SkAlphaType == alphaType) { |
- const SkUnPreMultiply::Scale* SK_RESTRICT table = SkUnPreMultiply::GetScaleTable(); |
- for (i = 0; i < num_trans; i++) { |
- const SkPMColor c = *colors++; |
- const unsigned a = SkGetPackedA32(c); |
- const SkUnPreMultiply::Scale s = table[a]; |
- trans[i] = a; |
- palette[i].red = SkUnPreMultiply::ApplyScale(s, SkGetPackedR32(c)); |
- palette[i].green = SkUnPreMultiply::ApplyScale(s,SkGetPackedG32(c)); |
- palette[i].blue = SkUnPreMultiply::ApplyScale(s, SkGetPackedB32(c)); |
+ auto getUnpremulColor = [alphaType](uint8_t color, uint8_t alpha) { |
+ if (kPremul_SkAlphaType == alphaType) { |
+ const SkUnPreMultiply::Scale* table = SkUnPreMultiply::GetScaleTable(); |
+ const SkUnPreMultiply::Scale scale = table[alpha]; |
+ return (uint8_t) SkUnPreMultiply::ApplyScale(scale, color); |
+ } else { |
+ return color; |
} |
- } else { |
- for (i = 0; i < num_trans; i++) { |
- const SkPMColor c = *colors++; |
- trans[i] = SkGetPackedA32(c); |
- palette[i].red = SkGetPackedR32(c); |
- palette[i].green = SkGetPackedG32(c); |
- palette[i].blue = SkGetPackedB32(c); |
+ }; |
+ |
+ // PNG requires that all non-opaque colors come first in the palette. Write these first. |
+ for (int i = 0; i < count; i++) { |
+ uint8_t alpha = SkGetPackedA32(colors[i]); |
+ if (0xFF != alpha) { |
+ alphas[numWithAlpha] = alpha; |
+ palette[numWithAlpha].red = getUnpremulColor(SkGetPackedR32(colors[i]), alpha); |
+ palette[numWithAlpha].green = getUnpremulColor(SkGetPackedG32(colors[i]), alpha); |
+ palette[numWithAlpha].blue = getUnpremulColor(SkGetPackedB32(colors[i]), alpha); |
+ numWithAlpha++; |
} |
} |
- // now fall out of this if-block to use common code for the trailing |
- // opaque entries |
} |
- // these (remaining) entries are opaque |
- for (i = num_trans; i < ctCount; i++) { |
- SkPMColor c = *colors++; |
- palette[i].red = SkGetPackedR32(c); |
- palette[i].green = SkGetPackedG32(c); |
- palette[i].blue = SkGetPackedB32(c); |
+ if (0 == numWithAlpha) { |
+ // All of the entries are opaque. |
+ for (int i = 0; i < count; i++) { |
+ SkPMColor c = *colors++; |
+ palette[i].red = SkGetPackedR32(c); |
+ palette[i].green = SkGetPackedG32(c); |
+ palette[i].blue = SkGetPackedB32(c); |
+ } |
+ } else { |
+ // We have already written the non-opaque colors. Now just write the opaque colors. |
+ int currIndex = numWithAlpha; |
+ int i = 0; |
+ while (currIndex != count) { |
+ uint8_t alpha = SkGetPackedA32(colors[i]); |
+ if (0xFF == alpha) { |
+ palette[currIndex].red = SkGetPackedR32(colors[i]); |
+ palette[currIndex].green = SkGetPackedG32(colors[i]); |
+ palette[currIndex].blue = SkGetPackedB32(colors[i]); |
+ currIndex++; |
+ } |
+ |
+ i++; |
+ } |
} |
- return num_trans; |
+ |
+ return numWithAlpha; |
} |
class SkPNGImageEncoder : public SkImageEncoder { |
@@ -325,6 +321,7 @@ bool SkPNGImageEncoder::doEncode(SkWStream* stream, const SkBitmap& bitmap, |
png_byte trans[256]; |
if (kIndex_8_SkColorType == ct) { |
SkColorTable* colorTable = bitmap.getColorTable(); |
+ SkASSERT(colorTable); |
int numTrans = pack_palette(colorTable, paletteColors, trans, alphaType); |
png_set_PLTE(png_ptr, info_ptr, paletteColors, colorTable->count()); |
if (numTrans > 0) { |