1
2/*
3 * Copyright 2006 The Android Open Source Project
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9
10#include "SkImageDecoder.h"
11#include "SkImageEncoder.h"
12#include "SkColor.h"
13#include "SkColorPriv.h"
14#include "SkDither.h"
15#include "SkMath.h"
16#include "SkScaledBitmapSampler.h"
17#include "SkStream.h"
18#include "SkTemplates.h"
19#include "SkUtils.h"
20#include "transform_scanline.h"
21
22extern "C" {
23#include "png.h"
24}
25
26/* These were dropped in libpng >= 1.4 */
27#ifndef png_infopp_NULL
28#define png_infopp_NULL NULL
29#endif
30
31#ifndef png_bytepp_NULL
32#define png_bytepp_NULL NULL
33#endif
34
35#ifndef int_p_NULL
36#define int_p_NULL NULL
37#endif
38
39#ifndef png_flush_ptr_NULL
40#define png_flush_ptr_NULL NULL
41#endif
42
43class SkPNGImageIndex {
44public:
45    SkPNGImageIndex(SkStream* stream, png_structp png_ptr, png_infop info_ptr)
46        : fStream(stream)
47        , fPng_ptr(png_ptr)
48        , fInfo_ptr(info_ptr)
49        , fConfig(SkBitmap::kNo_Config) {
50        SkASSERT(stream != NULL);
51        stream->ref();
52    }
53    ~SkPNGImageIndex() {
54        if (NULL != fPng_ptr) {
55            png_destroy_read_struct(&fPng_ptr, &fInfo_ptr, png_infopp_NULL);
56        }
57    }
58
59    SkAutoTUnref<SkStream>  fStream;
60    png_structp             fPng_ptr;
61    png_infop               fInfo_ptr;
62    SkBitmap::Config        fConfig;
63};
64
65class SkPNGImageDecoder : public SkImageDecoder {
66public:
67    SkPNGImageDecoder() {
68        fImageIndex = NULL;
69    }
70    virtual Format getFormat() const SK_OVERRIDE {
71        return kPNG_Format;
72    }
73
74    virtual ~SkPNGImageDecoder() {
75        SkDELETE(fImageIndex);
76    }
77
78protected:
79#ifdef SK_BUILD_FOR_ANDROID
80    virtual bool onBuildTileIndex(SkStream *stream, int *width, int *height) SK_OVERRIDE;
81    virtual bool onDecodeSubset(SkBitmap* bitmap, const SkIRect& region) SK_OVERRIDE;
82#endif
83    virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE;
84
85private:
86    SkPNGImageIndex* fImageIndex;
87
88    bool onDecodeInit(SkStream* stream, png_structp *png_ptrp, png_infop *info_ptrp);
89    bool decodePalette(png_structp png_ptr, png_infop info_ptr,
90                       bool * SK_RESTRICT hasAlphap, bool *reallyHasAlphap,
91                       SkColorTable **colorTablep);
92    bool getBitmapConfig(png_structp png_ptr, png_infop info_ptr,
93                         SkBitmap::Config *config, bool *hasAlpha,
94                         bool *doDither, SkPMColor *theTranspColor);
95
96    typedef SkImageDecoder INHERITED;
97};
98
99#ifndef png_jmpbuf
100#  define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
101#endif
102
103#define PNG_BYTES_TO_CHECK 4
104
105/* Automatically clean up after throwing an exception */
106struct PNGAutoClean {
107    PNGAutoClean(png_structp p, png_infop i): png_ptr(p), info_ptr(i) {}
108    ~PNGAutoClean() {
109        png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
110    }
111private:
112    png_structp png_ptr;
113    png_infop info_ptr;
114};
115
116static void sk_read_fn(png_structp png_ptr, png_bytep data, png_size_t length) {
117    SkStream* sk_stream = (SkStream*) png_get_io_ptr(png_ptr);
118    size_t bytes = sk_stream->read(data, length);
119    if (bytes != length) {
120        png_error(png_ptr, "Read Error!");
121    }
122}
123
124#ifdef SK_BUILD_FOR_ANDROID
125static void sk_seek_fn(png_structp png_ptr, png_uint_32 offset) {
126    SkStream* sk_stream = (SkStream*) png_get_io_ptr(png_ptr);
127    sk_stream->rewind();
128    (void)sk_stream->skip(offset);
129}
130#endif
131
132static int sk_read_user_chunk(png_structp png_ptr, png_unknown_chunkp chunk) {
133    SkImageDecoder::Peeker* peeker =
134                    (SkImageDecoder::Peeker*)png_get_user_chunk_ptr(png_ptr);
135    // peek() returning true means continue decoding
136    return peeker->peek((const char*)chunk->name, chunk->data, chunk->size) ?
137            1 : -1;
138}
139
140static void sk_error_fn(png_structp png_ptr, png_const_charp msg) {
141    SkDEBUGF(("------ png error %s\n", msg));
142    longjmp(png_jmpbuf(png_ptr), 1);
143}
144
145static void skip_src_rows(png_structp png_ptr, uint8_t storage[], int count) {
146    for (int i = 0; i < count; i++) {
147        uint8_t* tmp = storage;
148        png_read_rows(png_ptr, &tmp, png_bytepp_NULL, 1);
149    }
150}
151
152static bool pos_le(int value, int max) {
153    return value > 0 && value <= max;
154}
155
156static bool substituteTranspColor(SkBitmap* bm, SkPMColor match) {
157    SkASSERT(bm->config() == SkBitmap::kARGB_8888_Config);
158
159    bool reallyHasAlpha = false;
160
161    for (int y = bm->height() - 1; y >= 0; --y) {
162        SkPMColor* p = bm->getAddr32(0, y);
163        for (int x = bm->width() - 1; x >= 0; --x) {
164            if (match == *p) {
165                *p = 0;
166                reallyHasAlpha = true;
167            }
168            p += 1;
169        }
170    }
171    return reallyHasAlpha;
172}
173
174static bool canUpscalePaletteToConfig(SkBitmap::Config dstConfig,
175                                      bool srcHasAlpha) {
176    switch (dstConfig) {
177        case SkBitmap::kARGB_8888_Config:
178        case SkBitmap::kARGB_4444_Config:
179            return true;
180        case SkBitmap::kRGB_565_Config:
181            // only return true if the src is opaque (since 565 is opaque)
182            return !srcHasAlpha;
183        default:
184            return false;
185    }
186}
187
188// call only if color_type is PALETTE. Returns true if the ctable has alpha
189static bool hasTransparencyInPalette(png_structp png_ptr, png_infop info_ptr) {
190    png_bytep trans;
191    int num_trans;
192
193    if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
194        png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL);
195        return num_trans > 0;
196    }
197    return false;
198}
199
200bool SkPNGImageDecoder::onDecodeInit(SkStream* sk_stream, png_structp *png_ptrp,
201                                     png_infop *info_ptrp) {
202    /* Create and initialize the png_struct with the desired error handler
203    * functions.  If you want to use the default stderr and longjump method,
204    * you can supply NULL for the last three parameters.  We also supply the
205    * the compiler header file version, so that we know if the application
206    * was compiled with a compatible version of the library.  */
207    png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
208        NULL, sk_error_fn, NULL);
209    //   png_voidp user_error_ptr, user_error_fn, user_warning_fn);
210    if (png_ptr == NULL) {
211        return false;
212    }
213    *png_ptrp = png_ptr;
214
215    /* Allocate/initialize the memory for image information. */
216    png_infop info_ptr = png_create_info_struct(png_ptr);
217    if (info_ptr == NULL) {
218        png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL);
219        return false;
220    }
221    *info_ptrp = info_ptr;
222
223    /* Set error handling if you are using the setjmp/longjmp method (this is
224    * the normal method of doing things with libpng).  REQUIRED unless you
225    * set up your own error handlers in the png_create_read_struct() earlier.
226    */
227    if (setjmp(png_jmpbuf(png_ptr))) {
228        return false;
229    }
230
231    /* If you are using replacement read functions, instead of calling
232    * png_init_io() here you would call:
233    */
234    png_set_read_fn(png_ptr, (void *)sk_stream, sk_read_fn);
235#ifdef SK_BUILD_FOR_ANDROID
236    png_set_seek_fn(png_ptr, sk_seek_fn);
237#endif
238    /* where user_io_ptr is a structure you want available to the callbacks */
239    /* If we have already read some of the signature */
240//  png_set_sig_bytes(png_ptr, 0 /* sig_read */ );
241
242    // hookup our peeker so we can see any user-chunks the caller may be interested in
243    png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*)"", 0);
244    if (this->getPeeker()) {
245        png_set_read_user_chunk_fn(png_ptr, (png_voidp)this->getPeeker(), sk_read_user_chunk);
246    }
247
248    /* The call to png_read_info() gives us all of the information from the
249    * PNG file before the first IDAT (image data chunk). */
250    png_read_info(png_ptr, info_ptr);
251    png_uint_32 origWidth, origHeight;
252    int bitDepth, colorType;
253    png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth,
254                 &colorType, int_p_NULL, int_p_NULL, int_p_NULL);
255
256    /* tell libpng to strip 16 bit/color files down to 8 bits/color */
257    if (bitDepth == 16) {
258        png_set_strip_16(png_ptr);
259    }
260    /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single
261     * byte into separate bytes (useful for paletted and grayscale images). */
262    if (bitDepth < 8) {
263        png_set_packing(png_ptr);
264    }
265    /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */
266    if (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8) {
267        png_set_expand_gray_1_2_4_to_8(png_ptr);
268    }
269
270    return true;
271}
272
273bool SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* decodedBitmap,
274                                 Mode mode) {
275    png_structp png_ptr;
276    png_infop info_ptr;
277
278    if (!onDecodeInit(sk_stream, &png_ptr, &info_ptr)) {
279        return false;
280    }
281
282    if (setjmp(png_jmpbuf(png_ptr))) {
283        return false;
284    }
285
286    PNGAutoClean autoClean(png_ptr, info_ptr);
287
288    png_uint_32 origWidth, origHeight;
289    int bitDepth, colorType, interlaceType;
290    png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth,
291                 &colorType, &interlaceType, int_p_NULL, int_p_NULL);
292
293    SkBitmap::Config    config;
294    bool                hasAlpha = false;
295    bool                doDither = this->getDitherImage();
296    SkPMColor           theTranspColor = 0; // 0 tells us not to try to match
297
298    if (!getBitmapConfig(png_ptr, info_ptr, &config, &hasAlpha, &doDither, &theTranspColor)) {
299        return false;
300    }
301
302    const int sampleSize = this->getSampleSize();
303    SkScaledBitmapSampler sampler(origWidth, origHeight, sampleSize);
304    decodedBitmap->setConfig(config, sampler.scaledWidth(), sampler.scaledHeight());
305
306    if (SkImageDecoder::kDecodeBounds_Mode == mode) {
307        return true;
308    }
309
310    // from here down we are concerned with colortables and pixels
311
312    // we track if we actually see a non-opaque pixels, since sometimes a PNG sets its colortype
313    // to |= PNG_COLOR_MASK_ALPHA, but all of its pixels are in fact opaque. We care, since we
314    // draw lots faster if we can flag the bitmap has being opaque
315    bool reallyHasAlpha = false;
316    SkColorTable* colorTable = NULL;
317
318    if (colorType == PNG_COLOR_TYPE_PALETTE) {
319        decodePalette(png_ptr, info_ptr, &hasAlpha, &reallyHasAlpha, &colorTable);
320    }
321
322    SkAutoUnref aur(colorTable);
323
324    if (!this->allocPixelRef(decodedBitmap,
325                             SkBitmap::kIndex8_Config == config ? colorTable : NULL)) {
326        return false;
327    }
328
329    SkAutoLockPixels alp(*decodedBitmap);
330
331    /* Turn on interlace handling.  REQUIRED if you are not using
332    *  png_read_image().  To see how to handle interlacing passes,
333    *  see the png_read_row() method below:
334    */
335    const int number_passes = (interlaceType != PNG_INTERLACE_NONE) ?
336                              png_set_interlace_handling(png_ptr) : 1;
337
338    /* Optional call to gamma correct and add the background to the palette
339    *  and update info structure.  REQUIRED if you are expecting libpng to
340    *  update the palette for you (ie you selected such a transform above).
341    */
342    png_read_update_info(png_ptr, info_ptr);
343
344    if ((SkBitmap::kA8_Config == config || SkBitmap::kIndex8_Config == config)
345        && 1 == sampleSize) {
346        // A8 is only allowed if the original was GRAY.
347        SkASSERT(config != SkBitmap::kA8_Config
348                 || PNG_COLOR_TYPE_GRAY == colorType);
349        for (int i = 0; i < number_passes; i++) {
350            for (png_uint_32 y = 0; y < origHeight; y++) {
351                uint8_t* bmRow = decodedBitmap->getAddr8(0, y);
352                png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1);
353            }
354        }
355    } else {
356        SkScaledBitmapSampler::SrcConfig sc;
357        int srcBytesPerPixel = 4;
358
359        if (colorTable != NULL) {
360            sc = SkScaledBitmapSampler::kIndex;
361            srcBytesPerPixel = 1;
362        } else if (SkBitmap::kA8_Config == config) {
363            // A8 is only allowed if the original was GRAY.
364            SkASSERT(PNG_COLOR_TYPE_GRAY == colorType);
365            sc = SkScaledBitmapSampler::kGray;
366            srcBytesPerPixel = 1;
367        } else if (hasAlpha) {
368            sc = SkScaledBitmapSampler::kRGBA;
369        } else {
370            sc = SkScaledBitmapSampler::kRGBX;
371        }
372
373        /*  We have to pass the colortable explicitly, since we may have one
374            even if our decodedBitmap doesn't, due to the request that we
375            upscale png's palette to a direct model
376         */
377        SkAutoLockColors ctLock(colorTable);
378        if (!sampler.begin(decodedBitmap, sc, doDither, ctLock.colors(),
379                           this->getRequireUnpremultipliedColors())) {
380            return false;
381        }
382        const int height = decodedBitmap->height();
383
384        if (number_passes > 1) {
385            SkAutoMalloc storage(origWidth * origHeight * srcBytesPerPixel);
386            uint8_t* base = (uint8_t*)storage.get();
387            size_t rowBytes = origWidth * srcBytesPerPixel;
388
389            for (int i = 0; i < number_passes; i++) {
390                uint8_t* row = base;
391                for (png_uint_32 y = 0; y < origHeight; y++) {
392                    uint8_t* bmRow = row;
393                    png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1);
394                    row += rowBytes;
395                }
396            }
397            // now sample it
398            base += sampler.srcY0() * rowBytes;
399            for (int y = 0; y < height; y++) {
400                reallyHasAlpha |= sampler.next(base);
401                base += sampler.srcDY() * rowBytes;
402            }
403        } else {
404            SkAutoMalloc storage(origWidth * srcBytesPerPixel);
405            uint8_t* srcRow = (uint8_t*)storage.get();
406            skip_src_rows(png_ptr, srcRow, sampler.srcY0());
407
408            for (int y = 0; y < height; y++) {
409                uint8_t* tmp = srcRow;
410                png_read_rows(png_ptr, &tmp, png_bytepp_NULL, 1);
411                reallyHasAlpha |= sampler.next(srcRow);
412                if (y < height - 1) {
413                    skip_src_rows(png_ptr, srcRow, sampler.srcDY() - 1);
414                }
415            }
416
417            // skip the rest of the rows (if any)
418            png_uint_32 read = (height - 1) * sampler.srcDY() +
419                               sampler.srcY0() + 1;
420            SkASSERT(read <= origHeight);
421            skip_src_rows(png_ptr, srcRow, origHeight - read);
422        }
423    }
424
425    /* read rest of file, and get additional chunks in info_ptr - REQUIRED */
426    png_read_end(png_ptr, info_ptr);
427
428    if (0 != theTranspColor) {
429        reallyHasAlpha |= substituteTranspColor(decodedBitmap, theTranspColor);
430    }
431    if (reallyHasAlpha && this->getRequireUnpremultipliedColors() &&
432        SkBitmap::kARGB_8888_Config != decodedBitmap->config()) {
433        // If the caller wants an unpremultiplied bitmap, and we let them get
434        // away with a config other than 8888, and it has alpha after all,
435        // return false, since the result will have premultiplied colors.
436        return false;
437    }
438    decodedBitmap->setIsOpaque(!reallyHasAlpha);
439    return true;
440}
441
442
443
444bool SkPNGImageDecoder::getBitmapConfig(png_structp png_ptr, png_infop info_ptr,
445                                        SkBitmap::Config* SK_RESTRICT configp,
446                                        bool* SK_RESTRICT hasAlphap,
447                                        bool* SK_RESTRICT doDitherp,
448                                        SkPMColor* SK_RESTRICT theTranspColorp) {
449    png_uint_32 origWidth, origHeight;
450    int bitDepth, colorType;
451    png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth,
452                 &colorType, int_p_NULL, int_p_NULL, int_p_NULL);
453
454    // check for sBIT chunk data, in case we should disable dithering because
455    // our data is not truely 8bits per component
456    png_color_8p sig_bit;
457    if (*doDitherp && png_get_sBIT(png_ptr, info_ptr, &sig_bit)) {
458#if 0
459        SkDebugf("----- sBIT %d %d %d %d\n", sig_bit->red, sig_bit->green,
460                 sig_bit->blue, sig_bit->alpha);
461#endif
462        // 0 seems to indicate no information available
463        if (pos_le(sig_bit->red, SK_R16_BITS) &&
464            pos_le(sig_bit->green, SK_G16_BITS) &&
465            pos_le(sig_bit->blue, SK_B16_BITS)) {
466            *doDitherp = false;
467        }
468    }
469
470    if (colorType == PNG_COLOR_TYPE_PALETTE) {
471        bool paletteHasAlpha = hasTransparencyInPalette(png_ptr, info_ptr);
472        *configp = this->getPrefConfig(kIndex_SrcDepth, paletteHasAlpha);
473        // now see if we can upscale to their requested config
474        if (!canUpscalePaletteToConfig(*configp, paletteHasAlpha)) {
475            *configp = SkBitmap::kIndex8_Config;
476        }
477    } else {
478        png_color_16p transpColor = NULL;
479        int numTransp = 0;
480
481        png_get_tRNS(png_ptr, info_ptr, NULL, &numTransp, &transpColor);
482
483        bool valid = png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS);
484
485        if (valid && numTransp == 1 && transpColor != NULL) {
486            /*  Compute our transparent color, which we'll match against later.
487                We don't really handle 16bit components properly here, since we
488                do our compare *after* the values have been knocked down to 8bit
489                which means we will find more matches than we should. The real
490                fix seems to be to see the actual 16bit components, do the
491                compare, and then knock it down to 8bits ourselves.
492            */
493            if (colorType & PNG_COLOR_MASK_COLOR) {
494                if (16 == bitDepth) {
495                    *theTranspColorp = SkPackARGB32(0xFF, transpColor->red >> 8,
496                                                    transpColor->green >> 8,
497                                                    transpColor->blue >> 8);
498                } else {
499                    *theTranspColorp = SkPackARGB32(0xFF, transpColor->red,
500                                                    transpColor->green,
501                                                    transpColor->blue);
502                }
503            } else {    // gray
504                if (16 == bitDepth) {
505                    *theTranspColorp = SkPackARGB32(0xFF, transpColor->gray >> 8,
506                                                    transpColor->gray >> 8,
507                                                    transpColor->gray >> 8);
508                } else {
509                    *theTranspColorp = SkPackARGB32(0xFF, transpColor->gray,
510                                                    transpColor->gray,
511                                                    transpColor->gray);
512                }
513            }
514        }
515
516        if (valid ||
517            PNG_COLOR_TYPE_RGB_ALPHA == colorType ||
518            PNG_COLOR_TYPE_GRAY_ALPHA == colorType) {
519            *hasAlphap = true;
520        }
521
522        SrcDepth srcDepth = k32Bit_SrcDepth;
523        if (PNG_COLOR_TYPE_GRAY == colorType) {
524            srcDepth = k8BitGray_SrcDepth;
525            // Remove this assert, which fails on desk_pokemonwiki.skp
526            //SkASSERT(!*hasAlphap);
527        }
528
529        *configp = this->getPrefConfig(srcDepth, *hasAlphap);
530        // now match the request against our capabilities
531        if (*hasAlphap) {
532            if (*configp != SkBitmap::kARGB_4444_Config) {
533                *configp = SkBitmap::kARGB_8888_Config;
534            }
535        } else {
536            if (*configp != SkBitmap::kRGB_565_Config &&
537                *configp != SkBitmap::kARGB_4444_Config &&
538                *configp != SkBitmap::kA8_Config) {
539                *configp = SkBitmap::kARGB_8888_Config;
540            }
541        }
542    }
543
544    // sanity check for size
545    {
546        Sk64 size;
547        size.setMul(origWidth, origHeight);
548        if (size.isNeg() || !size.is32()) {
549            return false;
550        }
551        // now check that if we are 4-bytes per pixel, we also don't overflow
552        if (size.get32() > (0x7FFFFFFF >> 2)) {
553            return false;
554        }
555    }
556
557    if (!this->chooseFromOneChoice(*configp, origWidth, origHeight)) {
558        return false;
559    }
560
561    // If the image has alpha and the decoder wants unpremultiplied
562    // colors, the only supported config is 8888.
563    if (this->getRequireUnpremultipliedColors() && *hasAlphap) {
564        *configp = SkBitmap::kARGB_8888_Config;
565    }
566
567    if (fImageIndex != NULL) {
568        if (SkBitmap::kNo_Config == fImageIndex->fConfig) {
569            // This is the first time for this subset decode. From now on,
570            // all decodes must be in the same config.
571            fImageIndex->fConfig = *configp;
572        } else if (fImageIndex->fConfig != *configp) {
573            // Requesting a different config for a subsequent decode is not
574            // supported. Report failure before we make changes to png_ptr.
575            return false;
576        }
577    }
578
579    bool convertGrayToRGB = PNG_COLOR_TYPE_GRAY == colorType
580                            && *configp != SkBitmap::kA8_Config;
581
582    // Unless the user is requesting A8, convert a grayscale image into RGB.
583    // GRAY_ALPHA will always be converted to RGB
584    if (convertGrayToRGB || colorType == PNG_COLOR_TYPE_GRAY_ALPHA) {
585        png_set_gray_to_rgb(png_ptr);
586    }
587
588    // Add filler (or alpha) byte (after each RGB triplet) if necessary.
589    if (colorType == PNG_COLOR_TYPE_RGB || convertGrayToRGB) {
590        png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
591    }
592
593    return true;
594}
595
596typedef uint32_t (*PackColorProc)(U8CPU a, U8CPU r, U8CPU g, U8CPU b);
597
598bool SkPNGImageDecoder::decodePalette(png_structp png_ptr, png_infop info_ptr,
599                                      bool *hasAlphap, bool *reallyHasAlphap,
600                                      SkColorTable **colorTablep) {
601    int numPalette;
602    png_colorp palette;
603    png_bytep trans;
604    int numTrans;
605    bool reallyHasAlpha = false;
606    SkColorTable* colorTable = NULL;
607
608    png_get_PLTE(png_ptr, info_ptr, &palette, &numPalette);
609
610    /*  BUGGY IMAGE WORKAROUND
611
612        We hit some images (e.g. fruit_.png) who contain bytes that are == colortable_count
613        which is a problem since we use the byte as an index. To work around this we grow
614        the colortable by 1 (if its < 256) and duplicate the last color into that slot.
615    */
616    int colorCount = numPalette + (numPalette < 256);
617
618    colorTable = SkNEW_ARGS(SkColorTable, (colorCount));
619
620    SkPMColor* colorPtr = colorTable->lockColors();
621    if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
622        png_get_tRNS(png_ptr, info_ptr, &trans, &numTrans, NULL);
623        *hasAlphap = (numTrans > 0);
624    } else {
625        numTrans = 0;
626        colorTable->setFlags(colorTable->getFlags() | SkColorTable::kColorsAreOpaque_Flag);
627    }
628    // check for bad images that might make us crash
629    if (numTrans > numPalette) {
630        numTrans = numPalette;
631    }
632
633    int index = 0;
634    int transLessThanFF = 0;
635
636    // Choose which function to use to create the color table. If the final destination's
637    // config is unpremultiplied, the color table will store unpremultiplied colors.
638    PackColorProc proc;
639    if (this->getRequireUnpremultipliedColors()) {
640        proc = &SkPackARGB32NoCheck;
641    } else {
642        proc = &SkPreMultiplyARGB;
643    }
644    for (; index < numTrans; index++) {
645        transLessThanFF |= (int)*trans - 0xFF;
646        *colorPtr++ = proc(*trans++, palette->red, palette->green, palette->blue);
647        palette++;
648    }
649    reallyHasAlpha |= (transLessThanFF < 0);
650
651    for (; index < numPalette; index++) {
652        *colorPtr++ = SkPackARGB32(0xFF, palette->red, palette->green, palette->blue);
653        palette++;
654    }
655
656    // see BUGGY IMAGE WORKAROUND comment above
657    if (numPalette < 256) {
658        *colorPtr = colorPtr[-1];
659    }
660    colorTable->unlockColors(true);
661    *colorTablep = colorTable;
662    *reallyHasAlphap = reallyHasAlpha;
663    return true;
664}
665
666#ifdef SK_BUILD_FOR_ANDROID
667
668bool SkPNGImageDecoder::onBuildTileIndex(SkStream* sk_stream, int *width, int *height) {
669    png_structp png_ptr;
670    png_infop   info_ptr;
671
672    if (!onDecodeInit(sk_stream, &png_ptr, &info_ptr)) {
673        return false;
674    }
675
676    if (setjmp(png_jmpbuf(png_ptr)) != 0) {
677        png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
678        return false;
679    }
680
681    png_uint_32 origWidth, origHeight;
682    int bitDepth, colorType;
683    png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth,
684                 &colorType, int_p_NULL, int_p_NULL, int_p_NULL);
685
686    *width = origWidth;
687    *height = origHeight;
688
689    png_build_index(png_ptr);
690
691    if (fImageIndex) {
692        SkDELETE(fImageIndex);
693    }
694    fImageIndex = SkNEW_ARGS(SkPNGImageIndex, (sk_stream, png_ptr, info_ptr));
695
696    return true;
697}
698
699bool SkPNGImageDecoder::onDecodeSubset(SkBitmap* bm, const SkIRect& region) {
700    if (NULL == fImageIndex) {
701        return false;
702    }
703
704    png_structp png_ptr = fImageIndex->fPng_ptr;
705    png_infop info_ptr = fImageIndex->fInfo_ptr;
706    if (setjmp(png_jmpbuf(png_ptr))) {
707        return false;
708    }
709
710    png_uint_32 origWidth, origHeight;
711    int bitDepth, colorType, interlaceType;
712    png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth,
713                 &colorType, &interlaceType, int_p_NULL, int_p_NULL);
714
715    SkIRect rect = SkIRect::MakeWH(origWidth, origHeight);
716
717    if (!rect.intersect(region)) {
718        // If the requested region is entirely outside the image, just
719        // returns false
720        return false;
721    }
722
723    SkBitmap::Config    config;
724    bool                hasAlpha = false;
725    bool                doDither = this->getDitherImage();
726    SkPMColor           theTranspColor = 0; // 0 tells us not to try to match
727
728    if (!getBitmapConfig(png_ptr, info_ptr, &config, &hasAlpha, &doDither, &theTranspColor)) {
729        return false;
730    }
731
732    const int sampleSize = this->getSampleSize();
733    SkScaledBitmapSampler sampler(origWidth, rect.height(), sampleSize);
734
735    SkBitmap decodedBitmap;
736    decodedBitmap.setConfig(config, sampler.scaledWidth(), sampler.scaledHeight());
737
738    // from here down we are concerned with colortables and pixels
739
740    // we track if we actually see a non-opaque pixels, since sometimes a PNG sets its colortype
741    // to |= PNG_COLOR_MASK_ALPHA, but all of its pixels are in fact opaque. We care, since we
742    // draw lots faster if we can flag the bitmap has being opaque
743    bool reallyHasAlpha = false;
744    SkColorTable* colorTable = NULL;
745
746    if (colorType == PNG_COLOR_TYPE_PALETTE) {
747        decodePalette(png_ptr, info_ptr, &hasAlpha, &reallyHasAlpha, &colorTable);
748    }
749
750    SkAutoUnref aur(colorTable);
751
752    // Check ahead of time if the swap(dest, src) is possible.
753    // If yes, then we will stick to AllocPixelRef since it's cheaper with the swap happening.
754    // If no, then we will use alloc to allocate pixels to prevent garbage collection.
755    int w = rect.width() / sampleSize;
756    int h = rect.height() / sampleSize;
757    const bool swapOnly = (rect == region) && (w == decodedBitmap.width()) &&
758                          (h == decodedBitmap.height()) && bm->isNull();
759    const bool needColorTable = SkBitmap::kIndex8_Config == config;
760    if (swapOnly) {
761        if (!this->allocPixelRef(&decodedBitmap, needColorTable ? colorTable : NULL)) {
762            return false;
763        }
764    } else {
765        if (!decodedBitmap.allocPixels(NULL, needColorTable ? colorTable : NULL)) {
766            return false;
767        }
768    }
769    SkAutoLockPixels alp(decodedBitmap);
770
771    /* Turn on interlace handling.  REQUIRED if you are not using
772    * png_read_image().  To see how to handle interlacing passes,
773    * see the png_read_row() method below:
774    */
775    const int number_passes = (interlaceType != PNG_INTERLACE_NONE) ?
776                              png_set_interlace_handling(png_ptr) : 1;
777
778    /* Optional call to gamma correct and add the background to the palette
779    * and update info structure.  REQUIRED if you are expecting libpng to
780    * update the palette for you (ie you selected such a transform above).
781    */
782
783    // Direct access to png_ptr fields is deprecated in libpng > 1.2.
784#if defined(PNG_1_0_X) || defined (PNG_1_2_X)
785    png_ptr->pass = 0;
786#else
787    // FIXME: This sets pass as desired, but also sets iwidth. Is that ok?
788    png_set_interlaced_pass(png_ptr, 0);
789#endif
790    png_read_update_info(png_ptr, info_ptr);
791
792    int actualTop = rect.fTop;
793
794    if ((SkBitmap::kA8_Config == config || SkBitmap::kIndex8_Config == config)
795        && 1 == sampleSize) {
796        // A8 is only allowed if the original was GRAY.
797        SkASSERT(config != SkBitmap::kA8_Config
798                 || PNG_COLOR_TYPE_GRAY == colorType);
799
800        for (int i = 0; i < number_passes; i++) {
801            png_configure_decoder(png_ptr, &actualTop, i);
802            for (int j = 0; j < rect.fTop - actualTop; j++) {
803                uint8_t* bmRow = decodedBitmap.getAddr8(0, 0);
804                png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1);
805            }
806            png_uint_32 bitmapHeight = (png_uint_32) decodedBitmap.height();
807            for (png_uint_32 y = 0; y < bitmapHeight; y++) {
808                uint8_t* bmRow = decodedBitmap.getAddr8(0, y);
809                png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1);
810            }
811        }
812    } else {
813        SkScaledBitmapSampler::SrcConfig sc;
814        int srcBytesPerPixel = 4;
815
816        if (colorTable != NULL) {
817            sc = SkScaledBitmapSampler::kIndex;
818            srcBytesPerPixel = 1;
819        } else if (SkBitmap::kA8_Config == config) {
820            // A8 is only allowed if the original was GRAY.
821            SkASSERT(PNG_COLOR_TYPE_GRAY == colorType);
822            sc = SkScaledBitmapSampler::kGray;
823            srcBytesPerPixel = 1;
824        } else if (hasAlpha) {
825            sc = SkScaledBitmapSampler::kRGBA;
826        } else {
827            sc = SkScaledBitmapSampler::kRGBX;
828        }
829
830        /*  We have to pass the colortable explicitly, since we may have one
831            even if our decodedBitmap doesn't, due to the request that we
832            upscale png's palette to a direct model
833         */
834        SkAutoLockColors ctLock(colorTable);
835        if (!sampler.begin(&decodedBitmap, sc, doDither, ctLock.colors(),
836                           this->getRequireUnpremultipliedColors())) {
837            return false;
838        }
839        const int height = decodedBitmap.height();
840
841        if (number_passes > 1) {
842            SkAutoMalloc storage(origWidth * origHeight * srcBytesPerPixel);
843            uint8_t* base = (uint8_t*)storage.get();
844            size_t rb = origWidth * srcBytesPerPixel;
845
846            for (int i = 0; i < number_passes; i++) {
847                png_configure_decoder(png_ptr, &actualTop, i);
848                for (int j = 0; j < rect.fTop - actualTop; j++) {
849                    uint8_t* bmRow = (uint8_t*)decodedBitmap.getPixels();
850                    png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1);
851                }
852                uint8_t* row = base;
853                for (int32_t y = 0; y < rect.height(); y++) {
854                    uint8_t* bmRow = row;
855                    png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1);
856                    row += rb;
857                }
858            }
859            // now sample it
860            base += sampler.srcY0() * rb;
861            for (int y = 0; y < height; y++) {
862                reallyHasAlpha |= sampler.next(base);
863                base += sampler.srcDY() * rb;
864            }
865        } else {
866            SkAutoMalloc storage(origWidth * srcBytesPerPixel);
867            uint8_t* srcRow = (uint8_t*)storage.get();
868
869            png_configure_decoder(png_ptr, &actualTop, 0);
870            skip_src_rows(png_ptr, srcRow, sampler.srcY0());
871
872            for (int i = 0; i < rect.fTop - actualTop; i++) {
873                uint8_t* bmRow = (uint8_t*)decodedBitmap.getPixels();
874                png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1);
875            }
876            for (int y = 0; y < height; y++) {
877                uint8_t* tmp = srcRow;
878                png_read_rows(png_ptr, &tmp, png_bytepp_NULL, 1);
879                reallyHasAlpha |= sampler.next(srcRow);
880                if (y < height - 1) {
881                    skip_src_rows(png_ptr, srcRow, sampler.srcDY() - 1);
882                }
883            }
884        }
885    }
886
887    if (0 != theTranspColor) {
888        reallyHasAlpha |= substituteTranspColor(&decodedBitmap, theTranspColor);
889    }
890    decodedBitmap.setIsOpaque(!reallyHasAlpha);
891
892    if (swapOnly) {
893        bm->swap(decodedBitmap);
894        return true;
895    }
896    return this->cropBitmap(bm, &decodedBitmap, sampleSize, region.x(), region.y(),
897                            region.width(), region.height(), 0, rect.y());
898}
899#endif
900
901///////////////////////////////////////////////////////////////////////////////
902
903#include "SkColorPriv.h"
904#include "SkUnPreMultiply.h"
905
906static void sk_write_fn(png_structp png_ptr, png_bytep data, png_size_t len) {
907    SkWStream* sk_stream = (SkWStream*)png_get_io_ptr(png_ptr);
908    if (!sk_stream->write(data, len)) {
909        png_error(png_ptr, "sk_write_fn Error!");
910    }
911}
912
913static transform_scanline_proc choose_proc(SkBitmap::Config config,
914                                           bool hasAlpha) {
915    // we don't care about search on alpha if we're kIndex8, since only the
916    // colortable packing cares about that distinction, not the pixels
917    if (SkBitmap::kIndex8_Config == config) {
918        hasAlpha = false;   // we store false in the table entries for kIndex8
919    }
920
921    static const struct {
922        SkBitmap::Config        fConfig;
923        bool                    fHasAlpha;
924        transform_scanline_proc fProc;
925    } gMap[] = {
926        { SkBitmap::kRGB_565_Config,    false,  transform_scanline_565 },
927        { SkBitmap::kARGB_8888_Config,  false,  transform_scanline_888 },
928        { SkBitmap::kARGB_8888_Config,  true,   transform_scanline_8888 },
929        { SkBitmap::kARGB_4444_Config,  false,  transform_scanline_444 },
930        { SkBitmap::kARGB_4444_Config,  true,   transform_scanline_4444 },
931        { SkBitmap::kIndex8_Config,     false,  transform_scanline_memcpy },
932    };
933
934    for (int i = SK_ARRAY_COUNT(gMap) - 1; i >= 0; --i) {
935        if (gMap[i].fConfig == config && gMap[i].fHasAlpha == hasAlpha) {
936            return gMap[i].fProc;
937        }
938    }
939    sk_throw();
940    return NULL;
941}
942
943// return the minimum legal bitdepth (by png standards) for this many colortable
944// entries. SkBitmap always stores in 8bits per pixel, but for colorcount <= 16,
945// we can use fewer bits per in png
946static int computeBitDepth(int colorCount) {
947#if 0
948    int bits = SkNextLog2(colorCount);
949    SkASSERT(bits >= 1 && bits <= 8);
950    // now we need bits itself to be a power of 2 (e.g. 1, 2, 4, 8)
951    return SkNextPow2(bits);
952#else
953    // for the moment, we don't know how to pack bitdepth < 8
954    return 8;
955#endif
956}
957
958/*  Pack palette[] with the corresponding colors, and if hasAlpha is true, also
959    pack trans[] and return the number of trans[] entries written. If hasAlpha
960    is false, the return value will always be 0.
961
962    Note: this routine takes care of unpremultiplying the RGB values when we
963    have alpha in the colortable, since png doesn't support premul colors
964*/
965static inline int pack_palette(SkColorTable* ctable,
966                               png_color* SK_RESTRICT palette,
967                               png_byte* SK_RESTRICT trans, bool hasAlpha) {
968    SkAutoLockColors alc(ctable);
969    const SkPMColor* SK_RESTRICT colors = alc.colors();
970    const int ctCount = ctable->count();
971    int i, num_trans = 0;
972
973    if (hasAlpha) {
974        /*  first see if we have some number of fully opaque at the end of the
975            ctable. PNG allows num_trans < num_palette, but all of the trans
976            entries must come first in the palette. If I was smarter, I'd
977            reorder the indices and ctable so that all non-opaque colors came
978            first in the palette. But, since that would slow down the encode,
979            I'm leaving the indices and ctable order as is, and just looking
980            at the tail of the ctable for opaqueness.
981        */
982        num_trans = ctCount;
983        for (i = ctCount - 1; i >= 0; --i) {
984            if (SkGetPackedA32(colors[i]) != 0xFF) {
985                break;
986            }
987            num_trans -= 1;
988        }
989
990        const SkUnPreMultiply::Scale* SK_RESTRICT table =
991                                            SkUnPreMultiply::GetScaleTable();
992
993        for (i = 0; i < num_trans; i++) {
994            const SkPMColor c = *colors++;
995            const unsigned a = SkGetPackedA32(c);
996            const SkUnPreMultiply::Scale s = table[a];
997            trans[i] = a;
998            palette[i].red = SkUnPreMultiply::ApplyScale(s, SkGetPackedR32(c));
999            palette[i].green = SkUnPreMultiply::ApplyScale(s,SkGetPackedG32(c));
1000            palette[i].blue = SkUnPreMultiply::ApplyScale(s, SkGetPackedB32(c));
1001        }
1002        // now fall out of this if-block to use common code for the trailing
1003        // opaque entries
1004    }
1005
1006    // these (remaining) entries are opaque
1007    for (i = num_trans; i < ctCount; i++) {
1008        SkPMColor c = *colors++;
1009        palette[i].red = SkGetPackedR32(c);
1010        palette[i].green = SkGetPackedG32(c);
1011        palette[i].blue = SkGetPackedB32(c);
1012    }
1013    return num_trans;
1014}
1015
1016class SkPNGImageEncoder : public SkImageEncoder {
1017protected:
1018    virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) SK_OVERRIDE;
1019private:
1020    bool doEncode(SkWStream* stream, const SkBitmap& bm,
1021                  const bool& hasAlpha, int colorType,
1022                  int bitDepth, SkBitmap::Config config,
1023                  png_color_8& sig_bit);
1024
1025    typedef SkImageEncoder INHERITED;
1026};
1027
1028bool SkPNGImageEncoder::onEncode(SkWStream* stream, const SkBitmap& bitmap,
1029                                 int /*quality*/) {
1030    SkBitmap::Config config = bitmap.getConfig();
1031
1032    const bool hasAlpha = !bitmap.isOpaque();
1033    int colorType = PNG_COLOR_MASK_COLOR;
1034    int bitDepth = 8;   // default for color
1035    png_color_8 sig_bit;
1036
1037    switch (config) {
1038        case SkBitmap::kIndex8_Config:
1039            colorType |= PNG_COLOR_MASK_PALETTE;
1040            // fall through to the ARGB_8888 case
1041        case SkBitmap::kARGB_8888_Config:
1042            sig_bit.red = 8;
1043            sig_bit.green = 8;
1044            sig_bit.blue = 8;
1045            sig_bit.alpha = 8;
1046            break;
1047        case SkBitmap::kARGB_4444_Config:
1048            sig_bit.red = 4;
1049            sig_bit.green = 4;
1050            sig_bit.blue = 4;
1051            sig_bit.alpha = 4;
1052            break;
1053        case SkBitmap::kRGB_565_Config:
1054            sig_bit.red = 5;
1055            sig_bit.green = 6;
1056            sig_bit.blue = 5;
1057            sig_bit.alpha = 0;
1058            break;
1059        default:
1060            return false;
1061    }
1062
1063    if (hasAlpha) {
1064        // don't specify alpha if we're a palette, even if our ctable has alpha
1065        if (!(colorType & PNG_COLOR_MASK_PALETTE)) {
1066            colorType |= PNG_COLOR_MASK_ALPHA;
1067        }
1068    } else {
1069        sig_bit.alpha = 0;
1070    }
1071
1072    SkAutoLockPixels alp(bitmap);
1073    // readyToDraw checks for pixels (and colortable if that is required)
1074    if (!bitmap.readyToDraw()) {
1075        return false;
1076    }
1077
1078    // we must do this after we have locked the pixels
1079    SkColorTable* ctable = bitmap.getColorTable();
1080    if (NULL != ctable) {
1081        if (ctable->count() == 0) {
1082            return false;
1083        }
1084        // check if we can store in fewer than 8 bits
1085        bitDepth = computeBitDepth(ctable->count());
1086    }
1087
1088    return doEncode(stream, bitmap, hasAlpha, colorType,
1089                    bitDepth, config, sig_bit);
1090}
1091
1092bool SkPNGImageEncoder::doEncode(SkWStream* stream, const SkBitmap& bitmap,
1093                  const bool& hasAlpha, int colorType,
1094                  int bitDepth, SkBitmap::Config config,
1095                  png_color_8& sig_bit) {
1096
1097    png_structp png_ptr;
1098    png_infop info_ptr;
1099
1100    png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, sk_error_fn,
1101                                      NULL);
1102    if (NULL == png_ptr) {
1103        return false;
1104    }
1105
1106    info_ptr = png_create_info_struct(png_ptr);
1107    if (NULL == info_ptr) {
1108        png_destroy_write_struct(&png_ptr,  png_infopp_NULL);
1109        return false;
1110    }
1111
1112    /* Set error handling.  REQUIRED if you aren't supplying your own
1113    * error handling functions in the png_create_write_struct() call.
1114    */
1115    if (setjmp(png_jmpbuf(png_ptr))) {
1116        png_destroy_write_struct(&png_ptr, &info_ptr);
1117        return false;
1118    }
1119
1120    png_set_write_fn(png_ptr, (void*)stream, sk_write_fn, png_flush_ptr_NULL);
1121
1122    /* Set the image information here.  Width and height are up to 2^31,
1123    * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
1124    * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
1125    * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
1126    * or PNG_COLOR_TYPE_RGB_ALPHA.  interlace is either PNG_INTERLACE_NONE or
1127    * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
1128    * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED
1129    */
1130
1131    png_set_IHDR(png_ptr, info_ptr, bitmap.width(), bitmap.height(),
1132                 bitDepth, colorType,
1133                 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE,
1134                 PNG_FILTER_TYPE_BASE);
1135
1136    // set our colortable/trans arrays if needed
1137    png_color paletteColors[256];
1138    png_byte trans[256];
1139    if (SkBitmap::kIndex8_Config == config) {
1140        SkColorTable* ct = bitmap.getColorTable();
1141        int numTrans = pack_palette(ct, paletteColors, trans, hasAlpha);
1142        png_set_PLTE(png_ptr, info_ptr, paletteColors, ct->count());
1143        if (numTrans > 0) {
1144            png_set_tRNS(png_ptr, info_ptr, trans, numTrans, NULL);
1145        }
1146    }
1147
1148    png_set_sBIT(png_ptr, info_ptr, &sig_bit);
1149    png_write_info(png_ptr, info_ptr);
1150
1151    const char* srcImage = (const char*)bitmap.getPixels();
1152    SkAutoSMalloc<1024> rowStorage(bitmap.width() << 2);
1153    char* storage = (char*)rowStorage.get();
1154    transform_scanline_proc proc = choose_proc(config, hasAlpha);
1155
1156    for (int y = 0; y < bitmap.height(); y++) {
1157        png_bytep row_ptr = (png_bytep)storage;
1158        proc(srcImage, bitmap.width(), storage);
1159        png_write_rows(png_ptr, &row_ptr, 1);
1160        srcImage += bitmap.rowBytes();
1161    }
1162
1163    png_write_end(png_ptr, info_ptr);
1164
1165    /* clean up after the write, and free any memory allocated */
1166    png_destroy_write_struct(&png_ptr, &info_ptr);
1167    return true;
1168}
1169
1170///////////////////////////////////////////////////////////////////////////////
1171DEFINE_DECODER_CREATOR(PNGImageDecoder);
1172DEFINE_ENCODER_CREATOR(PNGImageEncoder);
1173///////////////////////////////////////////////////////////////////////////////
1174
1175#include "SkTRegistry.h"
1176
1177static bool is_png(SkStream* stream) {
1178    char buf[PNG_BYTES_TO_CHECK];
1179    if (stream->read(buf, PNG_BYTES_TO_CHECK) == PNG_BYTES_TO_CHECK &&
1180        !png_sig_cmp((png_bytep) buf, (png_size_t)0, PNG_BYTES_TO_CHECK)) {
1181        return true;
1182    }
1183    return false;
1184}
1185
1186SkImageDecoder* sk_libpng_dfactory(SkStream* stream) {
1187    if (is_png(stream)) {
1188        return SkNEW(SkPNGImageDecoder);
1189    }
1190    return NULL;
1191}
1192
1193static SkImageDecoder::Format get_format_png(SkStream* stream) {
1194    if (is_png(stream)) {
1195        return SkImageDecoder::kPNG_Format;
1196    }
1197    return SkImageDecoder::kUnknown_Format;
1198}
1199
1200SkImageEncoder* sk_libpng_efactory(SkImageEncoder::Type t) {
1201    return (SkImageEncoder::kPNG_Type == t) ? SkNEW(SkPNGImageEncoder) : NULL;
1202}
1203
1204static SkTRegistry<SkImageEncoder*, SkImageEncoder::Type> gEReg(sk_libpng_efactory);
1205static SkTRegistry<SkImageDecoder::Format, SkStream*> gFormatReg(get_format_png);
1206static SkTRegistry<SkImageDecoder*, SkStream*> gDReg(sk_libpng_dfactory);
1207