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