diff options
Diffstat (limited to 'src/images/SkImageDecoder_libpng.cpp')
-rw-r--r-- | src/images/SkImageDecoder_libpng.cpp | 683 |
1 files changed, 3 insertions, 680 deletions
diff --git a/src/images/SkImageDecoder_libpng.cpp b/src/images/SkImageDecoder_libpng.cpp index cd8152a36b..c3df5d10a8 100644 --- a/src/images/SkImageDecoder_libpng.cpp +++ b/src/images/SkImageDecoder_libpng.cpp @@ -5,14 +5,12 @@ * found in the LICENSE file. */ -#include "SkImageDecoder.h" #include "SkImageEncoder.h" #include "SkColor.h" #include "SkColorPriv.h" #include "SkDither.h" #include "SkMath.h" #include "SkRTConf.h" -#include "SkScaledBitmapSampler.h" #include "SkStream.h" #include "SkTemplates.h" #include "SkUtils.h" @@ -44,88 +42,10 @@ SK_CONF_DECLARE(bool, c_suppressPNGImageDecoderWarnings, "Suppress most PNG warnings when calling image decode " "functions."); -class SkPNGImageIndex { -public: - // Takes ownership of stream. - SkPNGImageIndex(SkStreamRewindable* stream, png_structp png_ptr, png_infop info_ptr) - : fStream(stream) - , fPng_ptr(png_ptr) - , fInfo_ptr(info_ptr) - , fColorType(kUnknown_SkColorType) { - SkASSERT(stream != nullptr); - } - ~SkPNGImageIndex() { - if (fPng_ptr) { - png_destroy_read_struct(&fPng_ptr, &fInfo_ptr, png_infopp_NULL); - } - } - - SkAutoTDelete<SkStreamRewindable> fStream; - png_structp fPng_ptr; - png_infop fInfo_ptr; - SkColorType fColorType; -}; - -class SkPNGImageDecoder : public SkImageDecoder { -public: - SkPNGImageDecoder() { - fImageIndex = nullptr; - } - Format getFormat() const override { - return kPNG_Format; - } - - virtual ~SkPNGImageDecoder() { delete fImageIndex; } - -protected: - Result onDecode(SkStream* stream, SkBitmap* bm, Mode) override; - -private: - SkPNGImageIndex* fImageIndex; - - bool onDecodeInit(SkStream* stream, png_structp *png_ptrp, png_infop *info_ptrp); - bool decodePalette(png_structp png_ptr, png_infop info_ptr, int bitDepth, - bool * SK_RESTRICT hasAlphap, bool *reallyHasAlphap, - SkColorTable **colorTablep); - bool getBitmapColorType(png_structp, png_infop, SkColorType*, bool* hasAlpha, - SkPMColor* theTranspColor); - - typedef SkImageDecoder INHERITED; -}; - -#ifndef png_jmpbuf -# define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) -#endif - -#define PNG_BYTES_TO_CHECK 4 - -/* Automatically clean up after throwing an exception */ -struct PNGAutoClean { - PNGAutoClean(png_structp p, png_infop i): png_ptr(p), info_ptr(i) {} - ~PNGAutoClean() { - png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); - } -private: - png_structp png_ptr; - png_infop info_ptr; -}; - -static void sk_read_fn(png_structp png_ptr, png_bytep data, png_size_t length) { - SkStream* sk_stream = (SkStream*) png_get_io_ptr(png_ptr); - size_t bytes = sk_stream->read(data, length); - if (bytes != length) { - png_error(png_ptr, "Read Error!"); - } -} +/////////////////////////////////////////////////////////////////////////////// -#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED -static int sk_read_user_chunk(png_structp png_ptr, png_unknown_chunkp chunk) { - SkPngChunkReader* peeker = (SkPngChunkReader*)png_get_user_chunk_ptr(png_ptr); - // readChunk() returning true means continue decoding - return peeker->readChunk((const char*)chunk->name, chunk->data, chunk->size) ? - 1 : -1; -} -#endif +#include "SkColorPriv.h" +#include "SkUnPreMultiply.h" static void sk_error_fn(png_structp png_ptr, png_const_charp msg) { if (!c_suppressPNGImageDecoderWarnings) { @@ -134,577 +54,6 @@ static void sk_error_fn(png_structp png_ptr, png_const_charp msg) { longjmp(png_jmpbuf(png_ptr), 1); } -static void skip_src_rows(png_structp png_ptr, uint8_t storage[], int count) { - for (int i = 0; i < count; i++) { - uint8_t* tmp = storage; - png_read_rows(png_ptr, &tmp, png_bytepp_NULL, 1); - } -} - -static bool pos_le(int value, int max) { - return value > 0 && value <= max; -} - -static bool substituteTranspColor(SkBitmap* bm, SkPMColor match) { - SkASSERT(bm->colorType() == kN32_SkColorType); - - bool reallyHasAlpha = false; - - for (int y = bm->height() - 1; y >= 0; --y) { - SkPMColor* p = bm->getAddr32(0, y); - for (int x = bm->width() - 1; x >= 0; --x) { - if (match == *p) { - *p = 0; - reallyHasAlpha = true; - } - p += 1; - } - } - return reallyHasAlpha; -} - -static bool canUpscalePaletteToConfig(SkColorType dstColorType, bool srcHasAlpha) { - switch (dstColorType) { - case kN32_SkColorType: - case kARGB_4444_SkColorType: - return true; - case kRGB_565_SkColorType: - // only return true if the src is opaque (since 565 is opaque) - return !srcHasAlpha; - default: - return false; - } -} - -// call only if color_type is PALETTE. Returns true if the ctable has alpha -static bool hasTransparencyInPalette(png_structp png_ptr, png_infop info_ptr) { - png_bytep trans; - int num_trans; - - if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { - png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, nullptr); - return num_trans > 0; - } - return false; -} - -void do_nothing_warning_fn(png_structp, png_const_charp) { - /* do nothing */ -} - -bool SkPNGImageDecoder::onDecodeInit(SkStream* sk_stream, png_structp *png_ptrp, - png_infop *info_ptrp) { - /* Create and initialize the png_struct with the desired error handler - * functions. If you want to use the default stderr and longjump method, - * you can supply nullptr for the last three parameters. We also supply the - * the compiler header file version, so that we know if the application - * was compiled with a compatible version of the library. */ - - png_error_ptr user_warning_fn = - (c_suppressPNGImageDecoderWarnings) ? (&do_nothing_warning_fn) : nullptr; - /* nullptr means to leave as default library behavior. */ - /* c_suppressPNGImageDecoderWarnings default depends on SK_DEBUG. */ - /* To suppress warnings with a SK_DEBUG binary, set the - * environment variable "skia_images_png_suppressDecoderWarnings" - * to "true". Inside a program that links to skia: - * SK_CONF_SET("images.png.suppressDecoderWarnings", true); */ - - png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, - nullptr, sk_error_fn, user_warning_fn); - // png_voidp user_error_ptr, user_error_fn, user_warning_fn); - if (png_ptr == nullptr) { - return false; - } - - *png_ptrp = png_ptr; - - /* Allocate/initialize the memory for image information. */ - png_infop info_ptr = png_create_info_struct(png_ptr); - if (info_ptr == nullptr) { - png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL); - return false; - } - *info_ptrp = info_ptr; - - /* Set error handling if you are using the setjmp/longjmp method (this is - * the normal method of doing things with libpng). REQUIRED unless you - * set up your own error handlers in the png_create_read_struct() earlier. - */ - if (setjmp(png_jmpbuf(png_ptr))) { - png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); - return false; - } - - /* If you are using replacement read functions, instead of calling - * png_init_io() here you would call: - */ - png_set_read_fn(png_ptr, (void *)sk_stream, sk_read_fn); - /* where user_io_ptr is a structure you want available to the callbacks */ - /* If we have already read some of the signature */ -// png_set_sig_bytes(png_ptr, 0 /* sig_read */ ); - -#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED - // hookup our peeker so we can see any user-chunks the caller may be interested in - png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*)"", 0); - if (this->getPeeker()) { - png_set_read_user_chunk_fn(png_ptr, (png_voidp)this->getPeeker(), sk_read_user_chunk); - } -#endif - /* The call to png_read_info() gives us all of the information from the - * PNG file before the first IDAT (image data chunk). */ - png_read_info(png_ptr, info_ptr); - png_uint_32 origWidth, origHeight; - int bitDepth, colorType; - png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth, - &colorType, int_p_NULL, int_p_NULL, int_p_NULL); - - /* tell libpng to strip 16 bit/color files down to 8 bits/color */ - if (bitDepth == 16) { - png_set_strip_16(png_ptr); - } -#ifdef PNG_READ_PACK_SUPPORTED - /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single - * byte into separate bytes (useful for paletted and grayscale images). */ - if (bitDepth < 8) { - png_set_packing(png_ptr); - } -#endif - /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */ - if (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8) { - png_set_expand_gray_1_2_4_to_8(png_ptr); - } - - return true; -} - -SkImageDecoder::Result SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* decodedBitmap, - Mode mode) { - png_structp png_ptr; - png_infop info_ptr; - - if (!onDecodeInit(sk_stream, &png_ptr, &info_ptr)) { - return kFailure; - } - - PNGAutoClean autoClean(png_ptr, info_ptr); - - if (setjmp(png_jmpbuf(png_ptr))) { - return kFailure; - } - - png_uint_32 origWidth, origHeight; - int bitDepth, pngColorType, interlaceType; - png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth, - &pngColorType, &interlaceType, int_p_NULL, int_p_NULL); - - SkColorType colorType; - bool hasAlpha = false; - SkPMColor theTranspColor = 0; // 0 tells us not to try to match - - if (!this->getBitmapColorType(png_ptr, info_ptr, &colorType, &hasAlpha, &theTranspColor)) { - return kFailure; - } - - SkAlphaType alphaType = this->getRequireUnpremultipliedColors() ? - kUnpremul_SkAlphaType : kPremul_SkAlphaType; - const int sampleSize = this->getSampleSize(); - SkScaledBitmapSampler sampler(origWidth, origHeight, sampleSize); - decodedBitmap->setInfo(SkImageInfo::Make(sampler.scaledWidth(), sampler.scaledHeight(), - colorType, alphaType)); - - if (SkImageDecoder::kDecodeBounds_Mode == mode) { - return kSuccess; - } - - // from here down we are concerned with colortables and pixels - - // we track if we actually see a non-opaque pixels, since sometimes a PNG sets its colortype - // to |= PNG_COLOR_MASK_ALPHA, but all of its pixels are in fact opaque. We care, since we - // draw lots faster if we can flag the bitmap has being opaque - bool reallyHasAlpha = false; - SkColorTable* colorTable = nullptr; - - if (pngColorType == PNG_COLOR_TYPE_PALETTE) { - decodePalette(png_ptr, info_ptr, bitDepth, &hasAlpha, &reallyHasAlpha, &colorTable); - } - - SkAutoUnref aur(colorTable); - - if (!this->allocPixelRef(decodedBitmap, - kIndex_8_SkColorType == colorType ? colorTable : nullptr)) { - return kFailure; - } - - SkAutoLockPixels alp(*decodedBitmap); - - // Repeat setjmp, otherwise variables declared since the last call (e.g. alp - // and aur) won't get their destructors called in case of a failure. - if (setjmp(png_jmpbuf(png_ptr))) { - return kFailure; - } - - /* Turn on interlace handling. REQUIRED if you are not using - * png_read_image(). To see how to handle interlacing passes, - * see the png_read_row() method below: - */ - const int number_passes = (interlaceType != PNG_INTERLACE_NONE) ? - png_set_interlace_handling(png_ptr) : 1; - - /* Optional call to gamma correct and add the background to the palette - * and update info structure. REQUIRED if you are expecting libpng to - * update the palette for you (ie you selected such a transform above). - */ - png_read_update_info(png_ptr, info_ptr); - - if ((kAlpha_8_SkColorType == colorType || kIndex_8_SkColorType == colorType) && - 1 == sampleSize) { - if (kAlpha_8_SkColorType == colorType) { - // For an A8 bitmap, we assume there is an alpha for speed. It is - // possible the bitmap is opaque, but that is an unlikely use case - // since it would not be very interesting. - reallyHasAlpha = true; - // A8 is only allowed if the original was GRAY. - SkASSERT(PNG_COLOR_TYPE_GRAY == pngColorType); - } - for (int i = 0; i < number_passes; i++) { - for (png_uint_32 y = 0; y < origHeight; y++) { - uint8_t* bmRow = decodedBitmap->getAddr8(0, y); - png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1); - } - } - } else { - SkScaledBitmapSampler::SrcConfig sc; - int srcBytesPerPixel = 4; - - if (colorTable != nullptr) { - sc = SkScaledBitmapSampler::kIndex; - srcBytesPerPixel = 1; - } else if (kAlpha_8_SkColorType == colorType) { - // A8 is only allowed if the original was GRAY. - SkASSERT(PNG_COLOR_TYPE_GRAY == pngColorType); - sc = SkScaledBitmapSampler::kGray; - srcBytesPerPixel = 1; - } else if (hasAlpha) { - sc = SkScaledBitmapSampler::kRGBA; - } else { - sc = SkScaledBitmapSampler::kRGBX; - } - - /* We have to pass the colortable explicitly, since we may have one - even if our decodedBitmap doesn't, due to the request that we - upscale png's palette to a direct model - */ - const SkPMColor* colors = colorTable ? colorTable->readColors() : nullptr; - if (!sampler.begin(decodedBitmap, sc, *this, colors)) { - return kFailure; - } - const int height = decodedBitmap->height(); - - if (number_passes > 1) { - SkAutoTMalloc<uint8_t> storage(origWidth * origHeight * srcBytesPerPixel); - uint8_t* base = storage.get(); - size_t rowBytes = origWidth * srcBytesPerPixel; - - for (int i = 0; i < number_passes; i++) { - uint8_t* row = base; - for (png_uint_32 y = 0; y < origHeight; y++) { - uint8_t* bmRow = row; - png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1); - row += rowBytes; - } - } - // now sample it - base += sampler.srcY0() * rowBytes; - for (int y = 0; y < height; y++) { - reallyHasAlpha |= sampler.next(base); - base += sampler.srcDY() * rowBytes; - } - } else { - SkAutoTMalloc<uint8_t> storage(origWidth * srcBytesPerPixel); - uint8_t* srcRow = storage.get(); - skip_src_rows(png_ptr, srcRow, sampler.srcY0()); - - for (int y = 0; y < height; y++) { - uint8_t* tmp = srcRow; - png_read_rows(png_ptr, &tmp, png_bytepp_NULL, 1); - reallyHasAlpha |= sampler.next(srcRow); - if (y < height - 1) { - skip_src_rows(png_ptr, srcRow, sampler.srcDY() - 1); - } - } - - // skip the rest of the rows (if any) - png_uint_32 read = (height - 1) * sampler.srcDY() + - sampler.srcY0() + 1; - SkASSERT(read <= origHeight); - skip_src_rows(png_ptr, srcRow, origHeight - read); - } - } - - /* read rest of file, and get additional chunks in info_ptr - REQUIRED */ - png_read_end(png_ptr, info_ptr); - - if (0 != theTranspColor) { - reallyHasAlpha |= substituteTranspColor(decodedBitmap, theTranspColor); - } - if (reallyHasAlpha && this->getRequireUnpremultipliedColors()) { - switch (decodedBitmap->colorType()) { - case kIndex_8_SkColorType: - // Fall through. - case kARGB_4444_SkColorType: - // We have chosen not to support unpremul for these colortypes. - return kFailure; - default: { - // Fall through to finish the decode. This colortype either - // supports unpremul or it is irrelevant because it has no - // alpha (or only alpha). - // These brackets prevent a warning. - } - } - } - - if (!reallyHasAlpha) { - decodedBitmap->setAlphaType(kOpaque_SkAlphaType); - } - return kSuccess; -} - - - -bool SkPNGImageDecoder::getBitmapColorType(png_structp png_ptr, png_infop info_ptr, - SkColorType* colorTypep, - bool* hasAlphap, - SkPMColor* SK_RESTRICT theTranspColorp) { - png_uint_32 origWidth, origHeight; - int bitDepth, colorType; - png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth, - &colorType, int_p_NULL, int_p_NULL, int_p_NULL); - -#ifdef PNG_sBIT_SUPPORTED - // check for sBIT chunk data, in case we should disable dithering because - // our data is not truely 8bits per component - png_color_8p sig_bit; - if (this->getDitherImage() && png_get_sBIT(png_ptr, info_ptr, &sig_bit)) { -#if 0 - SkDebugf("----- sBIT %d %d %d %d\n", sig_bit->red, sig_bit->green, - sig_bit->blue, sig_bit->alpha); -#endif - // 0 seems to indicate no information available - if (pos_le(sig_bit->red, SK_R16_BITS) && - pos_le(sig_bit->green, SK_G16_BITS) && - pos_le(sig_bit->blue, SK_B16_BITS)) { - this->setDitherImage(false); - } - } -#endif - - if (colorType == PNG_COLOR_TYPE_PALETTE) { - bool paletteHasAlpha = hasTransparencyInPalette(png_ptr, info_ptr); - *colorTypep = this->getPrefColorType(kIndex_SrcDepth, paletteHasAlpha); - // now see if we can upscale to their requested colortype - if (!canUpscalePaletteToConfig(*colorTypep, paletteHasAlpha)) { - *colorTypep = kIndex_8_SkColorType; - } - } else { - png_color_16p transpColor = nullptr; - int numTransp = 0; - - png_get_tRNS(png_ptr, info_ptr, nullptr, &numTransp, &transpColor); - - bool valid = png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS); - - if (valid && numTransp == 1 && transpColor != nullptr) { - /* Compute our transparent color, which we'll match against later. - We don't really handle 16bit components properly here, since we - do our compare *after* the values have been knocked down to 8bit - which means we will find more matches than we should. The real - fix seems to be to see the actual 16bit components, do the - compare, and then knock it down to 8bits ourselves. - */ - if (colorType & PNG_COLOR_MASK_COLOR) { - if (16 == bitDepth) { - *theTranspColorp = SkPackARGB32(0xFF, transpColor->red >> 8, - transpColor->green >> 8, - transpColor->blue >> 8); - } else { - /* We apply the mask because in a very small - number of corrupt PNGs, (transpColor->red > 255) - and (bitDepth == 8), for certain versions of libpng. */ - *theTranspColorp = SkPackARGB32(0xFF, - 0xFF & (transpColor->red), - 0xFF & (transpColor->green), - 0xFF & (transpColor->blue)); - } - } else { // gray - if (16 == bitDepth) { - *theTranspColorp = SkPackARGB32(0xFF, transpColor->gray >> 8, - transpColor->gray >> 8, - transpColor->gray >> 8); - } else { - /* We apply the mask because in a very small - number of corrupt PNGs, (transpColor->red > - 255) and (bitDepth == 8), for certain versions - of libpng. For safety we assume the same could - happen with a grayscale PNG. */ - *theTranspColorp = SkPackARGB32(0xFF, - 0xFF & (transpColor->gray), - 0xFF & (transpColor->gray), - 0xFF & (transpColor->gray)); - } - } - } - - if (valid || - PNG_COLOR_TYPE_RGB_ALPHA == colorType || - PNG_COLOR_TYPE_GRAY_ALPHA == colorType) { - *hasAlphap = true; - } - - SrcDepth srcDepth = k32Bit_SrcDepth; - if (PNG_COLOR_TYPE_GRAY == colorType) { - srcDepth = k8BitGray_SrcDepth; - // Remove this assert, which fails on desk_pokemonwiki.skp - //SkASSERT(!*hasAlphap); - } - - *colorTypep = this->getPrefColorType(srcDepth, *hasAlphap); - // now match the request against our capabilities - if (*hasAlphap) { - if (*colorTypep != kARGB_4444_SkColorType) { - *colorTypep = kN32_SkColorType; - } - } else { - if (kAlpha_8_SkColorType == *colorTypep) { - if (k8BitGray_SrcDepth != srcDepth) { - // Converting a non grayscale image to A8 is not currently supported. - *colorTypep = kN32_SkColorType; - } - } else if (*colorTypep != kRGB_565_SkColorType && - *colorTypep != kARGB_4444_SkColorType) { - *colorTypep = kN32_SkColorType; - } - } - } - - // sanity check for size - { - int64_t size = sk_64_mul(origWidth, origHeight); - // now check that if we are 4-bytes per pixel, we also don't overflow - if (size < 0 || size > (0x7FFFFFFF >> 2)) { - return false; - } - } - - // If the image has alpha and the decoder wants unpremultiplied - // colors, the only supported colortype is 8888. - if (this->getRequireUnpremultipliedColors() && *hasAlphap) { - *colorTypep = kN32_SkColorType; - } - - if (fImageIndex != nullptr) { - if (kUnknown_SkColorType == fImageIndex->fColorType) { - // This is the first time for this subset decode. From now on, - // all decodes must be in the same colortype. - fImageIndex->fColorType = *colorTypep; - } else if (fImageIndex->fColorType != *colorTypep) { - // Requesting a different colortype for a subsequent decode is not - // supported. Report failure before we make changes to png_ptr. - return false; - } - } - - bool convertGrayToRGB = PNG_COLOR_TYPE_GRAY == colorType && *colorTypep != kAlpha_8_SkColorType; - - // Unless the user is requesting A8, convert a grayscale image into RGB. - // GRAY_ALPHA will always be converted to RGB - if (convertGrayToRGB || colorType == PNG_COLOR_TYPE_GRAY_ALPHA) { - png_set_gray_to_rgb(png_ptr); - } - - // Add filler (or alpha) byte (after each RGB triplet) if necessary. - if (colorType == PNG_COLOR_TYPE_RGB || convertGrayToRGB) { - png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); - } - - return true; -} - -typedef uint32_t (*PackColorProc)(U8CPU a, U8CPU r, U8CPU g, U8CPU b); - -bool SkPNGImageDecoder::decodePalette(png_structp png_ptr, png_infop info_ptr, - int bitDepth, bool *hasAlphap, - bool *reallyHasAlphap, - SkColorTable **colorTablep) { - int numPalette; - png_colorp palette; - png_bytep trans; - int numTrans; - - png_get_PLTE(png_ptr, info_ptr, &palette, &numPalette); - - SkPMColor colorStorage[256]; // worst-case storage - SkPMColor* colorPtr = colorStorage; - - if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { - png_get_tRNS(png_ptr, info_ptr, &trans, &numTrans, nullptr); - *hasAlphap = (numTrans > 0); - } else { - numTrans = 0; - } - - // check for bad images that might make us crash - if (numTrans > numPalette) { - numTrans = numPalette; - } - - int index = 0; - int transLessThanFF = 0; - - // Choose which function to use to create the color table. If the final destination's - // colortype is unpremultiplied, the color table will store unpremultiplied colors. - PackColorProc proc; - if (this->getRequireUnpremultipliedColors()) { - proc = &SkPackARGB32NoCheck; - } else { - proc = &SkPreMultiplyARGB; - } - for (; index < numTrans; index++) { - transLessThanFF |= (int)*trans - 0xFF; - *colorPtr++ = proc(*trans++, palette->red, palette->green, palette->blue); - palette++; - } - bool reallyHasAlpha = (transLessThanFF < 0); - - for (; index < numPalette; index++) { - *colorPtr++ = SkPackARGB32(0xFF, palette->red, palette->green, palette->blue); - palette++; - } - - /* BUGGY IMAGE WORKAROUND - - Invalid images could contain pixel values that are greater than the number of palette - entries. Since we use pixel values as indices into the palette this could result in reading - beyond the end of the palette which could leak the contents of uninitialized memory. To - ensure this doesn't happen, we grow the colortable to the maximum size that can be - addressed by the bitdepth of the image and fill it with the last palette color or black if - the palette is empty (really broken image). - */ - int colorCount = SkTMax(numPalette, 1 << SkTMin(bitDepth, 8)); - SkPMColor lastColor = index > 0 ? colorPtr[-1] : SkPackARGB32(0xFF, 0, 0, 0); - for (; index < colorCount; index++) { - *colorPtr++ = lastColor; - } - - *colorTablep = new SkColorTable(colorStorage, colorCount); - *reallyHasAlphap = reallyHasAlpha; - return true; -} - -/////////////////////////////////////////////////////////////////////////////// - -#include "SkColorPriv.h" -#include "SkUnPreMultiply.h" - static void sk_write_fn(png_structp png_ptr, png_bytep data, png_size_t len) { SkWStream* sk_stream = (SkWStream*)png_get_io_ptr(png_ptr); if (!sk_stream->write(data, len)) { @@ -985,37 +334,11 @@ bool SkPNGImageEncoder::doEncode(SkWStream* stream, const SkBitmap& bitmap, } /////////////////////////////////////////////////////////////////////////////// -DEFINE_DECODER_CREATOR(PNGImageDecoder); DEFINE_ENCODER_CREATOR(PNGImageEncoder); /////////////////////////////////////////////////////////////////////////////// -static bool is_png(SkStreamRewindable* stream) { - char buf[PNG_BYTES_TO_CHECK]; - if (stream->read(buf, PNG_BYTES_TO_CHECK) == PNG_BYTES_TO_CHECK && - !png_sig_cmp((png_bytep) buf, (png_size_t)0, PNG_BYTES_TO_CHECK)) { - return true; - } - return false; -} - -SkImageDecoder* sk_libpng_dfactory(SkStreamRewindable* stream) { - if (is_png(stream)) { - return new SkPNGImageDecoder; - } - return nullptr; -} - -static SkImageDecoder::Format get_format_png(SkStreamRewindable* stream) { - if (is_png(stream)) { - return SkImageDecoder::kPNG_Format; - } - return SkImageDecoder::kUnknown_Format; -} - SkImageEncoder* sk_libpng_efactory(SkImageEncoder::Type t) { return (SkImageEncoder::kPNG_Type == t) ? new SkPNGImageEncoder : nullptr; } -static SkImageDecoder_DecodeReg gDReg(sk_libpng_dfactory); -static SkImageDecoder_FormatReg gFormatReg(get_format_png); static SkImageEncoder_EncodeReg gEReg(sk_libpng_efactory); |