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* SK_RESTRICT pale tte, | |
111 png_byte* SK_RESTRICT alphas, SkAlphaType alphaTy pe) { | |
112 const SkPMColor* SK_RESTRICT 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; |
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. | |
150 int currIndex = numWithAlpha; | |
151 int i = 0; | |
152 while (i < count && currIndex != count) { | |
scroggo
2016/09/12 17:12:48
I don't think you need to check currIndex on each
msarett
2016/09/12 17:17:13
Yeah I wrote that at first. I think the advantage
scroggo
2016/09/12 17:19:44
Ah, so this would let us exit early if for example
| |
153 uint8_t alpha = SkGetPackedA32(colors[i]); | |
154 if (0xFF == alpha) { | |
155 palette[currIndex].red = SkGetPackedR32(colors[i]); | |
156 palette[currIndex].green = SkGetPackedG32(colors[i]); | |
157 palette[currIndex].blue = SkGetPackedB32(colors[i]); | |
158 currIndex++; | |
159 i++; | |
160 } | |
161 } | |
168 } | 162 } |
169 return num_trans; | 163 |
164 return numWithAlpha; | |
170 } | 165 } |
171 | 166 |
172 class SkPNGImageEncoder : public SkImageEncoder { | 167 class SkPNGImageEncoder : public SkImageEncoder { |
173 protected: | 168 protected: |
174 bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) override; | 169 bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) override; |
175 private: | 170 private: |
176 bool doEncode(SkWStream* stream, const SkBitmap& bm, | 171 bool doEncode(SkWStream* stream, const SkBitmap& bm, |
177 SkAlphaType alphaType, int colorType, | 172 SkAlphaType alphaType, int colorType, |
178 int bitDepth, SkColorType ct, | 173 int bitDepth, SkColorType ct, |
179 png_color_8& sig_bit); | 174 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(), | 315 png_set_IHDR(png_ptr, info_ptr, bitmap.width(), bitmap.height(), |
321 bitDepth, colorType, | 316 bitDepth, colorType, |
322 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, | 317 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, |
323 PNG_FILTER_TYPE_BASE); | 318 PNG_FILTER_TYPE_BASE); |
324 | 319 |
325 // set our colortable/trans arrays if needed | 320 // set our colortable/trans arrays if needed |
326 png_color paletteColors[256]; | 321 png_color paletteColors[256]; |
327 png_byte trans[256]; | 322 png_byte trans[256]; |
328 if (kIndex_8_SkColorType == ct) { | 323 if (kIndex_8_SkColorType == ct) { |
329 SkColorTable* ct = bitmap.getColorTable(); | 324 SkColorTable* ct = bitmap.getColorTable(); |
325 SkASSERT(ct); | |
330 int numTrans = pack_palette(ct, paletteColors, trans, alphaType); | 326 int numTrans = pack_palette(ct, paletteColors, trans, alphaType); |
331 png_set_PLTE(png_ptr, info_ptr, paletteColors, ct->count()); | 327 png_set_PLTE(png_ptr, info_ptr, paletteColors, ct->count()); |
332 if (numTrans > 0) { | 328 if (numTrans > 0) { |
333 png_set_tRNS(png_ptr, info_ptr, trans, numTrans, nullptr); | 329 png_set_tRNS(png_ptr, info_ptr, trans, numTrans, nullptr); |
334 } | 330 } |
335 } | 331 } |
336 | 332 |
337 png_set_sBIT(png_ptr, info_ptr, &sig_bit); | 333 png_set_sBIT(png_ptr, info_ptr, &sig_bit); |
338 png_write_info(png_ptr, info_ptr); | 334 png_write_info(png_ptr, info_ptr); |
339 | 335 |
(...skipping 18 matching lines...) Expand all Loading... | |
358 | 354 |
359 /////////////////////////////////////////////////////////////////////////////// | 355 /////////////////////////////////////////////////////////////////////////////// |
360 DEFINE_ENCODER_CREATOR(PNGImageEncoder); | 356 DEFINE_ENCODER_CREATOR(PNGImageEncoder); |
361 /////////////////////////////////////////////////////////////////////////////// | 357 /////////////////////////////////////////////////////////////////////////////// |
362 | 358 |
363 SkImageEncoder* sk_libpng_efactory(SkImageEncoder::Type t) { | 359 SkImageEncoder* sk_libpng_efactory(SkImageEncoder::Type t) { |
364 return (SkImageEncoder::kPNG_Type == t) ? new SkPNGImageEncoder : nullptr; | 360 return (SkImageEncoder::kPNG_Type == t) ? new SkPNGImageEncoder : nullptr; |
365 } | 361 } |
366 | 362 |
367 static SkImageEncoder_EncodeReg gEReg(sk_libpng_efactory); | 363 static SkImageEncoder_EncodeReg gEReg(sk_libpng_efactory); |
OLD | NEW |