blob: 02d8135f1fd26c8e229a3792f103efca588c7647 [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/* libs/graphics/images/SkImageDecoder_libpng.cpp
2**
3** Copyright 2006, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9** http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18#include "SkImageDecoder.h"
reed@android.comb08eb2b2009-01-06 20:16:26 +000019#include "SkImageEncoder.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000020#include "SkColor.h"
21#include "SkColorPriv.h"
22#include "SkDither.h"
23#include "SkMath.h"
24#include "SkScaledBitmapSampler.h"
25#include "SkStream.h"
26#include "SkTemplates.h"
27#include "SkUtils.h"
28
29extern "C" {
30#include "png.h"
31}
32
33class SkPNGImageDecoder : public SkImageDecoder {
34public:
35 virtual Format getFormat() const {
36 return kPNG_Format;
37 }
38
39protected:
40 virtual bool onDecode(SkStream* stream, SkBitmap* bm,
41 SkBitmap::Config pref, Mode);
42};
43
44#ifndef png_jmpbuf
45# define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
46#endif
47
48#define PNG_BYTES_TO_CHECK 4
49
50/* Automatically clean up after throwing an exception */
51struct PNGAutoClean {
52 PNGAutoClean(png_structp p, png_infop i): png_ptr(p), info_ptr(i) {}
53 ~PNGAutoClean() {
54 png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
55 }
56private:
57 png_structp png_ptr;
58 png_infop info_ptr;
59};
60
61SkImageDecoder* SkImageDecoder_PNG_Factory(SkStream* stream) {
62 char buf[PNG_BYTES_TO_CHECK];
63 if (stream->read(buf, PNG_BYTES_TO_CHECK) == PNG_BYTES_TO_CHECK &&
64 !png_sig_cmp((png_bytep) buf, (png_size_t)0, PNG_BYTES_TO_CHECK)) {
65 return SkNEW(SkPNGImageDecoder);
66 }
67 return NULL;
68}
69
70static void sk_read_fn(png_structp png_ptr, png_bytep data, png_size_t length) {
71 SkStream* sk_stream = (SkStream*) png_ptr->io_ptr;
72 size_t bytes = sk_stream->read(data, length);
73 if (bytes != length) {
74 png_error(png_ptr, "Read Error!");
75 }
76}
77
78static int sk_read_user_chunk(png_structp png_ptr, png_unknown_chunkp chunk) {
79 SkImageDecoder::Peeker* peeker =
80 (SkImageDecoder::Peeker*)png_get_user_chunk_ptr(png_ptr);
81 // peek() returning true means continue decoding
82 return peeker->peek((const char*)chunk->name, chunk->data, chunk->size) ?
83 1 : -1;
84}
85
86static void sk_error_fn(png_structp png_ptr, png_const_charp msg) {
87#if 0
88 SkDebugf("------ png error %s\n", msg);
89#endif
90 longjmp(png_jmpbuf(png_ptr), 1);
91}
92
93static void skip_src_rows(png_structp png_ptr, uint8_t storage[], int count) {
94 for (int i = 0; i < count; i++) {
95 uint8_t* tmp = storage;
96 png_read_rows(png_ptr, &tmp, png_bytepp_NULL, 1);
97 }
98}
99
100static bool pos_le(int value, int max) {
101 return value > 0 && value <= max;
102}
103
104static bool substituteTranspColor(SkBitmap* bm, SkPMColor match) {
105 SkASSERT(bm->config() == SkBitmap::kARGB_8888_Config);
106
107 bool reallyHasAlpha = false;
108
109 for (int y = bm->height() - 1; y >= 0; --y) {
110 SkPMColor* p = bm->getAddr32(0, y);
111 for (int x = bm->width() - 1; x >= 0; --x) {
112 if (match == *p) {
113 *p = 0;
114 reallyHasAlpha = true;
115 }
116 p += 1;
117 }
118 }
119 return reallyHasAlpha;
120}
121
122bool SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* decodedBitmap,
123 SkBitmap::Config prefConfig, Mode mode) {
124// SkAutoTrace apr("SkPNGImageDecoder::onDecode");
125
126 /* Create and initialize the png_struct with the desired error handler
127 * functions. If you want to use the default stderr and longjump method,
128 * you can supply NULL for the last three parameters. We also supply the
129 * the compiler header file version, so that we know if the application
130 * was compiled with a compatible version of the library. */
131 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
132 NULL, sk_error_fn, NULL);
133 // png_voidp user_error_ptr, user_error_fn, user_warning_fn);
134 if (png_ptr == NULL) {
135 return false;
136 }
137
138 /* Allocate/initialize the memory for image information. */
139 png_infop info_ptr = png_create_info_struct(png_ptr);
140 if (info_ptr == NULL) {
141 png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL);
142 return false;
143 }
144
145 PNGAutoClean autoClean(png_ptr, info_ptr);
146
147 /* Set error handling if you are using the setjmp/longjmp method (this is
148 * the normal method of doing things with libpng). REQUIRED unless you
149 * set up your own error handlers in the png_create_read_struct() earlier.
150 */
151 if (setjmp(png_jmpbuf(png_ptr))) {
152 return false;
153 }
154
155 /* If you are using replacement read functions, instead of calling
156 * png_init_io() here you would call:
157 */
158 png_set_read_fn(png_ptr, (void *)sk_stream, sk_read_fn);
159 /* where user_io_ptr is a structure you want available to the callbacks */
160 /* If we have already read some of the signature */
161// png_set_sig_bytes(png_ptr, 0 /* sig_read */ );
162
163 // hookup our peeker so we can see any user-chunks the caller may be interested in
164 png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*)"", 0);
165 if (this->getPeeker()) {
166 png_set_read_user_chunk_fn(png_ptr, (png_voidp)this->getPeeker(), sk_read_user_chunk);
167 }
168
169 /* The call to png_read_info() gives us all of the information from the
170 * PNG file before the first IDAT (image data chunk). */
171 png_read_info(png_ptr, info_ptr);
172 png_uint_32 origWidth, origHeight;
173 int bit_depth, color_type, interlace_type;
174 png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bit_depth, &color_type,
175 &interlace_type, int_p_NULL, int_p_NULL);
176
177 /* tell libpng to strip 16 bit/color files down to 8 bits/color */
178 if (bit_depth == 16) {
179 png_set_strip_16(png_ptr);
180 }
181 /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single
182 * byte into separate bytes (useful for paletted and grayscale images). */
183 if (bit_depth < 8) {
184 png_set_packing(png_ptr);
185 }
186 /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */
187 if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) {
188 png_set_gray_1_2_4_to_8(png_ptr);
189 }
190
191 /* Make a grayscale image into RGB. */
192 if (color_type == PNG_COLOR_TYPE_GRAY ||
193 color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
194 png_set_gray_to_rgb(png_ptr);
195 }
196
197 SkBitmap::Config config;
198 bool hasAlpha = false;
199 bool doDither = this->getDitherImage();
200 SkPMColor theTranspColor = 0; // 0 tells us not to try to match
201
202 // check for sBIT chunk data, in case we should disable dithering because
203 // our data is not truely 8bits per component
204 if (doDither) {
205#if 0
206 SkDebugf("----- sBIT %d %d %d %d\n", info_ptr->sig_bit.red,
207 info_ptr->sig_bit.green, info_ptr->sig_bit.blue,
208 info_ptr->sig_bit.alpha);
209#endif
210 // 0 seems to indicate no information available
211 if (pos_le(info_ptr->sig_bit.red, SK_R16_BITS) &&
212 pos_le(info_ptr->sig_bit.green, SK_G16_BITS) &&
213 pos_le(info_ptr->sig_bit.blue, SK_B16_BITS)) {
214 doDither = false;
215 }
216 }
217
218 if (color_type == PNG_COLOR_TYPE_PALETTE) {
219 config = SkBitmap::kIndex8_Config; // defer sniffing for hasAlpha
220 } else {
221 png_color_16p transpColor = NULL;
222 int numTransp = 0;
223
224 png_get_tRNS(png_ptr, info_ptr, NULL, &numTransp, &transpColor);
225
226 bool valid = png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS);
227
228 if (valid && numTransp == 1 && transpColor != NULL) {
229 /* Compute our transparent color, which we'll match against later.
230 We don't really handle 16bit components properly here, since we
231 do our compare *after* the values have been knocked down to 8bit
232 which means we will find more matches than we should. The real
233 fix seems to be to see the actual 16bit components, do the
234 compare, and then knock it down to 8bits ourselves.
235 */
236 if (color_type & PNG_COLOR_MASK_COLOR) {
237 if (16 == bit_depth) {
238 theTranspColor = SkPackARGB32(0xFF, transpColor->red >> 8,
239 transpColor->green >> 8, transpColor->blue >> 8);
240 } else {
241 theTranspColor = SkPackARGB32(0xFF, transpColor->red,
242 transpColor->green, transpColor->blue);
243 }
244 } else { // gray
245 if (16 == bit_depth) {
246 theTranspColor = SkPackARGB32(0xFF, transpColor->gray >> 8,
247 transpColor->gray >> 8, transpColor->gray >> 8);
248 } else {
249 theTranspColor = SkPackARGB32(0xFF, transpColor->gray,
250 transpColor->gray, transpColor->gray);
251 }
252 }
253 }
254
255 if (valid ||
256 PNG_COLOR_TYPE_RGB_ALPHA == color_type ||
257 PNG_COLOR_TYPE_GRAY_ALPHA == color_type) {
258 hasAlpha = true;
259 config = SkBitmap::kARGB_8888_Config;
260 } else { // we get to choose the config
261 config = prefConfig;
262 if (config == SkBitmap::kNo_Config) {
263 config = SkImageDecoder::GetDeviceConfig();
264 }
265 if (config != SkBitmap::kRGB_565_Config &&
266 config != SkBitmap::kARGB_4444_Config) {
267 config = SkBitmap::kARGB_8888_Config;
268 }
269 }
270 }
271
272 if (!this->chooseFromOneChoice(config, origWidth, origHeight)) {
273 return false;
274 }
275
276 const int sampleSize = this->getSampleSize();
277 SkScaledBitmapSampler sampler(origWidth, origHeight, sampleSize);
278
279 decodedBitmap->setConfig(config, sampler.scaledWidth(),
280 sampler.scaledHeight(), 0);
281 if (SkImageDecoder::kDecodeBounds_Mode == mode) {
282 return true;
283 }
284
285 // from here down we are concerned with colortables and pixels
286
287 // we track if we actually see a non-opaque pixels, since sometimes a PNG sets its colortype
288 // to |= PNG_COLOR_MASK_ALPHA, but all of its pixels are in fact opaque. We care, since we
289 // draw lots faster if we can flag the bitmap has being opaque
290 bool reallyHasAlpha = false;
291
292 SkColorTable* colorTable = NULL;
293
294 if (color_type == PNG_COLOR_TYPE_PALETTE) {
295 int num_palette;
296 png_colorp palette;
297 png_bytep trans;
298 int num_trans;
299
300 png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
301
302 /* BUGGY IMAGE WORKAROUND
303
304 We hit some images (e.g. fruit_.png) who contain bytes that are == colortable_count
305 which is a problem since we use the byte as an index. To work around this we grow
306 the colortable by 1 (if its < 256) and duplicate the last color into that slot.
307 */
308 int colorCount = num_palette + (num_palette < 256);
309
310 colorTable = SkNEW_ARGS(SkColorTable, (colorCount));
311
312 SkPMColor* colorPtr = colorTable->lockColors();
313 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
314 png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL);
315 hasAlpha = (num_trans > 0);
316 } else {
317 num_trans = 0;
318 colorTable->setFlags(colorTable->getFlags() | SkColorTable::kColorsAreOpaque_Flag);
319 }
320 // check for bad images that might make us crash
321 if (num_trans > num_palette) {
322 num_trans = num_palette;
323 }
324
325 int index = 0;
326 int transLessThanFF = 0;
327
328 for (; index < num_trans; index++) {
329 transLessThanFF |= (int)*trans - 0xFF;
330 *colorPtr++ = SkPreMultiplyARGB(*trans++, palette->red, palette->green, palette->blue);
331 palette++;
332 }
333 reallyHasAlpha |= (transLessThanFF < 0);
334
335 for (; index < num_palette; index++) {
336 *colorPtr++ = SkPackARGB32(0xFF, palette->red, palette->green, palette->blue);
337 palette++;
338 }
339
340 // see BUGGY IMAGE WORKAROUND comment above
341 if (num_palette < 256) {
342 *colorPtr = colorPtr[-1];
343 }
344 colorTable->unlockColors(true);
345 }
346
347 SkAutoUnref aur(colorTable);
348
349 if (!this->allocPixelRef(decodedBitmap, colorTable)) {
350 return false;
351 }
352
353 SkAutoLockPixels alp(*decodedBitmap);
354
355 /* swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */
356// if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
357// ; // png_set_swap_alpha(png_ptr);
358
359 /* swap bytes of 16 bit files to least significant byte first */
360 // png_set_swap(png_ptr);
361
362 /* Add filler (or alpha) byte (before/after each RGB triplet) */
363 if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_GRAY) {
364 png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
365 }
366
367 /* Turn on interlace handling. REQUIRED if you are not using
368 * png_read_image(). To see how to handle interlacing passes,
369 * see the png_read_row() method below:
370 */
371 const int number_passes = interlace_type != PNG_INTERLACE_NONE ?
372 png_set_interlace_handling(png_ptr) : 1;
373
374 /* Optional call to gamma correct and add the background to the palette
375 * and update info structure. REQUIRED if you are expecting libpng to
376 * update the palette for you (ie you selected such a transform above).
377 */
378 png_read_update_info(png_ptr, info_ptr);
379
380 if (SkBitmap::kIndex8_Config == config && 1 == sampleSize) {
381 for (int i = 0; i < number_passes; i++) {
382 for (png_uint_32 y = 0; y < origHeight; y++) {
383 uint8_t* bmRow = decodedBitmap->getAddr8(0, y);
384 png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1);
385 }
386 }
387 } else {
388 SkScaledBitmapSampler::SrcConfig sc;
389 int srcBytesPerPixel = 4;
390
391 if (SkBitmap::kIndex8_Config == config) {
392 sc = SkScaledBitmapSampler::kIndex;
393 srcBytesPerPixel = 1;
394 } else if (hasAlpha) {
395 sc = SkScaledBitmapSampler::kRGBA;
396 } else {
397 sc = SkScaledBitmapSampler::kRGBX;
398 }
399
400 SkAutoMalloc storage(origWidth * srcBytesPerPixel);
401 const int height = decodedBitmap->height();
402
403 for (int i = 0; i < number_passes; i++) {
404 if (!sampler.begin(decodedBitmap, sc, doDither)) {
405 return false;
406 }
407
408 uint8_t* srcRow = (uint8_t*)storage.get();
409 skip_src_rows(png_ptr, srcRow, sampler.srcY0());
410
411 for (int y = 0; y < height; y++) {
412 uint8_t* tmp = srcRow;
413 png_read_rows(png_ptr, &tmp, png_bytepp_NULL, 1);
414 reallyHasAlpha |= sampler.next(srcRow);
415 if (y < height - 1) {
416 skip_src_rows(png_ptr, srcRow, sampler.srcDY() - 1);
417 }
418 }
419
420 // skip the rest of the rows (if any)
421 png_uint_32 read = (height - 1) * sampler.srcDY() +
422 sampler.srcY0() + 1;
423 SkASSERT(read <= origHeight);
424 skip_src_rows(png_ptr, srcRow, origHeight - read);
425 }
426
427 if (hasAlpha && !reallyHasAlpha) {
428#if 0
429 SkDEBUGF(("Image doesn't really have alpha [%d %d]\n",
430 origWidth, origHeight));
431#endif
432 }
433 }
434
435 /* read rest of file, and get additional chunks in info_ptr - REQUIRED */
436 png_read_end(png_ptr, info_ptr);
437
438 if (0 != theTranspColor) {
439 reallyHasAlpha |= substituteTranspColor(decodedBitmap, theTranspColor);
440 }
441 decodedBitmap->setIsOpaque(!reallyHasAlpha);
442 return true;
443}
444
445///////////////////////////////////////////////////////////////////////////////
446
reed@android.com8a1c16f2008-12-17 15:59:43 +0000447#include "SkColorPriv.h"
448#include "SkUnPreMultiply.h"
449
450static void sk_write_fn(png_structp png_ptr, png_bytep data, png_size_t len) {
451 SkWStream* sk_stream = (SkWStream*)png_ptr->io_ptr;
452 if (!sk_stream->write(data, len)) {
453 png_error(png_ptr, "sk_write_fn Error!");
454 }
455}
456
457typedef void (*transform_scanline_proc)(const char* SK_RESTRICT src,
458 int width, char* SK_RESTRICT dst);
459
460static void transform_scanline_565(const char* SK_RESTRICT src, int width,
461 char* SK_RESTRICT dst) {
462 const uint16_t* SK_RESTRICT srcP = (const uint16_t*)src;
463 for (int i = 0; i < width; i++) {
464 unsigned c = *srcP++;
465 *dst++ = SkPacked16ToR32(c);
466 *dst++ = SkPacked16ToG32(c);
467 *dst++ = SkPacked16ToB32(c);
468 }
469}
470
471static void transform_scanline_888(const char* SK_RESTRICT src, int width,
472 char* SK_RESTRICT dst) {
473 const SkPMColor* SK_RESTRICT srcP = (const SkPMColor*)src;
474 for (int i = 0; i < width; i++) {
475 SkPMColor c = *srcP++;
476 *dst++ = SkGetPackedR32(c);
477 *dst++ = SkGetPackedG32(c);
478 *dst++ = SkGetPackedB32(c);
479 }
480}
481
482static void transform_scanline_444(const char* SK_RESTRICT src, int width,
483 char* SK_RESTRICT dst) {
484 const SkPMColor16* SK_RESTRICT srcP = (const SkPMColor16*)src;
485 for (int i = 0; i < width; i++) {
486 SkPMColor16 c = *srcP++;
487 *dst++ = SkPacked4444ToR32(c);
488 *dst++ = SkPacked4444ToG32(c);
489 *dst++ = SkPacked4444ToB32(c);
490 }
491}
492
493static void transform_scanline_8888(const char* SK_RESTRICT src, int width,
494 char* SK_RESTRICT dst) {
495 const SkPMColor* SK_RESTRICT srcP = (const SkPMColor*)src;
496 const SkUnPreMultiply::Scale* SK_RESTRICT table =
497 SkUnPreMultiply::GetScaleTable();
498
499 for (int i = 0; i < width; i++) {
500 SkPMColor c = *srcP++;
501 unsigned a = SkGetPackedA32(c);
502 unsigned r = SkGetPackedR32(c);
503 unsigned g = SkGetPackedG32(c);
504 unsigned b = SkGetPackedB32(c);
505
506 if (0 != a && 255 != a) {
507 SkUnPreMultiply::Scale scale = table[a];
508 r = SkUnPreMultiply::ApplyScale(scale, r);
509 g = SkUnPreMultiply::ApplyScale(scale, g);
510 b = SkUnPreMultiply::ApplyScale(scale, b);
511 }
512 *dst++ = r;
513 *dst++ = g;
514 *dst++ = b;
515 *dst++ = a;
516 }
517}
518
519static void transform_scanline_4444(const char* SK_RESTRICT src, int width,
520 char* SK_RESTRICT dst) {
521 const SkPMColor16* SK_RESTRICT srcP = (const SkPMColor16*)src;
522 const SkUnPreMultiply::Scale* SK_RESTRICT table =
523 SkUnPreMultiply::GetScaleTable();
524
525 for (int i = 0; i < width; i++) {
526 SkPMColor16 c = *srcP++;
527 unsigned a = SkPacked4444ToA32(c);
528 unsigned r = SkPacked4444ToR32(c);
529 unsigned g = SkPacked4444ToG32(c);
530 unsigned b = SkPacked4444ToB32(c);
531
532 if (0 != a && 255 != a) {
533 SkUnPreMultiply::Scale scale = table[a];
534 r = SkUnPreMultiply::ApplyScale(scale, r);
535 g = SkUnPreMultiply::ApplyScale(scale, g);
536 b = SkUnPreMultiply::ApplyScale(scale, b);
537 }
538 *dst++ = r;
539 *dst++ = g;
540 *dst++ = b;
541 *dst++ = a;
542 }
543}
544
545static void transform_scanline_index8(const char* SK_RESTRICT src, int width,
546 char* SK_RESTRICT dst) {
547 memcpy(dst, src, width);
548}
549
550static transform_scanline_proc choose_proc(SkBitmap::Config config,
551 bool hasAlpha) {
552 // we don't care about search on alpha if we're kIndex8, since only the
553 // colortable packing cares about that distinction, not the pixels
554 if (SkBitmap::kIndex8_Config == config) {
555 hasAlpha = false; // we store false in the table entries for kIndex8
556 }
557
558 static const struct {
559 SkBitmap::Config fConfig;
560 bool fHasAlpha;
561 transform_scanline_proc fProc;
562 } gMap[] = {
563 { SkBitmap::kRGB_565_Config, false, transform_scanline_565 },
564 { SkBitmap::kARGB_8888_Config, false, transform_scanline_888 },
565 { SkBitmap::kARGB_8888_Config, true, transform_scanline_8888 },
566 { SkBitmap::kARGB_4444_Config, false, transform_scanline_444 },
567 { SkBitmap::kARGB_4444_Config, true, transform_scanline_4444 },
568 { SkBitmap::kIndex8_Config, false, transform_scanline_index8 },
569 };
570
571 for (int i = SK_ARRAY_COUNT(gMap) - 1; i >= 0; --i) {
572 if (gMap[i].fConfig == config && gMap[i].fHasAlpha == hasAlpha) {
573 return gMap[i].fProc;
574 }
575 }
576 sk_throw();
577 return NULL;
578}
579
580// return the minimum legal bitdepth (by png standards) for this many colortable
581// entries. SkBitmap always stores in 8bits per pixel, but for colorcount <= 16,
582// we can use fewer bits per in png
583static int computeBitDepth(int colorCount) {
584#if 0
585 int bits = SkNextLog2(colorCount);
586 SkASSERT(bits >= 1 && bits <= 8);
587 // now we need bits itself to be a power of 2 (e.g. 1, 2, 4, 8)
588 return SkNextPow2(bits);
589#else
590 // for the moment, we don't know how to pack bitdepth < 8
591 return 8;
592#endif
593}
594
595/* Pack palette[] with the corresponding colors, and if hasAlpha is true, also
596 pack trans[] and return the number of trans[] entries written. If hasAlpha
597 is false, the return value will always be 0.
598
599 Note: this routine takes care of unpremultiplying the RGB values when we
600 have alpha in the colortable, since png doesn't support premul colors
601*/
reed@android.com6f252972009-01-14 16:46:16 +0000602static inline int pack_palette(SkColorTable* ctable,
603 png_color* SK_RESTRICT palette,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000604 png_byte* SK_RESTRICT trans, bool hasAlpha) {
605 SkAutoLockColors alc(ctable);
606 const SkPMColor* SK_RESTRICT colors = alc.colors();
607 const int ctCount = ctable->count();
608 int i, num_trans = 0;
609
610 if (hasAlpha) {
611 /* first see if we have some number of fully opaque at the end of the
612 ctable. PNG allows num_trans < num_palette, but all of the trans
613 entries must come first in the palette. If I was smarter, I'd
614 reorder the indices and ctable so that all non-opaque colors came
615 first in the palette. But, since that would slow down the encode,
616 I'm leaving the indices and ctable order as is, and just looking
617 at the tail of the ctable for opaqueness.
618 */
619 num_trans = ctCount;
620 for (i = ctCount - 1; i >= 0; --i) {
621 if (SkGetPackedA32(colors[i]) != 0xFF) {
622 break;
623 }
624 num_trans -= 1;
625 }
626
627 const SkUnPreMultiply::Scale* SK_RESTRICT table =
628 SkUnPreMultiply::GetScaleTable();
629
630 for (i = 0; i < num_trans; i++) {
631 const SkPMColor c = *colors++;
632 const unsigned a = SkGetPackedA32(c);
633 const SkUnPreMultiply::Scale s = table[a];
634 trans[i] = a;
635 palette[i].red = SkUnPreMultiply::ApplyScale(s, SkGetPackedR32(c));
636 palette[i].green = SkUnPreMultiply::ApplyScale(s,SkGetPackedG32(c));
637 palette[i].blue = SkUnPreMultiply::ApplyScale(s, SkGetPackedB32(c));
638 }
639 // now fall out of this if-block to use common code for the trailing
640 // opaque entries
641 }
642
643 // these (remaining) entries are opaque
644 for (i = num_trans; i < ctCount; i++) {
645 SkPMColor c = *colors++;
646 palette[i].red = SkGetPackedR32(c);
647 palette[i].green = SkGetPackedG32(c);
648 palette[i].blue = SkGetPackedB32(c);
649 }
650 return num_trans;
651}
652
653class SkPNGImageEncoder : public SkImageEncoder {
654protected:
655 virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality);
656};
657
658bool SkPNGImageEncoder::onEncode(SkWStream* stream, const SkBitmap& bitmap,
659 int /*quality*/) {
660 SkBitmap::Config config = bitmap.getConfig();
661
662 const bool hasAlpha = !bitmap.isOpaque();
663 int colorType = PNG_COLOR_MASK_COLOR;
664 int bitDepth = 8; // default for color
665 png_color_8 sig_bit;
666
667 switch (config) {
668 case SkBitmap::kIndex8_Config:
669 colorType |= PNG_COLOR_MASK_PALETTE;
670 // fall through to the ARGB_8888 case
671 case SkBitmap::kARGB_8888_Config:
672 sig_bit.red = 8;
673 sig_bit.green = 8;
674 sig_bit.blue = 8;
675 sig_bit.alpha = 8;
676 break;
677 case SkBitmap::kARGB_4444_Config:
678 sig_bit.red = 4;
679 sig_bit.green = 4;
680 sig_bit.blue = 4;
681 sig_bit.alpha = 4;
682 break;
683 case SkBitmap::kRGB_565_Config:
684 sig_bit.red = 5;
685 sig_bit.green = 6;
686 sig_bit.blue = 5;
687 sig_bit.alpha = 0;
688 break;
689 default:
690 return false;
691 }
692
693 if (hasAlpha) {
694 // don't specify alpha if we're a palette, even if our ctable has alpha
695 if (!(colorType & PNG_COLOR_MASK_PALETTE)) {
696 colorType |= PNG_COLOR_MASK_ALPHA;
697 }
698 } else {
699 sig_bit.alpha = 0;
700 }
701
702 SkAutoLockPixels alp(bitmap);
703 // readyToDraw checks for pixels (and colortable if that is required)
704 if (!bitmap.readyToDraw()) {
705 return false;
706 }
707
708 // we must do this after we have locked the pixels
709 SkColorTable* ctable = bitmap.getColorTable();
710 if (NULL != ctable) {
711 if (ctable->count() == 0) {
712 return false;
713 }
714 // check if we can store in fewer than 8 bits
715 bitDepth = computeBitDepth(ctable->count());
716 }
717
718 png_structp png_ptr;
719 png_infop info_ptr;
720
721 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, sk_error_fn,
722 NULL);
723 if (NULL == png_ptr) {
724 return false;
725 }
726
727 info_ptr = png_create_info_struct(png_ptr);
728 if (NULL == info_ptr) {
729 png_destroy_write_struct(&png_ptr, png_infopp_NULL);
730 return false;
731 }
732
733 /* Set error handling. REQUIRED if you aren't supplying your own
734 * error handling functions in the png_create_write_struct() call.
735 */
736 if (setjmp(png_jmpbuf(png_ptr))) {
737 png_destroy_write_struct(&png_ptr, &info_ptr);
738 return false;
739 }
740
741 png_set_write_fn(png_ptr, (void*)stream, sk_write_fn, png_flush_ptr_NULL);
742
743 /* Set the image information here. Width and height are up to 2^31,
744 * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
745 * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
746 * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
747 * or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or
748 * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
749 * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED
750 */
751
752 png_set_IHDR(png_ptr, info_ptr, bitmap.width(), bitmap.height(),
753 bitDepth, colorType,
754 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE,
755 PNG_FILTER_TYPE_BASE);
756
757#if 0 // need to support this some day
758 /* set the palette if there is one. REQUIRED for indexed-color images */
759 palette = (png_colorp)png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH
760 * png_sizeof (png_color));
761 /* ... set palette colors ... */
762 png_set_PLTE(png_ptr, info_ptr, palette, PNG_MAX_PALETTE_LENGTH);
763 /* You must not free palette here, because png_set_PLTE only makes a link to
764 the palette that you malloced. Wait until you are about to destroy
765 the png structure. */
766#endif
767
768 png_set_sBIT(png_ptr, info_ptr, &sig_bit);
769 png_write_info(png_ptr, info_ptr);
770
771 const char* srcImage = (const char*)bitmap.getPixels();
772 SkAutoSMalloc<1024> rowStorage(bitmap.width() << 2);
773 char* storage = (char*)rowStorage.get();
774 transform_scanline_proc proc = choose_proc(config, hasAlpha);
775
776 for (int y = 0; y < bitmap.height(); y++) {
777 png_bytep row_ptr = (png_bytep)storage;
778 proc(srcImage, bitmap.width(), storage);
779 png_write_rows(png_ptr, &row_ptr, 1);
780 srcImage += bitmap.rowBytes();
781 }
782
783 png_write_end(png_ptr, info_ptr);
784
785 /* clean up after the write, and free any memory allocated */
786 png_destroy_write_struct(&png_ptr, &info_ptr);
787 return true;
788}
789
790SkImageEncoder* SkImageEncoder_PNG_Factory();
791SkImageEncoder* SkImageEncoder_PNG_Factory() {
792 return SkNEW(SkPNGImageEncoder);
793}
794