gfx/skia/trunk/src/images/SkImageDecoder_libpng.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

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

mercurial