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

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

Issue 1836493002: Rename encoders to Sk*ImageEncoder (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Created 4 years, 9 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
« no previous file with comments | « src/images/SkImageDecoder_libjpeg.cpp ('k') | src/images/SkImageDecoder_libwebp.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright 2006 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "SkImageEncoder.h"
9 #include "SkColor.h"
10 #include "SkColorPriv.h"
11 #include "SkDither.h"
12 #include "SkMath.h"
13 #include "SkRTConf.h"
14 #include "SkStream.h"
15 #include "SkTemplates.h"
16 #include "SkUtils.h"
17 #include "transform_scanline.h"
18
19 #include "png.h"
20
21 /* These were dropped in libpng >= 1.4 */
22 #ifndef png_infopp_NULL
23 #define png_infopp_NULL nullptr
24 #endif
25
26 #ifndef png_bytepp_NULL
27 #define png_bytepp_NULL nullptr
28 #endif
29
30 #ifndef int_p_NULL
31 #define int_p_NULL nullptr
32 #endif
33
34 #ifndef png_flush_ptr_NULL
35 #define png_flush_ptr_NULL nullptr
36 #endif
37
38 #define DEFAULT_FOR_SUPPRESS_PNG_IMAGE_DECODER_WARNINGS true
39 SK_CONF_DECLARE(bool, c_suppressPNGImageDecoderWarnings,
40 "images.png.suppressDecoderWarnings",
41 DEFAULT_FOR_SUPPRESS_PNG_IMAGE_DECODER_WARNINGS,
42 "Suppress most PNG warnings when calling image decode "
43 "functions.");
44
45 ///////////////////////////////////////////////////////////////////////////////
46
47 #include "SkColorPriv.h"
48 #include "SkUnPreMultiply.h"
49
50 static void sk_error_fn(png_structp png_ptr, png_const_charp msg) {
51 if (!c_suppressPNGImageDecoderWarnings) {
52 SkDEBUGF(("------ png error %s\n", msg));
53 }
54 longjmp(png_jmpbuf(png_ptr), 1);
55 }
56
57 static void sk_write_fn(png_structp png_ptr, png_bytep data, png_size_t len) {
58 SkWStream* sk_stream = (SkWStream*)png_get_io_ptr(png_ptr);
59 if (!sk_stream->write(data, len)) {
60 png_error(png_ptr, "sk_write_fn Error!");
61 }
62 }
63
64 static transform_scanline_proc choose_proc(SkColorType ct, bool hasAlpha) {
65 // we don't care about search on alpha if we're kIndex8, since only the
66 // colortable packing cares about that distinction, not the pixels
67 if (kIndex_8_SkColorType == ct) {
68 hasAlpha = false; // we store false in the table entries for kIndex8
69 }
70
71 static const struct {
72 SkColorType fColorType;
73 bool fHasAlpha;
74 transform_scanline_proc fProc;
75 } gMap[] = {
76 { kRGB_565_SkColorType, false, transform_scanline_565 },
77 { kN32_SkColorType, false, transform_scanline_888 },
78 { kN32_SkColorType, true, transform_scanline_8888 },
79 { kARGB_4444_SkColorType, false, transform_scanline_444 },
80 { kARGB_4444_SkColorType, true, transform_scanline_4444 },
81 { kIndex_8_SkColorType, false, transform_scanline_memcpy },
82 };
83
84 for (int i = SK_ARRAY_COUNT(gMap) - 1; i >= 0; --i) {
85 if (gMap[i].fColorType == ct && gMap[i].fHasAlpha == hasAlpha) {
86 return gMap[i].fProc;
87 }
88 }
89 sk_throw();
90 return nullptr;
91 }
92
93 // return the minimum legal bitdepth (by png standards) for this many colortable
94 // entries. SkBitmap always stores in 8bits per pixel, but for colorcount <= 16,
95 // we can use fewer bits per in png
96 static int computeBitDepth(int colorCount) {
97 #if 0
98 int bits = SkNextLog2(colorCount);
99 SkASSERT(bits >= 1 && bits <= 8);
100 // now we need bits itself to be a power of 2 (e.g. 1, 2, 4, 8)
101 return SkNextPow2(bits);
102 #else
103 // for the moment, we don't know how to pack bitdepth < 8
104 return 8;
105 #endif
106 }
107
108 /* Pack palette[] with the corresponding colors, and if hasAlpha is true, also
109 pack trans[] and return the number of trans[] entries written. If hasAlpha
110 is false, the return value will always be 0.
111
112 Note: this routine takes care of unpremultiplying the RGB values when we
113 have alpha in the colortable, since png doesn't support premul colors
114 */
115 static inline int pack_palette(SkColorTable* ctable,
116 png_color* SK_RESTRICT palette,
117 png_byte* SK_RESTRICT trans, bool hasAlpha) {
118 const SkPMColor* SK_RESTRICT colors = ctable ? ctable->readColors() : nullpt r;
119 const int ctCount = ctable->count();
120 int i, num_trans = 0;
121
122 if (hasAlpha) {
123 /* first see if we have some number of fully opaque at the end of the
124 ctable. PNG allows num_trans < num_palette, but all of the trans
125 entries must come first in the palette. If I was smarter, I'd
126 reorder the indices and ctable so that all non-opaque colors came
127 first in the palette. But, since that would slow down the encode,
128 I'm leaving the indices and ctable order as is, and just looking
129 at the tail of the ctable for opaqueness.
130 */
131 num_trans = ctCount;
132 for (i = ctCount - 1; i >= 0; --i) {
133 if (SkGetPackedA32(colors[i]) != 0xFF) {
134 break;
135 }
136 num_trans -= 1;
137 }
138
139 const SkUnPreMultiply::Scale* SK_RESTRICT table =
140 SkUnPreMultiply::GetScaleTable();
141
142 for (i = 0; i < num_trans; i++) {
143 const SkPMColor c = *colors++;
144 const unsigned a = SkGetPackedA32(c);
145 const SkUnPreMultiply::Scale s = table[a];
146 trans[i] = a;
147 palette[i].red = SkUnPreMultiply::ApplyScale(s, SkGetPackedR32(c));
148 palette[i].green = SkUnPreMultiply::ApplyScale(s,SkGetPackedG32(c));
149 palette[i].blue = SkUnPreMultiply::ApplyScale(s, SkGetPackedB32(c));
150 }
151 // now fall out of this if-block to use common code for the trailing
152 // opaque entries
153 }
154
155 // these (remaining) entries are opaque
156 for (i = num_trans; i < ctCount; i++) {
157 SkPMColor c = *colors++;
158 palette[i].red = SkGetPackedR32(c);
159 palette[i].green = SkGetPackedG32(c);
160 palette[i].blue = SkGetPackedB32(c);
161 }
162 return num_trans;
163 }
164
165 class SkPNGImageEncoder : public SkImageEncoder {
166 protected:
167 bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) override;
168 private:
169 bool doEncode(SkWStream* stream, const SkBitmap& bm,
170 const bool& hasAlpha, int colorType,
171 int bitDepth, SkColorType ct,
172 png_color_8& sig_bit);
173
174 typedef SkImageEncoder INHERITED;
175 };
176
177 bool SkPNGImageEncoder::onEncode(SkWStream* stream,
178 const SkBitmap& originalBitmap,
179 int /*quality*/) {
180 SkBitmap copy;
181 const SkBitmap* bitmap = &originalBitmap;
182 switch (originalBitmap.colorType()) {
183 case kIndex_8_SkColorType:
184 case kN32_SkColorType:
185 case kARGB_4444_SkColorType:
186 case kRGB_565_SkColorType:
187 break;
188 default:
189 // TODO(scroggo): support 8888-but-not-N32 natively.
190 // TODO(scroggo): support kGray_8 directly.
191 // TODO(scroggo): support Alpha_8 as Grayscale(black)+Alpha
192 if (originalBitmap.copyTo(&copy, kN32_SkColorType)) {
193 bitmap = &copy;
194 }
195 }
196 SkColorType ct = bitmap->colorType();
197
198 const bool hasAlpha = !bitmap->isOpaque();
199 int colorType = PNG_COLOR_MASK_COLOR;
200 int bitDepth = 8; // default for color
201 png_color_8 sig_bit;
202
203 switch (ct) {
204 case kIndex_8_SkColorType:
205 colorType |= PNG_COLOR_MASK_PALETTE;
206 // fall through to the ARGB_8888 case
207 case kN32_SkColorType:
208 sig_bit.red = 8;
209 sig_bit.green = 8;
210 sig_bit.blue = 8;
211 sig_bit.alpha = 8;
212 break;
213 case kARGB_4444_SkColorType:
214 sig_bit.red = 4;
215 sig_bit.green = 4;
216 sig_bit.blue = 4;
217 sig_bit.alpha = 4;
218 break;
219 case kRGB_565_SkColorType:
220 sig_bit.red = 5;
221 sig_bit.green = 6;
222 sig_bit.blue = 5;
223 sig_bit.alpha = 0;
224 break;
225 default:
226 return false;
227 }
228
229 if (hasAlpha) {
230 // don't specify alpha if we're a palette, even if our ctable has alpha
231 if (!(colorType & PNG_COLOR_MASK_PALETTE)) {
232 colorType |= PNG_COLOR_MASK_ALPHA;
233 }
234 } else {
235 sig_bit.alpha = 0;
236 }
237
238 SkAutoLockPixels alp(*bitmap);
239 // readyToDraw checks for pixels (and colortable if that is required)
240 if (!bitmap->readyToDraw()) {
241 return false;
242 }
243
244 // we must do this after we have locked the pixels
245 SkColorTable* ctable = bitmap->getColorTable();
246 if (ctable) {
247 if (ctable->count() == 0) {
248 return false;
249 }
250 // check if we can store in fewer than 8 bits
251 bitDepth = computeBitDepth(ctable->count());
252 }
253
254 return doEncode(stream, *bitmap, hasAlpha, colorType, bitDepth, ct, sig_bit) ;
255 }
256
257 bool SkPNGImageEncoder::doEncode(SkWStream* stream, const SkBitmap& bitmap,
258 const bool& hasAlpha, int colorType,
259 int bitDepth, SkColorType ct,
260 png_color_8& sig_bit) {
261
262 png_structp png_ptr;
263 png_infop info_ptr;
264
265 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, sk_error_f n,
266 nullptr);
267 if (nullptr == png_ptr) {
268 return false;
269 }
270
271 info_ptr = png_create_info_struct(png_ptr);
272 if (nullptr == info_ptr) {
273 png_destroy_write_struct(&png_ptr, png_infopp_NULL);
274 return false;
275 }
276
277 /* Set error handling. REQUIRED if you aren't supplying your own
278 * error handling functions in the png_create_write_struct() call.
279 */
280 if (setjmp(png_jmpbuf(png_ptr))) {
281 png_destroy_write_struct(&png_ptr, &info_ptr);
282 return false;
283 }
284
285 png_set_write_fn(png_ptr, (void*)stream, sk_write_fn, png_flush_ptr_NULL);
286
287 /* Set the image information here. Width and height are up to 2^31,
288 * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
289 * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
290 * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
291 * or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or
292 * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
293 * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED
294 */
295
296 png_set_IHDR(png_ptr, info_ptr, bitmap.width(), bitmap.height(),
297 bitDepth, colorType,
298 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE,
299 PNG_FILTER_TYPE_BASE);
300
301 // set our colortable/trans arrays if needed
302 png_color paletteColors[256];
303 png_byte trans[256];
304 if (kIndex_8_SkColorType == ct) {
305 SkColorTable* ct = bitmap.getColorTable();
306 int numTrans = pack_palette(ct, paletteColors, trans, hasAlpha);
307 png_set_PLTE(png_ptr, info_ptr, paletteColors, ct->count());
308 if (numTrans > 0) {
309 png_set_tRNS(png_ptr, info_ptr, trans, numTrans, nullptr);
310 }
311 }
312 #ifdef PNG_sBIT_SUPPORTED
313 png_set_sBIT(png_ptr, info_ptr, &sig_bit);
314 #endif
315 png_write_info(png_ptr, info_ptr);
316
317 const char* srcImage = (const char*)bitmap.getPixels();
318 SkAutoSTMalloc<1024, char> rowStorage(bitmap.width() << 2);
319 char* storage = rowStorage.get();
320 transform_scanline_proc proc = choose_proc(ct, hasAlpha);
321
322 for (int y = 0; y < bitmap.height(); y++) {
323 png_bytep row_ptr = (png_bytep)storage;
324 proc(srcImage, bitmap.width(), storage);
325 png_write_rows(png_ptr, &row_ptr, 1);
326 srcImage += bitmap.rowBytes();
327 }
328
329 png_write_end(png_ptr, info_ptr);
330
331 /* clean up after the write, and free any memory allocated */
332 png_destroy_write_struct(&png_ptr, &info_ptr);
333 return true;
334 }
335
336 ///////////////////////////////////////////////////////////////////////////////
337 DEFINE_ENCODER_CREATOR(PNGImageEncoder);
338 ///////////////////////////////////////////////////////////////////////////////
339
340 SkImageEncoder* sk_libpng_efactory(SkImageEncoder::Type t) {
341 return (SkImageEncoder::kPNG_Type == t) ? new SkPNGImageEncoder : nullptr;
342 }
343
344 static SkImageEncoder_EncodeReg gEReg(sk_libpng_efactory);
OLDNEW
« no previous file with comments | « src/images/SkImageDecoder_libjpeg.cpp ('k') | src/images/SkImageDecoder_libwebp.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698