Home | History | Annotate | Download | only in images
      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 
     22 extern "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 
     43 class SkPNGImageIndex {
     44 public:
     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 
     65 class SkPNGImageDecoder : public SkImageDecoder {
     66 public:
     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 
     78 protected:
     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 
     85 private:
     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 */
    106 struct 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     }
    111 private:
    112     png_structp png_ptr;
    113     png_infop info_ptr;
    114 };
    115 
    116 static 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
    125 static 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 
    134 static 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 
    142 static 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 
    147 static 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 
    154 static bool pos_le(int value, int max) {
    155     return value > 0 && value <= max;
    156 }
    157 
    158 static 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 
    176 static 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
    191 static 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 
    202 bool 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 
    275 bool 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 
    447 bool 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 
    602 typedef uint32_t (*PackColorProc)(U8CPU a, U8CPU r, U8CPU g, U8CPU b);
    603 
    604 bool 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 
    674 bool 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 
    705 bool 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 
    913 static 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 
    920 static 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
    953 static 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 */
    972 static 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 
   1023 class SkPNGImageEncoder : public SkImageEncoder {
   1024 protected:
   1025     virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) SK_OVERRIDE;
   1026 private:
   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 
   1035 bool 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 
   1099 bool 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 ///////////////////////////////////////////////////////////////////////////////
   1178 DEFINE_DECODER_CREATOR(PNGImageDecoder);
   1179 DEFINE_ENCODER_CREATOR(PNGImageEncoder);
   1180 ///////////////////////////////////////////////////////////////////////////////
   1181 
   1182 #include "SkTRegistry.h"
   1183 
   1184 static 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 
   1193 SkImageDecoder* sk_libpng_dfactory(SkStream* stream) {
   1194     if (is_png(stream)) {
   1195         return SkNEW(SkPNGImageDecoder);
   1196     }
   1197     return NULL;
   1198 }
   1199 
   1200 static 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 
   1207 SkImageEncoder* sk_libpng_efactory(SkImageEncoder::Type t) {
   1208     return (SkImageEncoder::kPNG_Type == t) ? SkNEW(SkPNGImageEncoder) : NULL;
   1209 }
   1210 
   1211 static SkTRegistry<SkImageEncoder*, SkImageEncoder::Type> gEReg(sk_libpng_efactory);
   1212 static SkTRegistry<SkImageDecoder::Format, SkStream*> gFormatReg(get_format_png);
   1213 static SkTRegistry<SkImageDecoder*, SkStream*> gDReg(sk_libpng_dfactory);
   1214