OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright 2006 The Android Open Source Project | 2 * Copyright 2006 The Android Open Source Project |
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 "SkImageEncoder.h" | 8 #include "SkImageEncoder.h" |
9 #include "SkColor.h" | 9 #include "SkColor.h" |
10 #include "SkColorPriv.h" | 10 #include "SkColorPriv.h" |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
96 int bits = SkNextLog2(colorCount); | 96 int bits = SkNextLog2(colorCount); |
97 SkASSERT(bits >= 1 && bits <= 8); | 97 SkASSERT(bits >= 1 && bits <= 8); |
98 // now we need bits itself to be a power of 2 (e.g. 1, 2, 4, 8) | 98 // now we need bits itself to be a power of 2 (e.g. 1, 2, 4, 8) |
99 return SkNextPow2(bits); | 99 return SkNextPow2(bits); |
100 #else | 100 #else |
101 // for the moment, we don't know how to pack bitdepth < 8 | 101 // for the moment, we don't know how to pack bitdepth < 8 |
102 return 8; | 102 return 8; |
103 #endif | 103 #endif |
104 } | 104 } |
105 | 105 |
106 /* Pack palette[] with the corresponding colors, and if hasAlpha is true, also | 106 /* Pack palette[] with the corresponding colors, and if the image has alpha, al so |
107 pack trans[] and return the number of trans[] entries written. If hasAlpha | 107 pack trans[] and return the number of alphas[] entries written. If the image is |
108 is false, the return value will always be 0. | 108 opaque, the return value will always be 0. |
109 */ | |
110 static inline int pack_palette(SkColorTable* ctable, png_color* palette, png_byt e* alphas, | |
111 SkAlphaType alphaType) { | |
112 const SkPMColor* colors = ctable->readColors(); | |
113 const int count = ctable->count(); | |
114 int numWithAlpha = 0; | |
115 if (kOpaque_SkAlphaType != alphaType) { | |
116 auto getUnpremulColor = [alphaType](uint8_t color, uint8_t alpha) { | |
117 if (kPremul_SkAlphaType == alphaType) { | |
118 const SkUnPreMultiply::Scale* table = SkUnPreMultiply::GetScaleT able(); | |
119 const SkUnPreMultiply::Scale scale = table[alpha]; | |
120 return (uint8_t) SkUnPreMultiply::ApplyScale(scale, color); | |
121 } else { | |
122 return color; | |
123 } | |
124 }; | |
109 | 125 |
110 Note: this routine takes care of unpremultiplying the RGB values when we | 126 // PNG requires that all non-opaque colors come first in the palette. W rite these first. |
111 have alpha in the colortable, since png doesn't support premul colors | 127 for (int i = 0; i < count; i++) { |
112 */ | 128 uint8_t alpha = SkGetPackedA32(colors[i]); |
113 static inline int pack_palette(SkColorTable* ctable, | 129 if (0xFF != alpha) { |
114 png_color* SK_RESTRICT palette, | 130 alphas[numWithAlpha] = alpha; |
scroggo
2016/09/12 16:40:57
Why did you remove SK_RESTRICT?
msarett
2016/09/12 16:58:31
SK_RESTRICT can sometimes allow the compiler to ma
| |
115 png_byte* SK_RESTRICT trans, SkAlphaType alphaTyp e) { | 131 palette[numWithAlpha].red = getUnpremulColor(SkGetPackedR32(co lors[i]), alpha); |
116 const SkPMColor* SK_RESTRICT colors = ctable ? ctable->readColors() : nullpt r; | 132 palette[numWithAlpha].green = getUnpremulColor(SkGetPackedG32(co lors[i]), alpha); |
117 const int ctCount = ctable->count(); | 133 palette[numWithAlpha].blue = getUnpremulColor(SkGetPackedB32(co lors[i]), alpha); |
118 int i, num_trans = 0; | 134 numWithAlpha++; |
119 | |
120 if (kOpaque_SkAlphaType != alphaType) { | |
121 /* first see if we have some number of fully opaque at the end of the | |
122 ctable. PNG allows num_trans < num_palette, but all of the trans | |
123 entries must come first in the palette. If I was smarter, I'd | |
124 reorder the indices and ctable so that all non-opaque colors came | |
125 first in the palette. But, since that would slow down the encode, | |
126 I'm leaving the indices and ctable order as is, and just looking | |
127 at the tail of the ctable for opaqueness. | |
128 */ | |
129 num_trans = ctCount; | |
130 for (i = ctCount - 1; i >= 0; --i) { | |
131 if (SkGetPackedA32(colors[i]) != 0xFF) { | |
132 break; | |
133 } | |
134 num_trans -= 1; | |
135 } | |
136 | |
137 if (kPremul_SkAlphaType == alphaType) { | |
138 const SkUnPreMultiply::Scale* SK_RESTRICT table = SkUnPreMultiply::G etScaleTable(); | |
139 for (i = 0; i < num_trans; i++) { | |
140 const SkPMColor c = *colors++; | |
141 const unsigned a = SkGetPackedA32(c); | |
142 const SkUnPreMultiply::Scale s = table[a]; | |
143 trans[i] = a; | |
144 palette[i].red = SkUnPreMultiply::ApplyScale(s, SkGetPackedR32(c )); | |
145 palette[i].green = SkUnPreMultiply::ApplyScale(s,SkGetPackedG32( c)); | |
146 palette[i].blue = SkUnPreMultiply::ApplyScale(s, SkGetPackedB32( c)); | |
147 } | |
148 } else { | |
149 for (i = 0; i < num_trans; i++) { | |
150 const SkPMColor c = *colors++; | |
151 trans[i] = SkGetPackedA32(c); | |
152 palette[i].red = SkGetPackedR32(c); | |
153 palette[i].green = SkGetPackedG32(c); | |
154 palette[i].blue = SkGetPackedB32(c); | |
155 } | 135 } |
156 } | 136 } |
157 | 137 |
158 // now fall out of this if-block to use common code for the trailing | |
159 // opaque entries | |
160 } | 138 } |
161 | 139 |
162 // these (remaining) entries are opaque | 140 if (0 == numWithAlpha) { |
163 for (i = num_trans; i < ctCount; i++) { | 141 // All of the entries are opaque. |
164 SkPMColor c = *colors++; | 142 for (int i = 0; i < count; i++) { |
165 palette[i].red = SkGetPackedR32(c); | 143 SkPMColor c = *colors++; |
166 palette[i].green = SkGetPackedG32(c); | 144 palette[i].red = SkGetPackedR32(c); |
167 palette[i].blue = SkGetPackedB32(c); | 145 palette[i].green = SkGetPackedG32(c); |
146 palette[i].blue = SkGetPackedB32(c); | |
147 } | |
148 } else { | |
149 // We have already written the non-opaque colors. Now just write the op aque colors. | |
scroggo
2016/09/12 16:40:57
I think you could skip this if numWithAlpha == cou
msarett
2016/09/12 16:58:31
Yes nice catch, let's skip it.
| |
150 int currIndex = numWithAlpha; | |
151 for (int i = 0; i < count; i++) { | |
152 uint8_t alpha = SkGetPackedA32(colors[i]); | |
153 if (0xFF == alpha) { | |
154 palette[currIndex].red = SkGetPackedR32(colors[i]); | |
155 palette[currIndex].green = SkGetPackedG32(colors[i]); | |
156 palette[currIndex].blue = SkGetPackedB32(colors[i]); | |
157 currIndex++; | |
158 } | |
159 } | |
168 } | 160 } |
169 return num_trans; | 161 |
162 return numWithAlpha; | |
170 } | 163 } |
171 | 164 |
172 class SkPNGImageEncoder : public SkImageEncoder { | 165 class SkPNGImageEncoder : public SkImageEncoder { |
173 protected: | 166 protected: |
174 bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) override; | 167 bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) override; |
175 private: | 168 private: |
176 bool doEncode(SkWStream* stream, const SkBitmap& bm, | 169 bool doEncode(SkWStream* stream, const SkBitmap& bm, |
177 SkAlphaType alphaType, int colorType, | 170 SkAlphaType alphaType, int colorType, |
178 int bitDepth, SkColorType ct, | 171 int bitDepth, SkColorType ct, |
179 png_color_8& sig_bit); | 172 png_color_8& sig_bit); |
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
320 png_set_IHDR(png_ptr, info_ptr, bitmap.width(), bitmap.height(), | 313 png_set_IHDR(png_ptr, info_ptr, bitmap.width(), bitmap.height(), |
321 bitDepth, colorType, | 314 bitDepth, colorType, |
322 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, | 315 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, |
323 PNG_FILTER_TYPE_BASE); | 316 PNG_FILTER_TYPE_BASE); |
324 | 317 |
325 // set our colortable/trans arrays if needed | 318 // set our colortable/trans arrays if needed |
326 png_color paletteColors[256]; | 319 png_color paletteColors[256]; |
327 png_byte trans[256]; | 320 png_byte trans[256]; |
328 if (kIndex_8_SkColorType == ct) { | 321 if (kIndex_8_SkColorType == ct) { |
329 SkColorTable* ct = bitmap.getColorTable(); | 322 SkColorTable* ct = bitmap.getColorTable(); |
323 SkASSERT(ct); | |
330 int numTrans = pack_palette(ct, paletteColors, trans, alphaType); | 324 int numTrans = pack_palette(ct, paletteColors, trans, alphaType); |
331 png_set_PLTE(png_ptr, info_ptr, paletteColors, ct->count()); | 325 png_set_PLTE(png_ptr, info_ptr, paletteColors, ct->count()); |
332 if (numTrans > 0) { | 326 if (numTrans > 0) { |
333 png_set_tRNS(png_ptr, info_ptr, trans, numTrans, nullptr); | 327 png_set_tRNS(png_ptr, info_ptr, trans, numTrans, nullptr); |
334 } | 328 } |
335 } | 329 } |
336 | 330 |
337 png_set_sBIT(png_ptr, info_ptr, &sig_bit); | 331 png_set_sBIT(png_ptr, info_ptr, &sig_bit); |
338 png_write_info(png_ptr, info_ptr); | 332 png_write_info(png_ptr, info_ptr); |
339 | 333 |
(...skipping 18 matching lines...) Expand all Loading... | |
358 | 352 |
359 /////////////////////////////////////////////////////////////////////////////// | 353 /////////////////////////////////////////////////////////////////////////////// |
360 DEFINE_ENCODER_CREATOR(PNGImageEncoder); | 354 DEFINE_ENCODER_CREATOR(PNGImageEncoder); |
361 /////////////////////////////////////////////////////////////////////////////// | 355 /////////////////////////////////////////////////////////////////////////////// |
362 | 356 |
363 SkImageEncoder* sk_libpng_efactory(SkImageEncoder::Type t) { | 357 SkImageEncoder* sk_libpng_efactory(SkImageEncoder::Type t) { |
364 return (SkImageEncoder::kPNG_Type == t) ? new SkPNGImageEncoder : nullptr; | 358 return (SkImageEncoder::kPNG_Type == t) ? new SkPNGImageEncoder : nullptr; |
365 } | 359 } |
366 | 360 |
367 static SkImageEncoder_EncodeReg gEReg(sk_libpng_efactory); | 361 static SkImageEncoder_EncodeReg gEReg(sk_libpng_efactory); |
OLD | NEW |