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