SkImageDecoder_libpng.cpp revision b50a60c463ae4e2475de8a421b0056b03335b28e
1/* 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 "SkImageEncoder.h"
20#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
447#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*/
602static inline int pack_palette(SkColorTable* ctable,
603                               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