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