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