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

Unified Diff: src/codec/SkPngCodec.cpp

Issue 1918873002: Remove SkEncodedInfo kUnknown_Color and kUnknown_Alpha from public API (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Fix errors Created 4 years, 8 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/SkJpegDecoderMgr.cpp ('k') | src/codec/SkRawCodec.cpp » ('j') | 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 a5ff9fcc96655b9cd36987b89ba5409e4ae83e7b..1ad7f8006ee85a0a8016e129dd15104993fe8108 100644
--- a/src/codec/SkPngCodec.cpp
+++ b/src/codec/SkPngCodec.cpp
@@ -261,6 +261,206 @@ sk_sp<SkColorSpace> read_color_space(png_structp png_ptr, png_infop info_ptr) {
return nullptr;
}
+static int bytes_per_pixel(int bitsPerPixel) {
+ // Note that we will have to change this implementation if we start
+ // supporting outputs from libpng that are less than 8-bits per component.
+ return bitsPerPixel / 8;
+}
+
+// Subclass of SkPngCodec which supports scanline decoding
+class SkPngScanlineDecoder : public SkPngCodec {
+public:
+ SkPngScanlineDecoder(int width, int height, const SkEncodedInfo& info, SkStream* stream,
+ SkPngChunkReader* chunkReader, png_structp png_ptr, png_infop info_ptr, int bitDepth,
+ sk_sp<SkColorSpace> colorSpace)
+ : INHERITED(width, height, info, stream, chunkReader, png_ptr, info_ptr, bitDepth, 1,
+ colorSpace)
+ , fSrcRow(nullptr)
+ {}
+
+ Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& options,
+ SkPMColor ctable[], int* ctableCount) override {
+ if (!conversion_possible(dstInfo, this->getInfo())) {
+ return kInvalidConversion;
+ }
+
+ const Result result = this->initializeSwizzler(dstInfo, options, ctable,
+ ctableCount);
+ if (result != kSuccess) {
+ return result;
+ }
+
+ fStorage.reset(this->getInfo().width() *
+ (bytes_per_pixel(this->getEncodedInfo().bitsPerPixel())));
+ fSrcRow = fStorage.get();
+
+ return kSuccess;
+ }
+
+ int onGetScanlines(void* dst, int count, size_t rowBytes) override {
+ // Assume that an error in libpng indicates an incomplete input.
+ int row = 0;
+ if (setjmp(png_jmpbuf(this->png_ptr()))) {
+ SkCodecPrintf("setjmp long jump!\n");
+ return row;
+ }
+
+ void* dstRow = dst;
+ for (; row < count; row++) {
+ png_read_row(this->png_ptr(), fSrcRow, nullptr);
+ this->swizzler()->swizzle(dstRow, fSrcRow);
+ dstRow = SkTAddOffset<void>(dstRow, rowBytes);
+ }
+
+ return row;
+ }
+
+ bool onSkipScanlines(int count) override {
+ // Assume that an error in libpng indicates an incomplete input.
+ if (setjmp(png_jmpbuf(this->png_ptr()))) {
+ SkCodecPrintf("setjmp long jump!\n");
+ return false;
+ }
+
+ for (int row = 0; row < count; row++) {
+ png_read_row(this->png_ptr(), fSrcRow, nullptr);
+ }
+ return true;
+ }
+
+private:
+ SkAutoTMalloc<uint8_t> fStorage;
+ uint8_t* fSrcRow;
+
+ typedef SkPngCodec INHERITED;
+};
+
+
+class SkPngInterlacedScanlineDecoder : public SkPngCodec {
+public:
+ SkPngInterlacedScanlineDecoder(int width, int height, const SkEncodedInfo& info,
+ SkStream* stream, SkPngChunkReader* chunkReader, png_structp png_ptr,
+ png_infop info_ptr, int bitDepth, int numberPasses, sk_sp<SkColorSpace> colorSpace)
+ : INHERITED(width, height, info, stream, chunkReader, png_ptr, info_ptr, bitDepth,
+ numberPasses, colorSpace)
+ , fHeight(-1)
+ , fCanSkipRewind(false)
+ {
+ SkASSERT(numberPasses != 1);
+ }
+
+ Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& options,
+ SkPMColor ctable[], int* ctableCount) override {
+ if (!conversion_possible(dstInfo, this->getInfo())) {
+ return kInvalidConversion;
+ }
+
+ const Result result = this->initializeSwizzler(dstInfo, options, ctable,
+ ctableCount);
+ if (result != kSuccess) {
+ return result;
+ }
+
+ fHeight = dstInfo.height();
+ // FIXME: This need not be called on a second call to onStartScanlineDecode.
+ fSrcRowBytes = this->getInfo().width() *
+ (bytes_per_pixel(this->getEncodedInfo().bitsPerPixel()));
+ fGarbageRow.reset(fSrcRowBytes);
+ fGarbageRowPtr = static_cast<uint8_t*>(fGarbageRow.get());
+ fCanSkipRewind = true;
+
+ return SkCodec::kSuccess;
+ }
+
+ int onGetScanlines(void* dst, int count, size_t dstRowBytes) override {
+ // rewind stream if have previously called onGetScanlines,
+ // since we need entire progressive image to get scanlines
+ if (fCanSkipRewind) {
+ // We already rewound in onStartScanlineDecode, so there is no reason to rewind.
+ // Next time onGetScanlines is called, we will need to rewind.
+ fCanSkipRewind = false;
+ } else {
+ // rewindIfNeeded resets fCurrScanline, since it assumes that start
+ // needs to be called again before scanline decoding. PNG scanline
+ // decoding is the exception, since it needs to rewind between
+ // calls to getScanlines. Keep track of fCurrScanline, to undo the
+ // reset.
+ const int currScanline = this->nextScanline();
+ // This method would never be called if currScanline is -1
+ SkASSERT(currScanline != -1);
+
+ if (!this->rewindIfNeeded()) {
+ return kCouldNotRewind;
+ }
+ this->updateCurrScanline(currScanline);
+ }
+
+ if (setjmp(png_jmpbuf(this->png_ptr()))) {
+ SkCodecPrintf("setjmp long jump!\n");
+ // FIXME (msarett): Returning 0 is pessimistic. If we can complete a single pass,
+ // we may be able to report that all of the memory has been initialized. Even if we
+ // fail on the first pass, we can still report than some scanlines are initialized.
+ return 0;
+ }
+ SkAutoTMalloc<uint8_t> storage(count * fSrcRowBytes);
+ uint8_t* storagePtr = storage.get();
+ uint8_t* srcRow;
+ const int startRow = this->nextScanline();
+ 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_row(this->png_ptr(), fGarbageRowPtr, nullptr);
+ }
+ // read rows we care about into buffer
+ srcRow = storagePtr;
+ for (int y = 0; y < count; y++) {
+ png_read_row(this->png_ptr(), srcRow, nullptr);
+ srcRow += fSrcRowBytes;
+ }
+ // read rows we don't want into garbage buffer
+ for (int y = 0; y < fHeight - startRow - count; y++) {
+ png_read_row(this->png_ptr(), fGarbageRowPtr, nullptr);
+ }
+ }
+ //swizzle the rows we care about
+ srcRow = storagePtr;
+ void* dstRow = dst;
+ for (int y = 0; y < count; y++) {
+ this->swizzler()->swizzle(dstRow, srcRow);
+ dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
+ srcRow += fSrcRowBytes;
+ }
+
+ return count;
+ }
+
+ bool onSkipScanlines(int count) override {
+ // The non-virtual version will update fCurrScanline.
+ return true;
+ }
+
+ SkScanlineOrder onGetScanlineOrder() const override {
+ return kNone_SkScanlineOrder;
+ }
+
+private:
+ int fHeight;
+ size_t fSrcRowBytes;
+ SkAutoMalloc fGarbageRow;
+ uint8_t* fGarbageRowPtr;
+ // FIXME: This imitates behavior in SkCodec::rewindIfNeeded. That function
+ // is called whenever some action is taken that reads the stream and
+ // therefore the next call will require a rewind. So it modifies a boolean
+ // to note that the *next* time it is called a rewind is needed.
+ // SkPngInterlacedScanlineDecoder has an extra wrinkle - calling
+ // onStartScanlineDecode followed by onGetScanlines does *not* require a
+ // rewind. Since rewindIfNeeded does not have this flexibility, we need to
+ // add another layer.
+ bool fCanSkipRewind;
+
+ typedef SkPngCodec INHERITED;
+};
+
// Reads the header and initializes the output fields, if not NULL.
//
// @param stream Input data. Will be read to get enough information to properly
@@ -268,23 +468,17 @@ sk_sp<SkColorSpace> read_color_space(png_structp png_ptr, png_infop info_ptr) {
// @param chunkReader SkPngChunkReader, for reading unknown chunks. May be NULL.
// If not NULL, png_ptr will hold an *unowned* pointer to it. The caller is
// expected to continue to own it for the lifetime of the png_ptr.
+// @param outCodec Optional output variable. If non-NULL, will be set to a new
+// SkPngCodec on success.
// @param png_ptrp Optional output variable. If non-NULL, will be set to a new
// png_structp on success.
// @param info_ptrp Optional output variable. If non-NULL, will be set to a new
// png_infop on success;
-// @param info Optional output variable. If non-NULL, will be set to
-// reflect the properties of the encoded image on success.
-// @param bitDepthPtr Optional output variable. If non-NULL, will be set to the
-// bit depth of the encoded image on success.
-// @param numberPassesPtr Optional output variable. If non-NULL, will be set to
-// the number_passes of the encoded image on success.
// @return true on success, in which case the caller is responsible for calling
// png_destroy_read_struct(png_ptrp, info_ptrp).
// If it returns false, the passed in fields (except stream) are unchanged.
-static bool read_header(SkStream* stream, SkPngChunkReader* chunkReader,
- png_structp* png_ptrp, png_infop* info_ptrp,
- int* width, int* height, SkEncodedInfo* info, int* bitDepthPtr,
- int* numberPassesPtr) {
+static bool read_header(SkStream* stream, SkPngChunkReader* chunkReader, SkCodec** outCodec,
+ png_structp* png_ptrp, png_infop* info_ptrp) {
// The image is known to be a PNG. Decode enough to know the SkImageInfo.
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr,
sk_error_fn, sk_warning_fn);
@@ -327,10 +521,6 @@ static bool read_header(SkStream* stream, SkPngChunkReader* chunkReader,
png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth,
&encodedColorType, nullptr, nullptr, nullptr);
- if (bitDepthPtr) {
- *bitDepthPtr = bitDepth;
- }
-
// 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?
@@ -401,19 +591,7 @@ static bool read_header(SkStream* stream, SkPngChunkReader* chunkReader,
}
int numberPasses = png_set_interlace_handling(png_ptr);
- if (numberPassesPtr) {
- *numberPassesPtr = numberPasses;
- }
- if (info) {
- *info = SkEncodedInfo::Make(color, alpha, 8);
- }
- if (width) {
- *width = origWidth;
- }
- if (height) {
- *height = origHeight;
- }
autoClean.release();
if (png_ptrp) {
*png_ptrp = png_ptr;
@@ -422,6 +600,19 @@ static bool read_header(SkStream* stream, SkPngChunkReader* chunkReader,
*info_ptrp = info_ptr;
}
+ if (outCodec) {
+ sk_sp<SkColorSpace> colorSpace = read_color_space(png_ptr, info_ptr);
+ SkEncodedInfo info = SkEncodedInfo::Make(color, alpha, 8);
+
+ if (1 == numberPasses) {
+ *outCodec = new SkPngScanlineDecoder(origWidth, origHeight, info, stream,
+ chunkReader, png_ptr, info_ptr, bitDepth, colorSpace);
+ } else {
+ *outCodec = new SkPngInterlacedScanlineDecoder(origWidth, origHeight, info, stream,
+ chunkReader, png_ptr, info_ptr, bitDepth, numberPasses, colorSpace);
+ }
+ }
+
return true;
}
@@ -496,8 +687,7 @@ bool SkPngCodec::onRewind() {
png_structp png_ptr;
png_infop info_ptr;
- if (!read_header(this->stream(), fPngChunkReader.get(), &png_ptr, &info_ptr,
- nullptr, nullptr, nullptr, nullptr, nullptr)) {
+ if (!read_header(this->stream(), fPngChunkReader.get(), nullptr, &png_ptr, &info_ptr)) {
return false;
}
@@ -506,12 +696,6 @@ bool SkPngCodec::onRewind() {
return true;
}
-static int bytes_per_pixel(int bitsPerPixel) {
- // Note that we will have to change this implementation if we start
- // supporting outputs from libpng that are less than 8-bits per component.
- return bitsPerPixel / 8;
-}
-
SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void* dst,
size_t dstRowBytes, const Options& options,
SkPMColor ctable[], int* ctableCount,
@@ -606,222 +790,16 @@ uint32_t SkPngCodec::onGetFillValue(SkColorType colorType) const {
return INHERITED::onGetFillValue(colorType);
}
-// Subclass of SkPngCodec which supports scanline decoding
-class SkPngScanlineDecoder : public SkPngCodec {
-public:
- SkPngScanlineDecoder(int width, int height, const SkEncodedInfo& info, SkStream* stream,
- SkPngChunkReader* chunkReader, png_structp png_ptr, png_infop info_ptr, int bitDepth,
- sk_sp<SkColorSpace> colorSpace)
- : INHERITED(width, height, info, stream, chunkReader, png_ptr, info_ptr, bitDepth, 1,
- colorSpace)
- , fSrcRow(nullptr)
- {}
-
- Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& options,
- SkPMColor ctable[], int* ctableCount) override {
- if (!conversion_possible(dstInfo, this->getInfo())) {
- return kInvalidConversion;
- }
-
- const Result result = this->initializeSwizzler(dstInfo, options, ctable,
- ctableCount);
- if (result != kSuccess) {
- return result;
- }
-
- fStorage.reset(this->getInfo().width() *
- (bytes_per_pixel(this->getEncodedInfo().bitsPerPixel())));
- fSrcRow = fStorage.get();
-
- return kSuccess;
- }
-
- int onGetScanlines(void* dst, int count, size_t rowBytes) override {
- // Assume that an error in libpng indicates an incomplete input.
- int row = 0;
- if (setjmp(png_jmpbuf(this->png_ptr()))) {
- SkCodecPrintf("setjmp long jump!\n");
- return row;
- }
-
- void* dstRow = dst;
- for (; row < count; row++) {
- png_read_row(this->png_ptr(), fSrcRow, nullptr);
- this->swizzler()->swizzle(dstRow, fSrcRow);
- dstRow = SkTAddOffset<void>(dstRow, rowBytes);
- }
-
- return row;
- }
-
- bool onSkipScanlines(int count) override {
- // Assume that an error in libpng indicates an incomplete input.
- if (setjmp(png_jmpbuf(this->png_ptr()))) {
- SkCodecPrintf("setjmp long jump!\n");
- return false;
- }
-
- for (int row = 0; row < count; row++) {
- png_read_row(this->png_ptr(), fSrcRow, nullptr);
- }
- return true;
- }
-
-private:
- SkAutoTMalloc<uint8_t> fStorage;
- uint8_t* fSrcRow;
-
- typedef SkPngCodec INHERITED;
-};
-
-
-class SkPngInterlacedScanlineDecoder : public SkPngCodec {
-public:
- SkPngInterlacedScanlineDecoder(int width, int height, const SkEncodedInfo& info,
- SkStream* stream, SkPngChunkReader* chunkReader, png_structp png_ptr,
- png_infop info_ptr, int bitDepth, int numberPasses, sk_sp<SkColorSpace> colorSpace)
- : INHERITED(width, height, info, stream, chunkReader, png_ptr, info_ptr, bitDepth,
- numberPasses, colorSpace)
- , fHeight(-1)
- , fCanSkipRewind(false)
- {
- SkASSERT(numberPasses != 1);
- }
-
- Result onStartScanlineDecode(const SkImageInfo& dstInfo, const Options& options,
- SkPMColor ctable[], int* ctableCount) override {
- if (!conversion_possible(dstInfo, this->getInfo())) {
- return kInvalidConversion;
- }
-
- const Result result = this->initializeSwizzler(dstInfo, options, ctable,
- ctableCount);
- if (result != kSuccess) {
- return result;
- }
-
- fHeight = dstInfo.height();
- // FIXME: This need not be called on a second call to onStartScanlineDecode.
- fSrcRowBytes = this->getInfo().width() *
- (bytes_per_pixel(this->getEncodedInfo().bitsPerPixel()));
- fGarbageRow.reset(fSrcRowBytes);
- fGarbageRowPtr = static_cast<uint8_t*>(fGarbageRow.get());
- fCanSkipRewind = true;
-
- return SkCodec::kSuccess;
- }
-
- int onGetScanlines(void* dst, int count, size_t dstRowBytes) override {
- // rewind stream if have previously called onGetScanlines,
- // since we need entire progressive image to get scanlines
- if (fCanSkipRewind) {
- // We already rewound in onStartScanlineDecode, so there is no reason to rewind.
- // Next time onGetScanlines is called, we will need to rewind.
- fCanSkipRewind = false;
- } else {
- // rewindIfNeeded resets fCurrScanline, since it assumes that start
- // needs to be called again before scanline decoding. PNG scanline
- // decoding is the exception, since it needs to rewind between
- // calls to getScanlines. Keep track of fCurrScanline, to undo the
- // reset.
- const int currScanline = this->nextScanline();
- // This method would never be called if currScanline is -1
- SkASSERT(currScanline != -1);
-
- if (!this->rewindIfNeeded()) {
- return kCouldNotRewind;
- }
- this->updateCurrScanline(currScanline);
- }
-
- if (setjmp(png_jmpbuf(this->png_ptr()))) {
- SkCodecPrintf("setjmp long jump!\n");
- // FIXME (msarett): Returning 0 is pessimistic. If we can complete a single pass,
- // we may be able to report that all of the memory has been initialized. Even if we
- // fail on the first pass, we can still report than some scanlines are initialized.
- return 0;
- }
- SkAutoTMalloc<uint8_t> storage(count * fSrcRowBytes);
- uint8_t* storagePtr = storage.get();
- uint8_t* srcRow;
- const int startRow = this->nextScanline();
- 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_row(this->png_ptr(), fGarbageRowPtr, nullptr);
- }
- // read rows we care about into buffer
- srcRow = storagePtr;
- for (int y = 0; y < count; y++) {
- png_read_row(this->png_ptr(), srcRow, nullptr);
- srcRow += fSrcRowBytes;
- }
- // read rows we don't want into garbage buffer
- for (int y = 0; y < fHeight - startRow - count; y++) {
- png_read_row(this->png_ptr(), fGarbageRowPtr, nullptr);
- }
- }
- //swizzle the rows we care about
- srcRow = storagePtr;
- void* dstRow = dst;
- for (int y = 0; y < count; y++) {
- this->swizzler()->swizzle(dstRow, srcRow);
- dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
- srcRow += fSrcRowBytes;
- }
-
- return count;
- }
-
- bool onSkipScanlines(int count) override {
- // The non-virtual version will update fCurrScanline.
- return true;
- }
-
- SkScanlineOrder onGetScanlineOrder() const override {
- return kNone_SkScanlineOrder;
- }
-
-private:
- int fHeight;
- size_t fSrcRowBytes;
- SkAutoMalloc fGarbageRow;
- uint8_t* fGarbageRowPtr;
- // FIXME: This imitates behavior in SkCodec::rewindIfNeeded. That function
- // is called whenever some action is taken that reads the stream and
- // therefore the next call will require a rewind. So it modifies a boolean
- // to note that the *next* time it is called a rewind is needed.
- // SkPngInterlacedScanlineDecoder has an extra wrinkle - calling
- // onStartScanlineDecode followed by onGetScanlines does *not* require a
- // rewind. Since rewindIfNeeded does not have this flexibility, we need to
- // add another layer.
- bool fCanSkipRewind;
-
- typedef SkPngCodec INHERITED;
-};
-
SkCodec* SkPngCodec::NewFromStream(SkStream* stream, SkPngChunkReader* chunkReader) {
SkAutoTDelete<SkStream> streamDeleter(stream);
- png_structp png_ptr;
- png_infop info_ptr;
- int width, height;
- SkEncodedInfo imageInfo;
- int bitDepth;
- int numberPasses;
-
- if (!read_header(stream, chunkReader, &png_ptr, &info_ptr, &width, &height, &imageInfo,
- &bitDepth, &numberPasses)) {
- return nullptr;
- }
-
- auto colorSpace = read_color_space(png_ptr, info_ptr);
- if (1 == numberPasses) {
- return new SkPngScanlineDecoder(width, height, imageInfo, streamDeleter.release(),
- chunkReader, png_ptr, info_ptr, bitDepth, colorSpace);
+ SkCodec* outCodec;
+ if (read_header(stream, chunkReader, &outCodec, nullptr, nullptr)) {
+ // Codec has taken ownership of the stream.
+ SkASSERT(outCodec);
+ streamDeleter.release();
+ return outCodec;
}
- return new SkPngInterlacedScanlineDecoder(width, height, imageInfo, streamDeleter.release(),
- chunkReader, png_ptr, info_ptr, bitDepth,
- numberPasses, colorSpace);
+ return nullptr;
}
« no previous file with comments | « src/codec/SkJpegDecoderMgr.cpp ('k') | src/codec/SkRawCodec.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698