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 (currIndex != count) { |
| 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 } |
| 160 |
| 161 i++; |
| 162 } |
168 } | 163 } |
169 return num_trans; | 164 |
| 165 return numWithAlpha; |
170 } | 166 } |
171 | 167 |
172 class SkPNGImageEncoder : public SkImageEncoder { | 168 class SkPNGImageEncoder : public SkImageEncoder { |
173 protected: | 169 protected: |
174 bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) override; | 170 bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) override; |
175 private: | 171 private: |
176 bool doEncode(SkWStream* stream, const SkBitmap& bm, | 172 bool doEncode(SkWStream* stream, const SkBitmap& bm, |
177 SkAlphaType alphaType, int colorType, | 173 SkAlphaType alphaType, int colorType, |
178 int bitDepth, SkColorType ct, | 174 int bitDepth, SkColorType ct, |
179 png_color_8& sig_bit); | 175 png_color_8& sig_bit); |
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
318 png_set_IHDR(png_ptr, info_ptr, bitmap.width(), bitmap.height(), | 314 png_set_IHDR(png_ptr, info_ptr, bitmap.width(), bitmap.height(), |
319 bitDepth, colorType, | 315 bitDepth, colorType, |
320 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, | 316 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, |
321 PNG_FILTER_TYPE_BASE); | 317 PNG_FILTER_TYPE_BASE); |
322 | 318 |
323 // set our colortable/trans arrays if needed | 319 // set our colortable/trans arrays if needed |
324 png_color paletteColors[256]; | 320 png_color paletteColors[256]; |
325 png_byte trans[256]; | 321 png_byte trans[256]; |
326 if (kIndex_8_SkColorType == ct) { | 322 if (kIndex_8_SkColorType == ct) { |
327 SkColorTable* colorTable = bitmap.getColorTable(); | 323 SkColorTable* colorTable = bitmap.getColorTable(); |
| 324 SkASSERT(colorTable); |
328 int numTrans = pack_palette(colorTable, paletteColors, trans, alphaType)
; | 325 int numTrans = pack_palette(colorTable, paletteColors, trans, alphaType)
; |
329 png_set_PLTE(png_ptr, info_ptr, paletteColors, colorTable->count()); | 326 png_set_PLTE(png_ptr, info_ptr, paletteColors, colorTable->count()); |
330 if (numTrans > 0) { | 327 if (numTrans > 0) { |
331 png_set_tRNS(png_ptr, info_ptr, trans, numTrans, nullptr); | 328 png_set_tRNS(png_ptr, info_ptr, trans, numTrans, nullptr); |
332 } | 329 } |
333 } | 330 } |
334 | 331 |
335 png_set_sBIT(png_ptr, info_ptr, &sig_bit); | 332 png_set_sBIT(png_ptr, info_ptr, &sig_bit); |
336 png_write_info(png_ptr, info_ptr); | 333 png_write_info(png_ptr, info_ptr); |
337 | 334 |
(...skipping 18 matching lines...) Expand all Loading... |
356 | 353 |
357 /////////////////////////////////////////////////////////////////////////////// | 354 /////////////////////////////////////////////////////////////////////////////// |
358 DEFINE_ENCODER_CREATOR(PNGImageEncoder); | 355 DEFINE_ENCODER_CREATOR(PNGImageEncoder); |
359 /////////////////////////////////////////////////////////////////////////////// | 356 /////////////////////////////////////////////////////////////////////////////// |
360 | 357 |
361 SkImageEncoder* sk_libpng_efactory(SkImageEncoder::Type t) { | 358 SkImageEncoder* sk_libpng_efactory(SkImageEncoder::Type t) { |
362 return (SkImageEncoder::kPNG_Type == t) ? new SkPNGImageEncoder : nullptr; | 359 return (SkImageEncoder::kPNG_Type == t) ? new SkPNGImageEncoder : nullptr; |
363 } | 360 } |
364 | 361 |
365 static SkImageEncoder_EncodeReg gEReg(sk_libpng_efactory); | 362 static SkImageEncoder_EncodeReg gEReg(sk_libpng_efactory); |
OLD | NEW |