aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/images
diff options
context:
space:
mode:
authorGravatar scroggo@google.com <scroggo@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-07-18 20:03:15 +0000
committerGravatar scroggo@google.com <scroggo@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2013-07-18 20:03:15 +0000
commitc70a3aa39bd3bf8e34906feecce5ae87f668e7d8 (patch)
treee8527b75b9cb327028ef6418d170959d34b66bd8 /src/images
parenteed6f1b76b6690796e3d40993b1504ba1eca2df5 (diff)
Support decoding Gray to A8 in PNG.
Move the code which sets the filler and forces gray to rgb after we get the config, so we can skip them if the caller wants A8. Call set_gray_to_rgb consistently for both normal decode and subset decode. In PNG, prevent subset decodes from alternating configs, which would otherwise fail. Use SK_RESTRICT for pointers in getBitmapConfig. Ref the SkStream input to buildTileIndex, so it will not be destroyed before calling decodeSubset. Convert some fields to match Skia style. Builds on https://codereview.chromium.org/18083026/, which has not yet been checked in. R=reed@google.com Review URL: https://codereview.chromium.org/19185006 git-svn-id: http://skia.googlecode.com/svn/trunk@10162 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src/images')
-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 {