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

Unified Diff: src/codec/SkCodec_libpng.cpp

Issue 1010903003: Add scanline decoding to SkCodec. (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Cleanups Created 5 years, 9 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
Index: src/codec/SkCodec_libpng.cpp
diff --git a/src/codec/SkCodec_libpng.cpp b/src/codec/SkCodec_libpng.cpp
index 8e7ee33a9554bce341cf8681b2db86d334bfae1b..186cd945247d771009ffe03281e9063d790ecb3e 100644
--- a/src/codec/SkCodec_libpng.cpp
+++ b/src/codec/SkCodec_libpng.cpp
@@ -10,6 +10,7 @@
#include "SkColorTable.h"
#include "SkBitmap.h"
#include "SkMath.h"
+#include "SkScanlineDecoder.h"
#include "SkSize.h"
#include "SkStream.h"
#include "SkSwizzler.h"
@@ -113,15 +114,13 @@ 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.
-SkColorTable* decode_palette(png_structp png_ptr, png_infop info_ptr,
- bool premultiply, SkAlphaType* outAlphaType) {
- SkASSERT(outAlphaType != NULL);
+bool SkPngCodec::decodePalette(bool premultiply) {
int numPalette;
png_colorp palette;
png_bytep trans;
- if (!png_get_PLTE(png_ptr, info_ptr, &palette, &numPalette)) {
- return NULL;
+ if (!png_get_PLTE(fPng_ptr, fInfo_ptr, &palette, &numPalette)) {
+ return false;
}
/* BUGGY IMAGE WORKAROUND
@@ -136,8 +135,8 @@ SkColorTable* decode_palette(png_structp png_ptr, png_infop info_ptr,
SkPMColor* colorPtr = colorStorage;
int numTrans;
- if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
- png_get_tRNS(png_ptr, info_ptr, &trans, &numTrans, NULL);
+ if (png_get_valid(fPng_ptr, fInfo_ptr, PNG_INFO_tRNS)) {
+ png_get_tRNS(fPng_ptr, fInfo_ptr, &trans, &numTrans, NULL);
} else {
numTrans = 0;
}
@@ -164,11 +163,7 @@ SkColorTable* decode_palette(png_structp png_ptr, png_infop info_ptr,
palette++;
}
- if (transLessThanFF < 0) {
- *outAlphaType = premultiply ? kPremul_SkAlphaType : kUnpremul_SkAlphaType;
- } else {
- *outAlphaType = kOpaque_SkAlphaType;
- }
+ fReallyHasAlpha = transLessThanFF < 0;
for (; index < numPalette; index++) {
*colorPtr++ = SkPackARGB32(0xFF, palette->red, palette->green, palette->blue);
@@ -180,7 +175,8 @@ SkColorTable* decode_palette(png_structp png_ptr, png_infop info_ptr,
*colorPtr = colorPtr[-1];
}
- return SkNEW_ARGS(SkColorTable, (colorStorage, colorCount));
+ fColorTable.reset(SkNEW_ARGS(SkColorTable, (colorStorage, colorCount)));
+ return true;
}
///////////////////////////////////////////////////////////////////////////////
@@ -332,11 +328,16 @@ SkCodec* SkPngCodec::NewFromStream(SkStream* stream) {
return codec;
}
+#define INVALID_NUMBER_PASSES -1
SkPngCodec::SkPngCodec(const SkImageInfo& info, SkStream* stream,
png_structp png_ptr, png_infop info_ptr)
: INHERITED(info, stream)
, fPng_ptr(png_ptr)
- , fInfo_ptr(info_ptr) {}
+ , fInfo_ptr(info_ptr)
+ , fSc(SkSwizzler::kUnknown)
+ , fNumberPasses(INVALID_NUMBER_PASSES)
+ , fReallyHasAlpha(false)
+{}
SkPngCodec::~SkPngCodec() {
png_destroy_read_struct(&fPng_ptr, &fInfo_ptr, png_infopp_NULL);
@@ -365,29 +366,8 @@ static bool conversion_possible(const SkImageInfo& A, const SkImageInfo& B) {
|| premul_and_unpremul(B.alphaType(), A.alphaType());
}
-SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void* dst,
- size_t rowBytes, SkPMColor ctable[],
- int* ctableCount) {
- if (!this->rewindIfNeeded()) {
- return kCouldNotRewind;
- }
- if (requestedInfo.dimensions() != this->getOriginalInfo().dimensions()) {
- return kInvalidScale;
- }
- if (!conversion_possible(requestedInfo, this->getOriginalInfo())) {
- return kInvalidConversion;
- }
-
- SkBitmap decodedBitmap;
- // If installPixels would have failed, getPixels should have failed before
- // calling onGetPixels.
- SkAssertResult(decodedBitmap.installPixels(requestedInfo, dst, rowBytes));
-
- // Initialize all non-trivial objects before setjmp.
- SkAutoTUnref<SkColorTable> colorTable;
- SkAutoTDelete<SkSwizzler> swizzler;
- SkAutoMalloc storage; // Scratch memory for pre-swizzled rows.
-
+SkCodec::Result SkPngCodec::initializeSwizzler(const SkImageInfo& requestedInfo, void* dst,
+ size_t rowBytes) {
// FIXME: Could we use the return value of setjmp to specify the type of
// error?
if (setjmp(png_jmpbuf(fPng_ptr))) {
@@ -401,42 +381,31 @@ SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void*
png_get_IHDR(fPng_ptr, fInfo_ptr, &origWidth, &origHeight, &bitDepth,
&pngColorType, &interlaceType, int_p_NULL, int_p_NULL);
- const int numberPasses = (interlaceType != PNG_INTERLACE_NONE) ?
+ fNumberPasses = (interlaceType != PNG_INTERLACE_NONE) ?
png_set_interlace_handling(fPng_ptr) : 1;
- SkSwizzler::SrcConfig sc;
- bool reallyHasAlpha = false;
+ // Set to the default before calling decodePalette, which may change it.
+ fReallyHasAlpha = false;
if (PNG_COLOR_TYPE_PALETTE == pngColorType) {
- sc = SkSwizzler::kIndex;
- SkAlphaType at = requestedInfo.alphaType();
- colorTable.reset(decode_palette(fPng_ptr, fInfo_ptr,
- kPremul_SkAlphaType == at,
- &at));
- if (!colorTable) {
+ fSc = SkSwizzler::kIndex;
+ if (!this->decodePalette(kPremul_SkAlphaType == requestedInfo.alphaType())) {
return kInvalidInput;
}
-
- reallyHasAlpha = (at != kOpaque_SkAlphaType);
-
- if (at != requestedInfo.alphaType()) {
- // It turns out the image is opaque.
- SkASSERT(kOpaque_SkAlphaType == at);
- }
} else if (kAlpha_8_SkColorType == requestedInfo.colorType()) {
// Note: we check the destination, since otherwise we would have
// told png to upscale.
SkASSERT(PNG_COLOR_TYPE_GRAY == pngColorType);
- sc = SkSwizzler::kGray;
+ fSc = SkSwizzler::kGray;
} else if (this->getOriginalInfo().alphaType() == kOpaque_SkAlphaType) {
- sc = SkSwizzler::kRGBX;
+ fSc = SkSwizzler::kRGBX;
} else {
- sc = SkSwizzler::kRGBA;
+ fSc = SkSwizzler::kRGBA;
}
- const SkPMColor* colors = colorTable ? colorTable->readColors() : NULL;
+ const SkPMColor* colors = fColorTable ? fColorTable->readColors() : NULL;
// TODO: Support skipZeroes.
- swizzler.reset(SkSwizzler::CreateSwizzler(sc, colors, requestedInfo,
- dst, rowBytes, false));
- if (!swizzler) {
+ fSwizzler.reset(SkSwizzler::CreateSwizzler(fSc, colors, requestedInfo,
+ dst, rowBytes, false));
+ if (!fSwizzler) {
// FIXME: CreateSwizzler could fail for another reason.
return kUnimplemented;
}
@@ -445,16 +414,46 @@ SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void*
// made in the factory.
png_read_update_info(fPng_ptr, fInfo_ptr);
- if (numberPasses > 1) {
+ return kSuccess;
+}
+
+SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void* dst,
+ size_t rowBytes, SkPMColor ctable[],
+ int* ctableCount) {
+ if (!this->rewindIfNeeded()) {
+ return kCouldNotRewind;
+ }
+ if (requestedInfo.dimensions() != this->getOriginalInfo().dimensions()) {
+ return kInvalidScale;
+ }
+ if (!conversion_possible(requestedInfo, this->getOriginalInfo())) {
+ return kInvalidConversion;
+ }
+
+ const Result result = this->initializeSwizzler(requestedInfo, dst, rowBytes);
+ if (result != kSuccess) {
+ return result;
+ }
+
+ // FIXME: Could we use the return value of setjmp to specify the type of
+ // error?
+ if (setjmp(png_jmpbuf(fPng_ptr))) {
+ SkDebugf("setjmp long jump!\n");
+ return kInvalidInput;
+ }
+
+ SkASSERT(fNumberPasses != INVALID_NUMBER_PASSES);
+ SkAutoMalloc storage;
+ if (fNumberPasses > 1) {
const int width = requestedInfo.width();
const int height = requestedInfo.height();
- const int bpp = SkSwizzler::BytesPerPixel(sc);
+ const int bpp = SkSwizzler::BytesPerPixel(fSc);
const size_t rowBytes = width * bpp;
storage.reset(width * height * bpp);
uint8_t* const base = static_cast<uint8_t*>(storage.get());
- for (int i = 0; i < numberPasses; i++) {
+ for (int i = 0; i < fNumberPasses; i++) {
uint8_t* row = base;
for (int y = 0; y < height; y++) {
uint8_t* bmRow = row;
@@ -466,27 +465,111 @@ SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void*
// Now swizzle it.
uint8_t* row = base;
for (int y = 0; y < height; y++) {
- reallyHasAlpha |= swizzler->next(row);
+ fReallyHasAlpha |= fSwizzler->next(row);
row += rowBytes;
}
} else {
- storage.reset(requestedInfo.width() * SkSwizzler::BytesPerPixel(sc));
+ storage.reset(requestedInfo.width() * SkSwizzler::BytesPerPixel(fSc));
uint8_t* srcRow = static_cast<uint8_t*>(storage.get());
for (int y = 0; y < requestedInfo.height(); y++) {
png_read_rows(fPng_ptr, &srcRow, png_bytepp_NULL, 1);
- reallyHasAlpha |= swizzler->next(srcRow);
+ fReallyHasAlpha |= fSwizzler->next(srcRow);
}
}
+ // 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.
+
+ return this->finish();
+}
+
+SkImageGenerator::Result SkPngCodec::finish() {
+ // FIXME: Maybe these should return incomplete?
+ if (setjmp(png_jmpbuf(fPng_ptr))) {
+ SkDebugf("setjmp long jump!\n");
+ return kInvalidInput;
+ }
/* read rest of file, and get additional chunks in info_ptr - REQUIRED */
png_read_end(fPng_ptr, fInfo_ptr);
- // FIXME: do we need substituteTranspColor?
+ return kSuccess;
+}
+
+class SkPngScanlineDecoder : public SkScanlineDecoder {
+public:
+ // FIXME: Need to support subsets...
+ SkPngScanlineDecoder(const SkImageInfo& origInfo, const SkImageInfo& dstInfo,
+ SkPngCodec* codec)
+ // FIXME: Does SkScanlineDecoder need origInfo? Maybe for subsets?
+ : INHERITED(origInfo, dstInfo)
+ , fDstInfo(dstInfo)
+ , fCodec(codec)
+ , fHasAlpha(false)
+ {
+ fStorage.reset(dstInfo.width() * SkSwizzler::BytesPerPixel(fCodec->fSc));
+ fSrcRow = static_cast<uint8_t*>(fStorage.get());
+ }
+
+ SkImageGenerator::Result onGetNextScanline(void* dst) SK_OVERRIDE {
reed1 2015/03/19 15:31:39 Is it easy to override the N-scanlines method here
scroggo 2015/03/19 17:59:19 Yes.
+ // FIXME: Could we use the return value of setjmp to specify the type of
+ // error?
+ if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) {
+ SkDebugf("setjmp long jump!\n");
+ return SkImageGenerator::kInvalidInput;
+ }
- if (reallyHasAlpha && requestedInfo.alphaType() != kOpaque_SkAlphaType) {
- // FIXME: We want to alert the caller. Is this the right way?
- SkImageInfo* modInfo = const_cast<SkImageInfo*>(&requestedInfo);
- *modInfo = requestedInfo.makeAlphaType(kOpaque_SkAlphaType);
+ png_read_rows(fCodec->fPng_ptr, &fSrcRow, png_bytepp_NULL, 1);
+ fCodec->fSwizzler->setDstRow(dst);
+ fHasAlpha |= fCodec->fSwizzler->next(fSrcRow);
+ return SkImageGenerator::kSuccess;
}
- return kSuccess;
+
+ SkImageGenerator::Result onFinish() SK_OVERRIDE {
+ return fCodec->finish();
+ }
+
+ bool onReallyHasAlpha() const SK_OVERRIDE { return fHasAlpha; }
+
+private:
+ const SkImageInfo& fDstInfo;
+ SkPngCodec* fCodec; // Unowned.
+ bool fHasAlpha;
+ SkAutoMalloc fStorage;
+ uint8_t* fSrcRow;
+
+ typedef SkScanlineDecoder INHERITED;
+};
+
+SkScanlineDecoder* SkPngCodec::onGetScanlineDecoder(const SkImageInfo& dstInfo,
+ const SkIRect& origSubset) {
+ // Check to see if scaling was requested.
+ if (dstInfo.dimensions() != origSubset.size()) {
+ SkDebugf("Scaling not supported: dimensions: %d %d\toriginal: %d %d\n",
+ dstInfo.width(), dstInfo.height(),
+ origSubset.width(), origSubset.height());
+ return NULL;
+ }
+
+ if (!conversion_possible(dstInfo, this->getOriginalInfo())) {
+ SkDebugf("no conversion possible\n");
+ return NULL;
+ }
+
+ // Note: We set dst to NULL since we do not know it yet. rowBytes is not needed,
+ // since we'll be manually updating the dstRow, but the SkSwizzler requires it to
+ // be at least dstInfo.minRowBytes.
+ if (this->initializeSwizzler(dstInfo, NULL, dstInfo.minRowBytes()) != kSuccess) {
+ SkDebugf("failed to initialize the swizzler.\n");
+ return NULL;
+ }
+
+ SkASSERT(fNumberPasses != INVALID_NUMBER_PASSES);
+ if (fNumberPasses > 1) {
+ // We cannot efficiently do scanline decoding.
+ return NULL;
+ }
+
+ return SkNEW_ARGS(SkPngScanlineDecoder, (this->getOriginalInfo(), dstInfo, this));
}
+

Powered by Google App Engine
This is Rietveld 408576698