aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/images/SkImageDecoder_libpng.cpp108
1 files changed, 78 insertions, 30 deletions
diff --git a/src/images/SkImageDecoder_libpng.cpp b/src/images/SkImageDecoder_libpng.cpp
index d59a67bf8e..4c44b9109c 100644
--- a/src/images/SkImageDecoder_libpng.cpp
+++ b/src/images/SkImageDecoder_libpng.cpp
@@ -42,18 +42,24 @@ extern "C" {
class SkPNGImageIndex {
public:
- SkPNGImageIndex(png_structp png_ptr, png_infop info_ptr) {
- this->png_ptr = png_ptr;
- this->info_ptr = info_ptr;
+ SkPNGImageIndex(SkStream* stream, png_structp png_ptr, png_infop info_ptr)
+ : fStream(stream)
+ , fPng_ptr(png_ptr)
+ , fInfo_ptr(info_ptr)
+ , fConfig(SkBitmap::kNo_Config) {
+ SkASSERT(stream != NULL);
+ stream->ref();
}
~SkPNGImageIndex() {
- if (NULL != png_ptr) {
- png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
+ if (NULL != fPng_ptr) {
+ png_destroy_read_struct(&fPng_ptr, &fInfo_ptr, png_infopp_NULL);
}
}
- png_structp png_ptr;
- png_infop info_ptr;
+ SkAutoTUnref<SkStream> fStream;
+ png_structp fPng_ptr;
+ png_infop fInfo_ptr;
+ SkBitmap::Config fConfig;
};
class SkPNGImageDecoder : public SkImageDecoder {
@@ -261,10 +267,6 @@ bool SkPNGImageDecoder::onDecodeInit(SkStream* sk_stream, png_structp *png_ptrp,
png_set_expand_gray_1_2_4_to_8(png_ptr);
}
- /* Make a grayscale image into RGB. */
- if (colorType == PNG_COLOR_TYPE_GRAY || colorType == PNG_COLOR_TYPE_GRAY_ALPHA) {
- png_set_gray_to_rgb(png_ptr);
- }
return true;
}
@@ -326,11 +328,6 @@ bool SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* decodedBitmap,
SkAutoLockPixels alp(*decodedBitmap);
- /* Add filler (or alpha) byte (before/after each RGB triplet) */
- if (colorType == PNG_COLOR_TYPE_RGB || colorType == PNG_COLOR_TYPE_GRAY) {
- png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
- }
-
/* 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:
@@ -344,7 +341,11 @@ bool SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* decodedBitmap,
*/
png_read_update_info(png_ptr, info_ptr);
- if (SkBitmap::kIndex8_Config == config && 1 == sampleSize) {
+ if ((SkBitmap::kA8_Config == config || SkBitmap::kIndex8_Config == config)
+ && 1 == sampleSize) {
+ // A8 is only allowed if the original was GRAY.
+ SkASSERT(config != SkBitmap::kA8_Config
+ || PNG_COLOR_TYPE_GRAY == colorType);
for (int i = 0; i < number_passes; i++) {
for (png_uint_32 y = 0; y < origHeight; y++) {
uint8_t* bmRow = decodedBitmap->getAddr8(0, y);
@@ -358,6 +359,11 @@ bool SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* decodedBitmap,
if (colorTable != NULL) {
sc = SkScaledBitmapSampler::kIndex;
srcBytesPerPixel = 1;
+ } else if (SkBitmap::kA8_Config == config) {
+ // A8 is only allowed if the original was GRAY.
+ SkASSERT(PNG_COLOR_TYPE_GRAY == colorType);
+ sc = SkScaledBitmapSampler::kGray;
+ srcBytesPerPixel = 1;
} else if (hasAlpha) {
sc = SkScaledBitmapSampler::kRGBA;
} else {
@@ -436,8 +442,10 @@ bool SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* decodedBitmap,
bool SkPNGImageDecoder::getBitmapConfig(png_structp png_ptr, png_infop info_ptr,
- SkBitmap::Config *configp, bool * SK_RESTRICT hasAlphap,
- bool *doDitherp, SkPMColor *theTranspColorp) {
+ SkBitmap::Config* SK_RESTRICT configp,
+ bool* SK_RESTRICT hasAlphap,
+ bool* SK_RESTRICT doDitherp,
+ SkPMColor* SK_RESTRICT theTranspColorp) {
png_uint_32 origWidth, origHeight;
int bitDepth, colorType;
png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth,
@@ -510,7 +518,14 @@ bool SkPNGImageDecoder::getBitmapConfig(png_structp png_ptr, png_infop info_ptr,
PNG_COLOR_TYPE_GRAY_ALPHA == colorType) {
*hasAlphap = true;
}
- *configp = this->getPrefConfig(k32Bit_SrcDepth, *hasAlphap);
+
+ SrcDepth srcDepth = k32Bit_SrcDepth;
+ if (PNG_COLOR_TYPE_GRAY == colorType) {
+ srcDepth = k8BitGray_SrcDepth;
+ SkASSERT(!*hasAlphap);
+ }
+
+ *configp = this->getPrefConfig(srcDepth, *hasAlphap);
// now match the request against our capabilities
if (*hasAlphap) {
if (*configp != SkBitmap::kARGB_4444_Config) {
@@ -518,7 +533,8 @@ bool SkPNGImageDecoder::getBitmapConfig(png_structp png_ptr, png_infop info_ptr,
}
} else {
if (*configp != SkBitmap::kRGB_565_Config &&
- *configp != SkBitmap::kARGB_4444_Config) {
+ *configp != SkBitmap::kARGB_4444_Config &&
+ *configp != SkBitmap::kA8_Config) {
*configp = SkBitmap::kARGB_8888_Config;
}
}
@@ -546,6 +562,33 @@ bool SkPNGImageDecoder::getBitmapConfig(png_structp png_ptr, png_infop info_ptr,
if (this->getRequireUnpremultipliedColors() && *hasAlphap) {
*configp = SkBitmap::kARGB_8888_Config;
}
+
+ if (fImageIndex != NULL) {
+ if (SkBitmap::kNo_Config == fImageIndex->fConfig) {
+ // This is the first time for this subset decode. From now on,
+ // all decodes must be in the same config.
+ fImageIndex->fConfig = *configp;
+ } else if (fImageIndex->fConfig != *configp) {
+ // Requesting a different config 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
+ && *configp != SkBitmap::kA8_Config;
+
+ // 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;
}
@@ -647,7 +690,7 @@ bool SkPNGImageDecoder::onBuildTileIndex(SkStream* sk_stream, int *width, int *h
if (fImageIndex) {
SkDELETE(fImageIndex);
}
- fImageIndex = SkNEW_ARGS(SkPNGImageIndex, (png_ptr, info_ptr));
+ fImageIndex = SkNEW_ARGS(SkPNGImageIndex, (sk_stream, png_ptr, info_ptr));
return true;
}
@@ -657,8 +700,8 @@ bool SkPNGImageDecoder::onDecodeSubset(SkBitmap* bm, const SkIRect& region) {
return false;
}
- png_structp png_ptr = fImageIndex->png_ptr;
- png_infop info_ptr = fImageIndex->info_ptr;
+ png_structp png_ptr = fImageIndex->fPng_ptr;
+ png_infop info_ptr = fImageIndex->fInfo_ptr;
if (setjmp(png_jmpbuf(png_ptr))) {
return false;
}
@@ -724,11 +767,6 @@ bool SkPNGImageDecoder::onDecodeSubset(SkBitmap* bm, const SkIRect& region) {
}
SkAutoLockPixels alp(decodedBitmap);
- /* Add filler (or alpha) byte (before/after each RGB triplet) */
- if (colorType == PNG_COLOR_TYPE_RGB || colorType == PNG_COLOR_TYPE_GRAY) {
- png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
- }
-
/* 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:
@@ -752,7 +790,12 @@ bool SkPNGImageDecoder::onDecodeSubset(SkBitmap* bm, const SkIRect& region) {
int actualTop = rect.fTop;
- if (SkBitmap::kIndex8_Config == config && 1 == sampleSize) {
+ if ((SkBitmap::kA8_Config == config || SkBitmap::kIndex8_Config == config)
+ && 1 == sampleSize) {
+ // A8 is only allowed if the original was GRAY.
+ SkASSERT(config != SkBitmap::kA8_Config
+ || PNG_COLOR_TYPE_GRAY == colorType);
+
for (int i = 0; i < number_passes; i++) {
png_configure_decoder(png_ptr, &actualTop, i);
for (int j = 0; j < rect.fTop - actualTop; j++) {
@@ -772,6 +815,11 @@ bool SkPNGImageDecoder::onDecodeSubset(SkBitmap* bm, const SkIRect& region) {
if (colorTable != NULL) {
sc = SkScaledBitmapSampler::kIndex;
srcBytesPerPixel = 1;
+ } else if (SkBitmap::kA8_Config == config) {
+ // A8 is only allowed if the original was GRAY.
+ SkASSERT(PNG_COLOR_TYPE_GRAY == colorType);
+ sc = SkScaledBitmapSampler::kGray;
+ srcBytesPerPixel = 1;
} else if (hasAlpha) {
sc = SkScaledBitmapSampler::kRGBA;
} else {