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

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: Build with no-clobbered 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
« no previous file with comments | « src/codec/SkCodec_libpng.h ('k') | src/codec/SkSwizzler.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/codec/SkCodec_libpng.cpp
diff --git a/src/codec/SkCodec_libpng.cpp b/src/codec/SkCodec_libpng.cpp
index e113a0e1b6f1f6c93045ad361811918967c2540e..60923356c18fb3f7f1bf9a6a754cbe2f2d67064a 100644
--- a/src/codec/SkCodec_libpng.cpp
+++ b/src/codec/SkCodec_libpng.cpp
@@ -11,6 +11,7 @@
#include "SkColorTable.h"
#include "SkBitmap.h"
#include "SkMath.h"
+#include "SkScanlineDecoder.h"
#include "SkSize.h"
#include "SkStream.h"
#include "SkSwizzler.h"
@@ -114,15 +115,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
@@ -137,8 +136,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;
}
@@ -165,11 +164,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);
@@ -181,7 +176,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;
}
///////////////////////////////////////////////////////////////////////////////
@@ -333,11 +329,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)
+ , fSrcConfig(SkSwizzler::kUnknown)
+ , fNumberPasses(INVALID_NUMBER_PASSES)
+ , fReallyHasAlpha(false)
+{}
SkPngCodec::~SkPngCodec() {
png_destroy_read_struct(&fPng_ptr, &fInfo_ptr, png_infopp_NULL);
@@ -362,29 +363,9 @@ static bool conversion_possible(const SkImageInfo& dst, const SkImageInfo& src)
kUnpremul_SkAlphaType == src.alphaType();
}
-SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void* dst,
- size_t rowBytes, const Options& options,
- SkPMColor ctable[], int* ctableCount) {
- if (!this->rewindIfNeeded()) {
- return kCouldNotRewind;
- }
- if (requestedInfo.dimensions() != this->getInfo().dimensions()) {
- return kInvalidScale;
- }
- if (!conversion_possible(requestedInfo, this->getInfo())) {
- 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,
+ const Options& options) {
// FIXME: Could we use the return value of setjmp to specify the type of
// error?
if (setjmp(png_jmpbuf(fPng_ptr))) {
@@ -398,42 +379,30 @@ 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) {
+ fSrcConfig = 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;
+ fSrcConfig = SkSwizzler::kGray;
} else if (this->getInfo().alphaType() == kOpaque_SkAlphaType) {
- sc = SkSwizzler::kRGBX;
+ fSrcConfig = SkSwizzler::kRGBX;
} else {
- sc = SkSwizzler::kRGBA;
+ fSrcConfig = SkSwizzler::kRGBA;
}
- const SkPMColor* colors = colorTable ? colorTable->readColors() : NULL;
- swizzler.reset(SkSwizzler::CreateSwizzler(sc, colors, requestedInfo,
- dst, rowBytes,
- options.fZeroInitialized));
- if (!swizzler) {
+ const SkPMColor* colors = fColorTable ? fColorTable->readColors() : NULL;
+ fSwizzler.reset(SkSwizzler::CreateSwizzler(fSrcConfig, colors, requestedInfo,
+ dst, rowBytes, options.fZeroInitialized));
+ if (!fSwizzler) {
// FIXME: CreateSwizzler could fail for another reason.
return kUnimplemented;
}
@@ -442,16 +411,47 @@ 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, const Options& options,
+ SkPMColor ctable[], int* ctableCount) {
+ if (!this->rewindIfNeeded()) {
+ return kCouldNotRewind;
+ }
+ if (requestedInfo.dimensions() != this->getInfo().dimensions()) {
+ return kInvalidScale;
+ }
+ if (!conversion_possible(requestedInfo, this->getInfo())) {
+ return kInvalidConversion;
+ }
+
+ const Result result = this->initializeSwizzler(requestedInfo, dst, rowBytes,
+ options);
+ 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(fSrcConfig);
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;
@@ -463,27 +463,116 @@ SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void*
// Now swizzle it.
uint8_t* row = base;
for (int y = 0; y < height; y++) {
- reallyHasAlpha |= !SkSwizzler::IsOpaque(swizzler->next(row));
+ fReallyHasAlpha |= !SkSwizzler::IsOpaque(fSwizzler->next(row));
row += rowBytes;
}
} else {
- storage.reset(requestedInfo.width() * SkSwizzler::BytesPerPixel(sc));
+ storage.reset(requestedInfo.width() * SkSwizzler::BytesPerPixel(fSrcConfig));
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 |= !SkSwizzler::IsOpaque(swizzler->next(srcRow));
+ fReallyHasAlpha |= !SkSwizzler::IsOpaque(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.
+
+ this->finish();
+ return kSuccess;
+}
+
+void SkPngCodec::finish() {
+ if (setjmp(png_jmpbuf(fPng_ptr))) {
+ // We've already read all the scanlines. This is a success.
+ return;
+ }
/* read rest of file, and get additional chunks in info_ptr - REQUIRED */
png_read_end(fPng_ptr, fInfo_ptr);
+}
- // FIXME: do we need substituteTranspColor?
+class SkPngScanlineDecoder : public SkScanlineDecoder {
+public:
+ SkPngScanlineDecoder(const SkImageInfo& dstInfo, SkPngCodec* codec)
+ : INHERITED(dstInfo)
+ , fCodec(codec)
+ , fHasAlpha(false)
+ {
+ fStorage.reset(dstInfo.width() * SkSwizzler::BytesPerPixel(fCodec->fSrcConfig));
+ fSrcRow = static_cast<uint8_t*>(fStorage.get());
+ }
- 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);
+ SkImageGenerator::Result onGetScanlines(void* dst, int count, size_t rowBytes) SK_OVERRIDE {
+ if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) {
+ SkDebugf("setjmp long jump!\n");
+ return SkImageGenerator::kInvalidInput;
+ }
+
+ for (int i = 0; i < count; i++) {
+ png_read_rows(fCodec->fPng_ptr, &fSrcRow, png_bytepp_NULL, 1);
+ fCodec->fSwizzler->setDstRow(dst);
+ fHasAlpha |= !SkSwizzler::IsOpaque(fCodec->fSwizzler->next(fSrcRow));
+ dst = SkTAddOffset<void>(dst, rowBytes);
+ }
+ return SkImageGenerator::kSuccess;
}
- return kSuccess;
+
+ SkImageGenerator::Result onSkipScanlines(int count) SK_OVERRIDE {
+ // 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;
+ }
+
+ png_read_rows(fCodec->fPng_ptr, png_bytepp_NULL, png_bytepp_NULL, count);
+ return SkImageGenerator::kSuccess;
+ }
+
+ void onFinish() SK_OVERRIDE {
+ fCodec->finish();
+ }
+
+ bool onReallyHasAlpha() const SK_OVERRIDE { return fHasAlpha; }
+
+private:
+ SkPngCodec* fCodec; // Unowned.
+ bool fHasAlpha;
+ SkAutoMalloc fStorage;
+ uint8_t* fSrcRow;
+
+ typedef SkScanlineDecoder INHERITED;
+};
+
+SkScanlineDecoder* SkPngCodec::onGetScanlineDecoder(const SkImageInfo& dstInfo) {
+ // Check to see if scaling was requested.
+ if (dstInfo.dimensions() != this->getInfo().dimensions()) {
+ return NULL;
+ }
+
+ if (!conversion_possible(dstInfo, this->getInfo())) {
+ 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.
+ Options opts;
+ // FIXME: Pass this in to getScanlineDecoder?
+ opts.fZeroInitialized = kNo_ZeroInitialized;
+ if (this->initializeSwizzler(dstInfo, NULL, dstInfo.minRowBytes(), opts) != 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, (dstInfo, this));
}
+
« no previous file with comments | « src/codec/SkCodec_libpng.h ('k') | src/codec/SkSwizzler.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698