blob: 862ebf1d98d54a4fdc6ec309e05e32fed6aad829 [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"
19#include "SkColor.h"
20#include "SkColorPriv.h"
21#include "SkDither.h"
22#include "SkMath.h"
23#include "SkScaledBitmapSampler.h"
24#include "SkStream.h"
25#include "SkTemplates.h"
26#include "SkUtils.h"
27
28extern "C" {
29#include "png.h"
30}
31
32class SkPNGImageDecoder : public SkImageDecoder {
33public:
34 virtual Format getFormat() const {
35 return kPNG_Format;
36 }
37
38protected:
39 virtual bool onDecode(SkStream* stream, SkBitmap* bm,
40 SkBitmap::Config pref, Mode);
41};
42
43#ifndef png_jmpbuf
44# define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
45#endif
46
47#define PNG_BYTES_TO_CHECK 4
48
49/* Automatically clean up after throwing an exception */
50struct PNGAutoClean {
51 PNGAutoClean(png_structp p, png_infop i): png_ptr(p), info_ptr(i) {}
52 ~PNGAutoClean() {
53 png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
54 }
55private:
56 png_structp png_ptr;
57 png_infop info_ptr;
58};
59
60SkImageDecoder* SkImageDecoder_PNG_Factory(SkStream* stream) {
61 char buf[PNG_BYTES_TO_CHECK];
62 if (stream->read(buf, PNG_BYTES_TO_CHECK) == PNG_BYTES_TO_CHECK &&
63 !png_sig_cmp((png_bytep) buf, (png_size_t)0, PNG_BYTES_TO_CHECK)) {
64 return SkNEW(SkPNGImageDecoder);
65 }
66 return NULL;
67}
68
69static void sk_read_fn(png_structp png_ptr, png_bytep data, png_size_t length) {
70 SkStream* sk_stream = (SkStream*) png_ptr->io_ptr;
71 size_t bytes = sk_stream->read(data, length);
72 if (bytes != length) {
73 png_error(png_ptr, "Read Error!");
74 }
75}
76
77static int sk_read_user_chunk(png_structp png_ptr, png_unknown_chunkp chunk) {
78 SkImageDecoder::Peeker* peeker =
79 (SkImageDecoder::Peeker*)png_get_user_chunk_ptr(png_ptr);
80 // peek() returning true means continue decoding
81 return peeker->peek((const char*)chunk->name, chunk->data, chunk->size) ?
82 1 : -1;
83}
84
85static void sk_error_fn(png_structp png_ptr, png_const_charp msg) {
86#if 0
87 SkDebugf("------ png error %s\n", msg);
88#endif
89 longjmp(png_jmpbuf(png_ptr), 1);
90}
91
92static void skip_src_rows(png_structp png_ptr, uint8_t storage[], int count) {
93 for (int i = 0; i < count; i++) {
94 uint8_t* tmp = storage;
95 png_read_rows(png_ptr, &tmp, png_bytepp_NULL, 1);
96 }
97}
98
99static bool pos_le(int value, int max) {
100 return value > 0 && value <= max;
101}
102
103static bool substituteTranspColor(SkBitmap* bm, SkPMColor match) {
104 SkASSERT(bm->config() == SkBitmap::kARGB_8888_Config);
105
106 bool reallyHasAlpha = false;
107
108 for (int y = bm->height() - 1; y >= 0; --y) {
109 SkPMColor* p = bm->getAddr32(0, y);
110 for (int x = bm->width() - 1; x >= 0; --x) {
111 if (match == *p) {
112 *p = 0;
113 reallyHasAlpha = true;
114 }
115 p += 1;
116 }
117 }
118 return reallyHasAlpha;
119}
120
121bool SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* decodedBitmap,
122 SkBitmap::Config prefConfig, Mode mode) {
123// SkAutoTrace apr("SkPNGImageDecoder::onDecode");
124
125 /* Create and initialize the png_struct with the desired error handler
126 * functions. If you want to use the default stderr and longjump method,
127 * you can supply NULL for the last three parameters. We also supply the
128 * the compiler header file version, so that we know if the application
129 * was compiled with a compatible version of the library. */
130 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
131 NULL, sk_error_fn, NULL);
132 // png_voidp user_error_ptr, user_error_fn, user_warning_fn);
133 if (png_ptr == NULL) {
134 return false;
135 }
136
137 /* Allocate/initialize the memory for image information. */
138 png_infop info_ptr = png_create_info_struct(png_ptr);
139 if (info_ptr == NULL) {
140 png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL);
141 return false;
142 }
143
144 PNGAutoClean autoClean(png_ptr, info_ptr);
145
146 /* Set error handling if you are using the setjmp/longjmp method (this is
147 * the normal method of doing things with libpng). REQUIRED unless you
148 * set up your own error handlers in the png_create_read_struct() earlier.
149 */
150 if (setjmp(png_jmpbuf(png_ptr))) {
151 return false;
152 }
153
154 /* If you are using replacement read functions, instead of calling
155 * png_init_io() here you would call:
156 */
157 png_set_read_fn(png_ptr, (void *)sk_stream, sk_read_fn);
158 /* where user_io_ptr is a structure you want available to the callbacks */
159 /* If we have already read some of the signature */
160// png_set_sig_bytes(png_ptr, 0 /* sig_read */ );
161
162 // hookup our peeker so we can see any user-chunks the caller may be interested in
163 png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*)"", 0);
164 if (this->getPeeker()) {
165 png_set_read_user_chunk_fn(png_ptr, (png_voidp)this->getPeeker(), sk_read_user_chunk);
166 }
167
168 /* The call to png_read_info() gives us all of the information from the
169 * PNG file before the first IDAT (image data chunk). */
170 png_read_info(png_ptr, info_ptr);
171 png_uint_32 origWidth, origHeight;
172 int bit_depth, color_type, interlace_type;
173 png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bit_depth, &color_type,
174 &interlace_type, int_p_NULL, int_p_NULL);
175
176 /* tell libpng to strip 16 bit/color files down to 8 bits/color */
177 if (bit_depth == 16) {
178 png_set_strip_16(png_ptr);
179 }
180 /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single
181 * byte into separate bytes (useful for paletted and grayscale images). */
182 if (bit_depth < 8) {
183 png_set_packing(png_ptr);
184 }
185 /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */
186 if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) {
187 png_set_gray_1_2_4_to_8(png_ptr);
188 }
189
190 /* Make a grayscale image into RGB. */
191 if (color_type == PNG_COLOR_TYPE_GRAY ||
192 color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
193 png_set_gray_to_rgb(png_ptr);
194 }
195
196 SkBitmap::Config config;
197 bool hasAlpha = false;
198 bool doDither = this->getDitherImage();
199 SkPMColor theTranspColor = 0; // 0 tells us not to try to match
200
201 // check for sBIT chunk data, in case we should disable dithering because
202 // our data is not truely 8bits per component
203 if (doDither) {
204#if 0
205 SkDebugf("----- sBIT %d %d %d %d\n", info_ptr->sig_bit.red,
206 info_ptr->sig_bit.green, info_ptr->sig_bit.blue,
207 info_ptr->sig_bit.alpha);
208#endif
209 // 0 seems to indicate no information available
210 if (pos_le(info_ptr->sig_bit.red, SK_R16_BITS) &&
211 pos_le(info_ptr->sig_bit.green, SK_G16_BITS) &&
212 pos_le(info_ptr->sig_bit.blue, SK_B16_BITS)) {
213 doDither = false;
214 }
215 }
216
217 if (color_type == PNG_COLOR_TYPE_PALETTE) {
218 config = SkBitmap::kIndex8_Config; // defer sniffing for hasAlpha
219 } else {
220 png_color_16p transpColor = NULL;
221 int numTransp = 0;
222
223 png_get_tRNS(png_ptr, info_ptr, NULL, &numTransp, &transpColor);
224
225 bool valid = png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS);
226
227 if (valid && numTransp == 1 && transpColor != NULL) {
228 /* Compute our transparent color, which we'll match against later.
229 We don't really handle 16bit components properly here, since we
230 do our compare *after* the values have been knocked down to 8bit
231 which means we will find more matches than we should. The real
232 fix seems to be to see the actual 16bit components, do the
233 compare, and then knock it down to 8bits ourselves.
234 */
235 if (color_type & PNG_COLOR_MASK_COLOR) {
236 if (16 == bit_depth) {
237 theTranspColor = SkPackARGB32(0xFF, transpColor->red >> 8,
238 transpColor->green >> 8, transpColor->blue >> 8);
239 } else {
240 theTranspColor = SkPackARGB32(0xFF, transpColor->red,
241 transpColor->green, transpColor->blue);
242 }
243 } else { // gray
244 if (16 == bit_depth) {
245 theTranspColor = SkPackARGB32(0xFF, transpColor->gray >> 8,
246 transpColor->gray >> 8, transpColor->gray >> 8);
247 } else {
248 theTranspColor = SkPackARGB32(0xFF, transpColor->gray,
249 transpColor->gray, transpColor->gray);
250 }
251 }
252 }
253
254 if (valid ||
255 PNG_COLOR_TYPE_RGB_ALPHA == color_type ||
256 PNG_COLOR_TYPE_GRAY_ALPHA == color_type) {
257 hasAlpha = true;
258 config = SkBitmap::kARGB_8888_Config;
259 } else { // we get to choose the config
260 config = prefConfig;
261 if (config == SkBitmap::kNo_Config) {
262 config = SkImageDecoder::GetDeviceConfig();
263 }
264 if (config != SkBitmap::kRGB_565_Config &&
265 config != SkBitmap::kARGB_4444_Config) {
266 config = SkBitmap::kARGB_8888_Config;
267 }
268 }
269 }
270
271 if (!this->chooseFromOneChoice(config, origWidth, origHeight)) {
272 return false;
273 }
274
275 const int sampleSize = this->getSampleSize();
276 SkScaledBitmapSampler sampler(origWidth, origHeight, sampleSize);
277
278 decodedBitmap->setConfig(config, sampler.scaledWidth(),
279 sampler.scaledHeight(), 0);
280 if (SkImageDecoder::kDecodeBounds_Mode == mode) {
281 return true;
282 }
283
284 // from here down we are concerned with colortables and pixels
285
286 // we track if we actually see a non-opaque pixels, since sometimes a PNG sets its colortype
287 // to |= PNG_COLOR_MASK_ALPHA, but all of its pixels are in fact opaque. We care, since we
288 // draw lots faster if we can flag the bitmap has being opaque
289 bool reallyHasAlpha = false;
290
291 SkColorTable* colorTable = NULL;
292
293 if (color_type == PNG_COLOR_TYPE_PALETTE) {
294 int num_palette;
295 png_colorp palette;
296 png_bytep trans;
297 int num_trans;
298
299 png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
300
301 /* BUGGY IMAGE WORKAROUND
302
303 We hit some images (e.g. fruit_.png) who contain bytes that are == colortable_count
304 which is a problem since we use the byte as an index. To work around this we grow
305 the colortable by 1 (if its < 256) and duplicate the last color into that slot.
306 */
307 int colorCount = num_palette + (num_palette < 256);
308
309 colorTable = SkNEW_ARGS(SkColorTable, (colorCount));
310
311 SkPMColor* colorPtr = colorTable->lockColors();
312 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
313 png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL);
314 hasAlpha = (num_trans > 0);
315 } else {
316 num_trans = 0;
317 colorTable->setFlags(colorTable->getFlags() | SkColorTable::kColorsAreOpaque_Flag);
318 }
319 // check for bad images that might make us crash
320 if (num_trans > num_palette) {
321 num_trans = num_palette;
322 }
323
324 int index = 0;
325 int transLessThanFF = 0;
326
327 for (; index < num_trans; index++) {
328 transLessThanFF |= (int)*trans - 0xFF;
329 *colorPtr++ = SkPreMultiplyARGB(*trans++, palette->red, palette->green, palette->blue);
330 palette++;
331 }
332 reallyHasAlpha |= (transLessThanFF < 0);
333
334 for (; index < num_palette; index++) {
335 *colorPtr++ = SkPackARGB32(0xFF, palette->red, palette->green, palette->blue);
336 palette++;
337 }
338
339 // see BUGGY IMAGE WORKAROUND comment above
340 if (num_palette < 256) {
341 *colorPtr = colorPtr[-1];
342 }
343 colorTable->unlockColors(true);
344 }
345
346 SkAutoUnref aur(colorTable);
347
348 if (!this->allocPixelRef(decodedBitmap, colorTable)) {
349 return false;
350 }
351
352 SkAutoLockPixels alp(*decodedBitmap);
353
354 /* swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */
355// if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
356// ; // png_set_swap_alpha(png_ptr);
357
358 /* swap bytes of 16 bit files to least significant byte first */
359 // png_set_swap(png_ptr);
360
361 /* Add filler (or alpha) byte (before/after each RGB triplet) */
362 if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_GRAY) {
363 png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
364 }
365
366 /* Turn on interlace handling. REQUIRED if you are not using
367 * png_read_image(). To see how to handle interlacing passes,
368 * see the png_read_row() method below:
369 */
370 const int number_passes = interlace_type != PNG_INTERLACE_NONE ?
371 png_set_interlace_handling(png_ptr) : 1;
372
373 /* Optional call to gamma correct and add the background to the palette
374 * and update info structure. REQUIRED if you are expecting libpng to
375 * update the palette for you (ie you selected such a transform above).
376 */
377 png_read_update_info(png_ptr, info_ptr);
378
379 if (SkBitmap::kIndex8_Config == config && 1 == sampleSize) {
380 for (int i = 0; i < number_passes; i++) {
381 for (png_uint_32 y = 0; y < origHeight; y++) {
382 uint8_t* bmRow = decodedBitmap->getAddr8(0, y);
383 png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1);
384 }
385 }
386 } else {
387 SkScaledBitmapSampler::SrcConfig sc;
388 int srcBytesPerPixel = 4;
389
390 if (SkBitmap::kIndex8_Config == config) {
391 sc = SkScaledBitmapSampler::kIndex;
392 srcBytesPerPixel = 1;
393 } else if (hasAlpha) {
394 sc = SkScaledBitmapSampler::kRGBA;
395 } else {
396 sc = SkScaledBitmapSampler::kRGBX;
397 }
398
399 SkAutoMalloc storage(origWidth * srcBytesPerPixel);
400 const int height = decodedBitmap->height();
401
402 for (int i = 0; i < number_passes; i++) {
403 if (!sampler.begin(decodedBitmap, sc, doDither)) {
404 return false;
405 }
406
407 uint8_t* srcRow = (uint8_t*)storage.get();
408 skip_src_rows(png_ptr, srcRow, sampler.srcY0());
409
410 for (int y = 0; y < height; y++) {
411 uint8_t* tmp = srcRow;
412 png_read_rows(png_ptr, &tmp, png_bytepp_NULL, 1);
413 reallyHasAlpha |= sampler.next(srcRow);
414 if (y < height - 1) {
415 skip_src_rows(png_ptr, srcRow, sampler.srcDY() - 1);
416 }
417 }
418
419 // skip the rest of the rows (if any)
420 png_uint_32 read = (height - 1) * sampler.srcDY() +
421 sampler.srcY0() + 1;
422 SkASSERT(read <= origHeight);
423 skip_src_rows(png_ptr, srcRow, origHeight - read);
424 }
425
426 if (hasAlpha && !reallyHasAlpha) {
427#if 0
428 SkDEBUGF(("Image doesn't really have alpha [%d %d]\n",
429 origWidth, origHeight));
430#endif
431 }
432 }
433
434 /* read rest of file, and get additional chunks in info_ptr - REQUIRED */
435 png_read_end(png_ptr, info_ptr);
436
437 if (0 != theTranspColor) {
438 reallyHasAlpha |= substituteTranspColor(decodedBitmap, theTranspColor);
439 }
440 decodedBitmap->setIsOpaque(!reallyHasAlpha);
441 return true;
442}
443
444///////////////////////////////////////////////////////////////////////////////
445
446#ifdef SK_SUPPORT_IMAGE_ENCODE
447
448#include "SkColorPriv.h"
449#include "SkUnPreMultiply.h"
450
451static void sk_write_fn(png_structp png_ptr, png_bytep data, png_size_t len) {
452 SkWStream* sk_stream = (SkWStream*)png_ptr->io_ptr;
453 if (!sk_stream->write(data, len)) {
454 png_error(png_ptr, "sk_write_fn Error!");
455 }
456}
457
458typedef void (*transform_scanline_proc)(const char* SK_RESTRICT src,
459 int width, char* SK_RESTRICT dst);
460
461static void transform_scanline_565(const char* SK_RESTRICT src, int width,
462 char* SK_RESTRICT dst) {
463 const uint16_t* SK_RESTRICT srcP = (const uint16_t*)src;
464 for (int i = 0; i < width; i++) {
465 unsigned c = *srcP++;
466 *dst++ = SkPacked16ToR32(c);
467 *dst++ = SkPacked16ToG32(c);
468 *dst++ = SkPacked16ToB32(c);
469 }
470}
471
472static void transform_scanline_888(const char* SK_RESTRICT src, int width,
473 char* SK_RESTRICT dst) {
474 const SkPMColor* SK_RESTRICT srcP = (const SkPMColor*)src;
475 for (int i = 0; i < width; i++) {
476 SkPMColor c = *srcP++;
477 *dst++ = SkGetPackedR32(c);
478 *dst++ = SkGetPackedG32(c);
479 *dst++ = SkGetPackedB32(c);
480 }
481}
482
483static void transform_scanline_444(const char* SK_RESTRICT src, int width,
484 char* SK_RESTRICT dst) {
485 const SkPMColor16* SK_RESTRICT srcP = (const SkPMColor16*)src;
486 for (int i = 0; i < width; i++) {
487 SkPMColor16 c = *srcP++;
488 *dst++ = SkPacked4444ToR32(c);
489 *dst++ = SkPacked4444ToG32(c);
490 *dst++ = SkPacked4444ToB32(c);
491 }
492}
493
494static void transform_scanline_8888(const char* SK_RESTRICT src, int width,
495 char* SK_RESTRICT dst) {
496 const SkPMColor* SK_RESTRICT srcP = (const SkPMColor*)src;
497 const SkUnPreMultiply::Scale* SK_RESTRICT table =
498 SkUnPreMultiply::GetScaleTable();
499
500 for (int i = 0; i < width; i++) {
501 SkPMColor c = *srcP++;
502 unsigned a = SkGetPackedA32(c);
503 unsigned r = SkGetPackedR32(c);
504 unsigned g = SkGetPackedG32(c);
505 unsigned b = SkGetPackedB32(c);
506
507 if (0 != a && 255 != a) {
508 SkUnPreMultiply::Scale scale = table[a];
509 r = SkUnPreMultiply::ApplyScale(scale, r);
510 g = SkUnPreMultiply::ApplyScale(scale, g);
511 b = SkUnPreMultiply::ApplyScale(scale, b);
512 }
513 *dst++ = r;
514 *dst++ = g;
515 *dst++ = b;
516 *dst++ = a;
517 }
518}
519
520static void transform_scanline_4444(const char* SK_RESTRICT src, int width,
521 char* SK_RESTRICT dst) {
522 const SkPMColor16* SK_RESTRICT srcP = (const SkPMColor16*)src;
523 const SkUnPreMultiply::Scale* SK_RESTRICT table =
524 SkUnPreMultiply::GetScaleTable();
525
526 for (int i = 0; i < width; i++) {
527 SkPMColor16 c = *srcP++;
528 unsigned a = SkPacked4444ToA32(c);
529 unsigned r = SkPacked4444ToR32(c);
530 unsigned g = SkPacked4444ToG32(c);
531 unsigned b = SkPacked4444ToB32(c);
532
533 if (0 != a && 255 != a) {
534 SkUnPreMultiply::Scale scale = table[a];
535 r = SkUnPreMultiply::ApplyScale(scale, r);
536 g = SkUnPreMultiply::ApplyScale(scale, g);
537 b = SkUnPreMultiply::ApplyScale(scale, b);
538 }
539 *dst++ = r;
540 *dst++ = g;
541 *dst++ = b;
542 *dst++ = a;
543 }
544}
545
546static void transform_scanline_index8(const char* SK_RESTRICT src, int width,
547 char* SK_RESTRICT dst) {
548 memcpy(dst, src, width);
549}
550
551static transform_scanline_proc choose_proc(SkBitmap::Config config,
552 bool hasAlpha) {
553 // we don't care about search on alpha if we're kIndex8, since only the
554 // colortable packing cares about that distinction, not the pixels
555 if (SkBitmap::kIndex8_Config == config) {
556 hasAlpha = false; // we store false in the table entries for kIndex8
557 }
558
559 static const struct {
560 SkBitmap::Config fConfig;
561 bool fHasAlpha;
562 transform_scanline_proc fProc;
563 } gMap[] = {
564 { SkBitmap::kRGB_565_Config, false, transform_scanline_565 },
565 { SkBitmap::kARGB_8888_Config, false, transform_scanline_888 },
566 { SkBitmap::kARGB_8888_Config, true, transform_scanline_8888 },
567 { SkBitmap::kARGB_4444_Config, false, transform_scanline_444 },
568 { SkBitmap::kARGB_4444_Config, true, transform_scanline_4444 },
569 { SkBitmap::kIndex8_Config, false, transform_scanline_index8 },
570 };
571
572 for (int i = SK_ARRAY_COUNT(gMap) - 1; i >= 0; --i) {
573 if (gMap[i].fConfig == config && gMap[i].fHasAlpha == hasAlpha) {
574 return gMap[i].fProc;
575 }
576 }
577 sk_throw();
578 return NULL;
579}
580
581// return the minimum legal bitdepth (by png standards) for this many colortable
582// entries. SkBitmap always stores in 8bits per pixel, but for colorcount <= 16,
583// we can use fewer bits per in png
584static int computeBitDepth(int colorCount) {
585#if 0
586 int bits = SkNextLog2(colorCount);
587 SkASSERT(bits >= 1 && bits <= 8);
588 // now we need bits itself to be a power of 2 (e.g. 1, 2, 4, 8)
589 return SkNextPow2(bits);
590#else
591 // for the moment, we don't know how to pack bitdepth < 8
592 return 8;
593#endif
594}
595
596/* Pack palette[] with the corresponding colors, and if hasAlpha is true, also
597 pack trans[] and return the number of trans[] entries written. If hasAlpha
598 is false, the return value will always be 0.
599
600 Note: this routine takes care of unpremultiplying the RGB values when we
601 have alpha in the colortable, since png doesn't support premul colors
602*/
603static int pack_palette(SkColorTable* ctable, png_color* SK_RESTRICT palette,
604 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
795#endif /* SK_SUPPORT_IMAGE_ENCODE */