Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(63)

Unified Diff: src/codec/SkPngCodec.cpp

Issue 1643623004: A variety of SkPngCodec clean-ups (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Change comment Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/codec/SkPngCodec.cpp
diff --git a/src/codec/SkPngCodec.cpp b/src/codec/SkPngCodec.cpp
index 9691f12d4d6b210245d1a0992b5853a20b5fb3cc..c77f9212252c329194ae7e0b2d089dcbb9ac89a3 100644
--- a/src/codec/SkPngCodec.cpp
+++ b/src/codec/SkPngCodec.cpp
@@ -10,6 +10,7 @@
#include "SkColorTable.h"
#include "SkBitmap.h"
#include "SkMath.h"
+#include "SkOpts.h"
#include "SkPngCodec.h"
#include "SkPngFilters.h"
#include "SkSize.h"
@@ -35,31 +36,6 @@
#endif
///////////////////////////////////////////////////////////////////////////////
-// Helper macros
-///////////////////////////////////////////////////////////////////////////////
-
-#ifndef png_jmpbuf
-# define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
-#endif
-
-/* These were dropped in libpng >= 1.4 */
-#ifndef png_infopp_NULL
- #define png_infopp_NULL nullptr
-#endif
-
-#ifndef png_bytepp_NULL
- #define png_bytepp_NULL nullptr
-#endif
-
-#ifndef int_p_NULL
- #define int_p_NULL nullptr
-#endif
-
-#ifndef png_flush_ptr_NULL
- #define png_flush_ptr_NULL nullptr
-#endif
-
-///////////////////////////////////////////////////////////////////////////////
// Callback functions
///////////////////////////////////////////////////////////////////////////////
@@ -106,7 +82,7 @@ public:
// fInfo_ptr will never be non-nullptr unless fPng_ptr is.
if (fPng_ptr) {
png_infopp info_pp = fInfo_ptr ? &fInfo_ptr : nullptr;
- png_destroy_read_struct(&fPng_ptr, info_pp, png_infopp_NULL);
+ png_destroy_read_struct(&fPng_ptr, info_pp, nullptr);
}
}
@@ -126,91 +102,75 @@ private:
};
#define AutoCleanPng(...) SK_REQUIRE_LOCAL_VAR(AutoCleanPng)
-//checks if there is transparency info in the tRNS chunk
-//image types which could have data in the tRNS chunk include: Index8, Gray8, RGB
-static bool has_transparency_in_tRNS(png_structp png_ptr,
- png_infop info_ptr) {
- if (!png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
- return false;
- }
-
- png_bytep trans;
- int num_trans;
- png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, nullptr);
- return num_trans > 0;
-}
-
// Method for coverting to either an SkPMColor or a similarly packed
// unpremultiplied color.
typedef uint32_t (*PackColorProc)(U8CPU a, U8CPU r, U8CPU g, U8CPU b);
// Note: SkColorTable claims to store SkPMColors, which is not necessarily
// the case here.
+// TODO: If we add support for non-native swizzles, we'll need to handle that here.
bool SkPngCodec::decodePalette(bool premultiply, int* ctableCount) {
- int numPalette;
- png_colorp palette;
- png_bytep trans;
- if (!png_get_PLTE(fPng_ptr, fInfo_ptr, &palette, &numPalette)) {
+ int numColors;
+ png_color* palette;
+ if (!png_get_PLTE(fPng_ptr, fInfo_ptr, &palette, &numColors)) {
return false;
}
- // Note: These are not necessarily SkPMColors
- SkPMColor colorStorage[256]; // worst-case storage
- SkPMColor* colorPtr = colorStorage;
+ // Note: These are not necessarily SkPMColors.
+ SkPMColor colorPtr[256];
- int numTrans;
- if (png_get_valid(fPng_ptr, fInfo_ptr, PNG_INFO_tRNS)) {
- png_get_tRNS(fPng_ptr, fInfo_ptr, &trans, &numTrans, nullptr);
- } else {
- numTrans = 0;
- }
+ png_bytep alphas;
+ int numColorsWithAlpha = 0;
+ if (png_get_tRNS(fPng_ptr, fInfo_ptr, &alphas, &numColorsWithAlpha, nullptr)) {
+ // 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 (premultiply) {
+ proc = &SkPremultiplyARGBInline;
+ } else {
+ proc = &SkPackARGB32NoCheck;
+ }
- // check for bad images that might make us crash
- if (numTrans > numPalette) {
- numTrans = numPalette;
+ for (int i = 0; i < numColorsWithAlpha; i++) {
+ // We don't have a function in SkOpts that combines a set of alphas with a set
+ // of RGBs. We could write one, but it's hardly worth it, given that this
+ // is such a small fraction of the total decode time.
+ colorPtr[i] = proc(alphas[i], palette->red, palette->green, palette->blue);
+ palette++;
+ }
}
- int index = 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 (premultiply) {
- proc = &SkPreMultiplyARGB;
- } else {
- proc = &SkPackARGB32NoCheck;
- }
- for (; index < numTrans; index++) {
- *colorPtr++ = proc(*trans++, palette->red, palette->green, palette->blue);
- palette++;
- }
+ if (numColorsWithAlpha < numColors) {
+ // The optimized code depends on a 3-byte png_color struct with the colors
+ // in RGB order. These checks make sure it is safe to use.
+ static_assert(3 == sizeof(png_color), "png_color struct has changed. Opts are broken.");
+#ifdef SK_DEBUG
+ SkASSERT(&palette->red < &palette->green);
+ SkASSERT(&palette->green < &palette->blue);
+#endif
- for (; index < numPalette; index++) {
- *colorPtr++ = SkPackARGB32(0xFF, palette->red, palette->green, palette->blue);
- palette++;
+#ifdef SK_PMCOLOR_IS_RGBA
+ SkOpts::RGB_to_RGB1(colorPtr + numColorsWithAlpha, palette, numColors - numColorsWithAlpha);
+#else
+ SkOpts::RGB_to_BGR1(colorPtr + numColorsWithAlpha, palette, numColors - numColorsWithAlpha);
+#endif
}
- /* 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(fBitDepth, 8));
- SkPMColor lastColor = index > 0 ? colorPtr[-1] : SkPackARGB32(0xFF, 0, 0, 0);
- for (; index < colorCount; index++) {
- *colorPtr++ = lastColor;
+ // Pad the color table with the last color in the table (or black) in the case that
+ // invalid pixel indices exceed the number of colors in the table.
+ const int maxColors = 1 << fBitDepth;
+ if (numColors < maxColors) {
+ SkPMColor lastColor = numColors > 0 ? colorPtr[numColors - 1] : SK_ColorBLACK;
+ sk_memset32(colorPtr + numColors, lastColor, maxColors - numColors);
}
- // Set the new color count
+ // Set the new color count.
if (ctableCount != nullptr) {
- *ctableCount = colorCount;
+ *ctableCount = maxColors;
}
- fColorTable.reset(new SkColorTable(colorStorage, colorCount));
+ fColorTable.reset(new SkColorTable(colorPtr, maxColors));
return true;
}
@@ -283,84 +243,81 @@ static bool read_header(SkStream* stream, SkPngChunkReader* chunkReader,
// PNG file before the first IDAT (image data chunk).
png_read_info(png_ptr, info_ptr);
png_uint_32 origWidth, origHeight;
- int bitDepth, colorType;
+ int bitDepth, encodedColorType;
png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth,
- &colorType, int_p_NULL, int_p_NULL, int_p_NULL);
+ &encodedColorType, nullptr, nullptr, nullptr);
if (bitDepthPtr) {
*bitDepthPtr = bitDepth;
}
- // 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;
- }
- }
-
- // Tell libpng to strip 16 bit/color files down to 8 bits/color
+ // Tell libpng to strip 16 bit/color files down to 8 bits/color.
+ // TODO: Should we handle this in SkSwizzler? Could this also benefit
+ // RAW decodes?
if (bitDepth == 16) {
+ SkASSERT(PNG_COLOR_TYPE_PALETTE != encodedColorType);
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);
- }
- // Now determine the default SkColorType and SkAlphaType and set required transforms
- SkColorType skColorType = kUnknown_SkColorType;
- SkAlphaType skAlphaType = kUnknown_SkAlphaType;
- switch (colorType) {
+ // Now determine the default colorType and alphaType and set the required transforms.
+ // Often, we depend on SkSwizzler to perform any transforms that we need. However, we
+ // still depend on libpng for many of the rare and PNG-specific cases.
+ SkColorType colorType = kUnknown_SkColorType;
+ SkAlphaType alphaType = kUnknown_SkAlphaType;
+ switch (encodedColorType) {
case PNG_COLOR_TYPE_PALETTE:
- skColorType = kIndex_8_SkColorType;
- skAlphaType = has_transparency_in_tRNS(png_ptr, info_ptr) ?
+ // 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) {
+ // TODO: Should we use SkSwizzler here?
+ png_set_packing(png_ptr);
+ }
+
+ colorType = kIndex_8_SkColorType;
+ // Set the alpha type depending on if a transparency chunk exists.
+ alphaType = png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) ?
kUnpremul_SkAlphaType : kOpaque_SkAlphaType;
break;
case PNG_COLOR_TYPE_RGB:
- if (has_transparency_in_tRNS(png_ptr, info_ptr)) {
- //convert to RGBA with tranparency information in tRNS chunk if it exists
+ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
+ // Convert to RGBA if transparency chunk exists.
png_set_tRNS_to_alpha(png_ptr);
- skAlphaType = kUnpremul_SkAlphaType;
+ alphaType = kUnpremul_SkAlphaType;
} else {
- skAlphaType = kOpaque_SkAlphaType;
+ alphaType = kOpaque_SkAlphaType;
}
- skColorType = kN32_SkColorType;
+ colorType = kN32_SkColorType;
break;
case PNG_COLOR_TYPE_GRAY:
- if (has_transparency_in_tRNS(png_ptr, info_ptr)) {
- //FIXME: support gray with alpha as a color type
- //convert to RGBA if there is transparentcy info in the tRNS chunk
+ // Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel.
+ if (bitDepth < 8) {
+ // TODO: Should we use SkSwizzler here?
+ png_set_expand_gray_1_2_4_to_8(png_ptr);
+ }
+
+ if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
+ // Convert to RGBA if there is a transparency chunk.
png_set_tRNS_to_alpha(png_ptr);
png_set_gray_to_rgb(png_ptr);
- skColorType = kN32_SkColorType;
- skAlphaType = kUnpremul_SkAlphaType;
+ colorType = kN32_SkColorType;
+ alphaType = kUnpremul_SkAlphaType;
} else {
- skColorType = kGray_8_SkColorType;
- skAlphaType = kOpaque_SkAlphaType;
+ colorType = kGray_8_SkColorType;
+ alphaType = kOpaque_SkAlphaType;
}
break;
case PNG_COLOR_TYPE_GRAY_ALPHA:
- //FIXME: support gray with alpha as a color type
- //convert to RGBA
+ // Convert to RGBA if the image has alpha.
png_set_gray_to_rgb(png_ptr);
- skColorType = kN32_SkColorType;
- skAlphaType = kUnpremul_SkAlphaType;
+ colorType = kN32_SkColorType;
+ alphaType = kUnpremul_SkAlphaType;
break;
case PNG_COLOR_TYPE_RGBA:
- skColorType = kN32_SkColorType;
- skAlphaType = kUnpremul_SkAlphaType;
+ colorType = kN32_SkColorType;
+ alphaType = kUnpremul_SkAlphaType;
break;
default:
- //all the color types have been covered above
+ // All the color types have been covered above.
SkASSERT(false);
}
@@ -372,7 +329,7 @@ static bool read_header(SkStream* stream, SkPngChunkReader* chunkReader,
// FIXME: Also need to check for sRGB ( https://bug.skia.org/3471 ).
if (imageInfo) {
- *imageInfo = SkImageInfo::Make(origWidth, origHeight, skColorType, skAlphaType);
+ *imageInfo = SkImageInfo::Make(origWidth, origHeight, colorType, alphaType);
}
autoClean.detach();
if (png_ptrp) {
@@ -404,7 +361,7 @@ void SkPngCodec::destroyReadStruct() {
if (fPng_ptr) {
// We will never have a nullptr fInfo_ptr with a non-nullptr fPng_ptr
SkASSERT(fInfo_ptr);
- png_destroy_read_struct(&fPng_ptr, &fInfo_ptr, png_infopp_NULL);
+ png_destroy_read_struct(&fPng_ptr, &fInfo_ptr, nullptr);
fPng_ptr = nullptr;
fInfo_ptr = nullptr;
}
@@ -426,7 +383,7 @@ SkCodec::Result SkPngCodec::initializeSwizzler(const SkImageInfo& requestedInfo,
}
png_read_update_info(fPng_ptr, fInfo_ptr);
- //srcColorType was determined in read_header() which determined png color type
+ // srcColorType was determined in read_header() which determined png color type
const SkColorType srcColorType = this->getInfo().colorType();
switch (srcColorType) {
@@ -449,7 +406,7 @@ SkCodec::Result SkPngCodec::initializeSwizzler(const SkImageInfo& requestedInfo,
}
break;
default:
- //would have exited before now if the colorType was supported by png
+ // We will always recommend one of the above colorTypes.
SkASSERT(false);
}
@@ -459,10 +416,8 @@ SkCodec::Result SkPngCodec::initializeSwizzler(const SkImageInfo& requestedInfo,
// Create the swizzler. SkPngCodec retains ownership of the color table.
const SkPMColor* colors = get_color_ptr(fColorTable.get());
fSwizzler.reset(SkSwizzler::CreateSwizzler(fSrcConfig, colors, requestedInfo, options));
- if (!fSwizzler) {
- // FIXME: CreateSwizzler could fail for another reason.
- return kUnimplemented;
- }
+ SkASSERT(fSwizzler);
+
return kSuccess;
}
@@ -545,7 +500,7 @@ SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void*
uint8_t* srcRow = base;
for (int y = 0; y < height; y++) {
uint8_t* bmRow = srcRow;
- png_read_rows(fPng_ptr, &bmRow, png_bytepp_NULL, 1);
+ png_read_rows(fPng_ptr, &bmRow, nullptr, 1);
srcRow += srcRowBytes;
}
}
@@ -561,17 +516,13 @@ SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void*
storage.reset(requestedInfo.width() * SkSwizzler::BytesPerPixel(fSrcConfig));
uint8_t* srcRow = storage.get();
for (; row < requestedInfo.height(); row++) {
- png_read_rows(fPng_ptr, &srcRow, png_bytepp_NULL, 1);
+ png_read_rows(fPng_ptr, &srcRow, nullptr, 1);
// FIXME: Only call IsOpaque once, outside the loop. Same for onGetScanlines.
fSwizzler->swizzle(dstRow, srcRow);
dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
}
}
- // FIXME: do we need substituteTranspColor? Note that we cannot do it for
- // scanline decoding, but we could do it here. Alternatively, we could do
- // it as we go, instead of in post-processing like SkPNGImageDecoder.
-
if (setjmp(png_jmpbuf(fPng_ptr))) {
// We've already read all the scanlines. This is a success.
return kSuccess;
@@ -628,7 +579,7 @@ public:
void* dstRow = dst;
for (; row < count; row++) {
- png_read_rows(this->png_ptr(), &fSrcRow, png_bytepp_NULL, 1);
+ png_read_rows(this->png_ptr(), &fSrcRow, nullptr, 1);
this->swizzler()->swizzle(dstRow, fSrcRow);
dstRow = SkTAddOffset<void>(dstRow, rowBytes);
}
@@ -646,7 +597,7 @@ public:
//calling png_read_rows in a loop is insignificantly slower than calling it once with count
//as png_read_rows has it's own loop which calls png_read_row count times.
for (int row = 0; row < count; row++) {
- png_read_rows(this->png_ptr(), &fSrcRow, png_bytepp_NULL, 1);
+ png_read_rows(this->png_ptr(), &fSrcRow, nullptr, 1);
}
return true;
}
@@ -730,17 +681,17 @@ public:
for (int i = 0; i < this->numberPasses(); i++) {
// read rows we planned to skip into garbage row
for (int y = 0; y < startRow; y++){
- png_read_rows(this->png_ptr(), &fGarbageRowPtr, png_bytepp_NULL, 1);
+ png_read_rows(this->png_ptr(), &fGarbageRowPtr, nullptr, 1);
}
// read rows we care about into buffer
srcRow = storagePtr;
for (int y = 0; y < count; y++) {
- png_read_rows(this->png_ptr(), &srcRow, png_bytepp_NULL, 1);
+ png_read_rows(this->png_ptr(), &srcRow, nullptr, 1);
srcRow += fSrcRowBytes;
}
// read rows we don't want into garbage buffer
for (int y = 0; y < fHeight - startRow - count; y++) {
- png_read_rows(this->png_ptr(), &fGarbageRowPtr, png_bytepp_NULL, 1);
+ png_read_rows(this->png_ptr(), &fGarbageRowPtr, nullptr, 1);
}
}
//swizzle the rows we care about
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698