From f682d9ad70d690a343bc15e26ef321d86770be41 Mon Sep 17 00:00:00 2001 From: msarett Date: Mon, 18 Apr 2016 16:20:00 -0700 Subject: Add SkEncodedInfo to report properties of encoded image data All this does is build an SkEncodedInfo for each codec, and then convert it to an SkImageInfo. In future steps I intend to: (1) Use SkEncodedInfo in place of SrcConfig in SkSwizzler. (2) Support more conversions in SkSwizzler (non-native BGRA/RGBA, 16-bit components, float, fixed point) (3) Investigate optimizing conversions from encoded data to linear color spaces. BUG=skia:4133 GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1820073002 Review URL: https://codereview.chromium.org/1820073002 --- include/codec/SkCodec.h | 8 +- include/codec/SkEncodedInfo.h | 178 +++++++++++++++++++++++++++++++++++++++ src/codec/SkBmpCodec.cpp | 82 +++++++++++------- src/codec/SkBmpCodec.h | 4 +- src/codec/SkBmpMaskCodec.cpp | 4 +- src/codec/SkBmpMaskCodec.h | 4 +- src/codec/SkBmpRLECodec.cpp | 4 +- src/codec/SkBmpRLECodec.h | 4 +- src/codec/SkBmpStandardCodec.cpp | 6 +- src/codec/SkBmpStandardCodec.h | 4 +- src/codec/SkCodec.cpp | 7 +- src/codec/SkGifCodec.cpp | 30 +++---- src/codec/SkGifCodec.h | 6 +- src/codec/SkIcoCodec.cpp | 10 ++- src/codec/SkIcoCodec.h | 3 +- src/codec/SkJpegCodec.cpp | 17 ++-- src/codec/SkJpegCodec.h | 6 +- src/codec/SkJpegDecoderMgr.cpp | 14 ++- src/codec/SkJpegDecoderMgr.h | 5 +- src/codec/SkPngCodec.cpp | 102 +++++++++++----------- src/codec/SkPngCodec.h | 4 +- src/codec/SkRawCodec.cpp | 25 ++++-- src/codec/SkWbmpCodec.cpp | 10 +-- src/codec/SkWbmpCodec.h | 2 +- src/codec/SkWebpCodec.cpp | 59 ++++++++++--- src/codec/SkWebpCodec.h | 2 +- 26 files changed, 434 insertions(+), 166 deletions(-) create mode 100644 include/codec/SkEncodedInfo.h diff --git a/include/codec/SkCodec.h b/include/codec/SkCodec.h index 629274d21c..50875e46c4 100644 --- a/include/codec/SkCodec.h +++ b/include/codec/SkCodec.h @@ -11,6 +11,7 @@ #include "../private/SkTemplates.h" #include "SkColor.h" #include "SkEncodedFormat.h" +#include "SkEncodedInfo.h" #include "SkImageInfo.h" #include "SkSize.h" #include "SkStream.h" @@ -100,6 +101,8 @@ public: */ const SkImageInfo& getInfo() const { return fSrcInfo; } + const SkEncodedInfo& getEncodedInfo() const { return fEncodedInfo; } + /** * Returns the color space associated with the codec. * Does not affect ownership. @@ -511,7 +514,9 @@ protected: /** * Takes ownership of SkStream* */ - SkCodec(const SkImageInfo&, + SkCodec(int width, + int height, + const SkEncodedInfo&, SkStream*, sk_sp = nullptr, Origin = kTopLeft_Origin); @@ -642,6 +647,7 @@ protected: virtual int onOutputScanline(int inputScanline) const; private: + const SkEncodedInfo fEncodedInfo; const SkImageInfo fSrcInfo; SkAutoTDelete fStream; bool fNeedsRewind; diff --git a/include/codec/SkEncodedInfo.h b/include/codec/SkEncodedInfo.h new file mode 100644 index 0000000000..f91660529e --- /dev/null +++ b/include/codec/SkEncodedInfo.h @@ -0,0 +1,178 @@ +/* + * Copyright 2016 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkEncodedInfo_DEFINED +#define SkEncodedInfo_DEFINED + +#include "SkImageInfo.h" + +struct SkEncodedInfo { +public: + + enum Alpha { + kOpaque_Alpha, + kUnpremul_Alpha, + + // Each pixel is either fully opaque or fully transparent. + // There is no difference between requesting kPremul or kUnpremul. + kBinary_Alpha, + + // Allows us to have a default constructor. Should be treated as + // invalid. + kUnknown_Alpha, + }; + + /* + * We strive to make the number of components per pixel obvious through + * our naming conventions. + * Ex: kRGB has 3 components. kRGBA has 4 components. + * + * This sometimes results in redundant Alpha and Color information. + * Ex: kRGB images must also be kOpaque. + */ + enum Color { + // PNG, WBMP + kGray_Color, + + // PNG + kGrayAlpha_Color, + + // PNG, GIF, BMP + kPalette_Color, + + // PNG, RAW + kRGB_Color, + kRGBA_Color, + + // BMP + kBGR_Color, + kBGRX_Color, + kBGRA_Color, + + // JPEG, WEBP + kYUV_Color, + + // WEBP + kYUVA_Color, + + // JPEG + // Photoshop actually writes inverted CMYK data into JPEGs, where zero + // represents 100% ink coverage. For this reason, we treat CMYK JPEGs + // as having inverted CMYK. libjpeg-turbo warns that this may break + // other applications, but the CMYK JPEGs we see on the web expect to + // be treated as inverted CMYK. + kInvertedCMYK_Color, + kYCCK_Color, + + // Allows us to have a default constructor. Should be treated as + // invalid. + kUnknown_Color, + }; + + static SkEncodedInfo Make(Color color, Alpha alpha, int bitsPerComponent) { + SkASSERT(1 == bitsPerComponent || + 2 == bitsPerComponent || + 4 == bitsPerComponent || + 8 == bitsPerComponent || + 16 == bitsPerComponent); + + switch (color) { + case kGray_Color: + SkASSERT(kOpaque_Alpha == alpha); + break; + case kGrayAlpha_Color: + SkASSERT(kOpaque_Alpha != alpha); + break; + case kPalette_Color: + SkASSERT(16 != bitsPerComponent); + break; + case kRGB_Color: + case kBGR_Color: + case kBGRX_Color: + SkASSERT(kOpaque_Alpha == alpha); + SkASSERT(bitsPerComponent >= 8); + break; + case kYUV_Color: + case kInvertedCMYK_Color: + case kYCCK_Color: + SkASSERT(kOpaque_Alpha == alpha); + SkASSERT(8 == bitsPerComponent); + break; + case kRGBA_Color: + SkASSERT(kOpaque_Alpha != alpha); + SkASSERT(bitsPerComponent >= 8); + break; + case kBGRA_Color: + case kYUVA_Color: + SkASSERT(kOpaque_Alpha != alpha); + SkASSERT(8 == bitsPerComponent); + break; + default: + SkASSERT(false); + break; + } + + return SkEncodedInfo(color, alpha, bitsPerComponent); + } + + /* + * Returns an SkImageInfo with Skia color and alpha types that are the + * closest possible match to the encoded info. + */ + SkImageInfo makeImageInfo(int width, int height) const { + switch (fColor) { + case kGray_Color: + SkASSERT(kOpaque_Alpha == fAlpha); + return SkImageInfo::Make(width, height, kGray_8_SkColorType, kOpaque_SkAlphaType); + case kGrayAlpha_Color: + SkASSERT(kOpaque_Alpha != fAlpha); + return SkImageInfo::Make(width, height, kN32_SkColorType, + kUnpremul_SkAlphaType); + case kPalette_Color: { + SkAlphaType alphaType = (kOpaque_Alpha == fAlpha) ? kOpaque_SkAlphaType : + kUnpremul_SkAlphaType; + return SkImageInfo::Make(width, height, kIndex_8_SkColorType, alphaType); + } + case kRGB_Color: + case kBGR_Color: + case kBGRX_Color: + case kYUV_Color: + case kInvertedCMYK_Color: + case kYCCK_Color: + SkASSERT(kOpaque_Alpha == fAlpha); + return SkImageInfo::Make(width, height, kN32_SkColorType, kOpaque_SkAlphaType); + case kRGBA_Color: + case kBGRA_Color: + case kYUVA_Color: + SkASSERT(kOpaque_Alpha != fAlpha); + return SkImageInfo::Make(width, height, kN32_SkColorType, kUnpremul_SkAlphaType); + default: + SkASSERT(false); + return SkImageInfo::MakeUnknown(); + } + } + + SkEncodedInfo() + : fColor(kUnknown_Color) + , fAlpha(kUnknown_Alpha) + , fBitsPerComponent(0) + {} + +private: + + SkEncodedInfo(Color color, Alpha alpha, uint8_t bitsPerComponent) + : fColor(color) + , fAlpha(alpha) + , fBitsPerComponent(bitsPerComponent) + {} + + Color fColor; + Alpha fAlpha; + uint8_t fBitsPerComponent; +}; + +#endif diff --git a/src/codec/SkBmpCodec.cpp b/src/codec/SkBmpCodec.cpp index ad6f0ddc4d..680436ab91 100644 --- a/src/codec/SkBmpCodec.cpp +++ b/src/codec/SkBmpCodec.cpp @@ -415,33 +415,47 @@ bool SkBmpCodec::ReadHeader(SkStream* stream, bool inIco, SkCodec** codecOut) { switch (inputFormat) { case kStandard_BmpInputFormat: { - // BMPs-in-ICOs often contain an alpha mask after the image, which - // means we cannot guarantee that an image is opaque, even if the - // embedded bmp is opaque. - // We use |isOpaque| to indicate if the BMP itself is opaque, but - // still need to recommend kUnpremul when it is contained in an ICO. - SkColorType colorType = kN32_SkColorType; - SkAlphaType alphaType = inIco ? kUnpremul_SkAlphaType : kOpaque_SkAlphaType; + // BMPs are generally opaque, however BMPs-in-ICOs may contain + // a transparency mask after the image. Therefore, we mark the + // alpha as kBinary if the BMP is contained in an ICO. + // We use |isOpaque| to indicate if the BMP itself is opaque. + SkEncodedInfo::Alpha alpha = inIco ? SkEncodedInfo::kBinary_Alpha : + SkEncodedInfo::kOpaque_Alpha; bool isOpaque = true; + + SkEncodedInfo::Color color; + uint8_t bitsPerComponent; switch (bitsPerPixel) { // Palette formats case 1: case 2: case 4: case 8: - // We cannot recommend a palette color type for ICOs because they - // may contain a transparency mask. - if (!inIco) { - colorType = kIndex_8_SkColorType; + // In the case of ICO, kBGRA is actually the closest match, + // since we will need to apply a transparency mask. + if (inIco) { + color = SkEncodedInfo::kBGRA_Color; + bitsPerComponent = 8; + } else { + color = SkEncodedInfo::kPalette_Color; + bitsPerComponent = (uint8_t) bitsPerPixel; } break; case 24: + color = SkEncodedInfo::kBGR_Color; + bitsPerComponent = 8; + break; case 32: // 32-bit BMP-in-ICOs actually use the alpha channel in place of a // transparency mask. if (inIco) { isOpaque = false; + alpha = SkEncodedInfo::kUnpremul_Alpha; + color = SkEncodedInfo::kBGRA_Color; + } else { + color = SkEncodedInfo::kBGRX_Color; } + bitsPerComponent = 8; break; default: SkCodecPrintf("Error: invalid input value for bits per pixel.\n"); @@ -453,11 +467,9 @@ bool SkBmpCodec::ReadHeader(SkStream* stream, bool inIco, SkCodec** codecOut) { SkASSERT(!inIco || nullptr != stream->getMemoryBase()); // Set the image info and create a codec. - const SkImageInfo imageInfo = SkImageInfo::Make(width, height, colorType, - alphaType); - *codecOut = new SkBmpStandardCodec(imageInfo, stream, bitsPerPixel, numColors, - bytesPerColor, offset - bytesRead, rowOrder, isOpaque, inIco); - + const SkEncodedInfo info = SkEncodedInfo::Make(color, alpha, bitsPerComponent); + *codecOut = new SkBmpStandardCodec(width, height, info, stream, bitsPerPixel, + numColors, bytesPerColor, offset - bytesRead, rowOrder, isOpaque, inIco); } return true; } @@ -495,13 +507,22 @@ bool SkBmpCodec::ReadHeader(SkStream* stream, bool inIco, SkCodec** codecOut) { return false; } - // Set the image info - SkAlphaType alphaType = masks->getAlphaMask() ? kUnpremul_SkAlphaType : - kOpaque_SkAlphaType; - const SkImageInfo imageInfo = SkImageInfo::Make(width, height, kN32_SkColorType, - alphaType); - *codecOut = new SkBmpMaskCodec(imageInfo, stream, bitsPerPixel, masks.release(), - rowOrder); + // Masked bmps are not a great fit for SkEncodedInfo, since they have + // arbitrary component orderings and bits per component. Here we choose + // somewhat reasonable values - it's ok that we don't match exactly + // because SkBmpMaskCodec has its own mask swizzler anyway. + SkEncodedInfo::Color color; + SkEncodedInfo::Alpha alpha; + if (masks->getAlphaMask()) { + color = SkEncodedInfo::kBGRA_Color; + alpha = SkEncodedInfo::kUnpremul_Alpha; + } else { + color = SkEncodedInfo::kBGR_Color; + alpha = SkEncodedInfo::kOpaque_Alpha; + } + const SkEncodedInfo info = SkEncodedInfo::Make(color, alpha, 8); + *codecOut = new SkBmpMaskCodec(width, height, info, stream, bitsPerPixel, + masks.release(), rowOrder); } return true; } @@ -526,10 +547,11 @@ bool SkBmpCodec::ReadHeader(SkStream* stream, bool inIco, SkCodec** codecOut) { if (codecOut) { // RLE inputs may skip pixels, leaving them as transparent. This // is uncommon, but we cannot be certain that an RLE bmp will be - // opaque. - const SkImageInfo imageInfo = SkImageInfo::Make(width, height, kN32_SkColorType, - kUnpremul_SkAlphaType); - *codecOut = new SkBmpRLECodec(imageInfo, stream, bitsPerPixel, numColors, + // opaque or that we will be able to represent it with a palette. + // For that reason, we always indicate that we are kBGRA. + const SkEncodedInfo info = SkEncodedInfo::Make(SkEncodedInfo::kBGRA_Color, + SkEncodedInfo::kBinary_Alpha, 8); + *codecOut = new SkBmpRLECodec(width, height, info, stream, bitsPerPixel, numColors, bytesPerColor, offset - bytesRead, rowOrder, RLEBytes); } return true; @@ -557,12 +579,12 @@ SkCodec* SkBmpCodec::NewFromStream(SkStream* stream, bool inIco) { return nullptr; } -SkBmpCodec::SkBmpCodec(const SkImageInfo& info, SkStream* stream, +SkBmpCodec::SkBmpCodec(int width, int height, const SkEncodedInfo& info, SkStream* stream, uint16_t bitsPerPixel, SkCodec::SkScanlineOrder rowOrder) - : INHERITED(info, stream) + : INHERITED(width, height, info, stream) , fBitsPerPixel(bitsPerPixel) , fRowOrder(rowOrder) - , fSrcRowBytes(SkAlign4(compute_row_bytes(info.width(), fBitsPerPixel))) + , fSrcRowBytes(SkAlign4(compute_row_bytes(width, fBitsPerPixel))) {} bool SkBmpCodec::onRewind() { diff --git a/src/codec/SkBmpCodec.h b/src/codec/SkBmpCodec.h index a7e8e58431..0ece7ad6ce 100644 --- a/src/codec/SkBmpCodec.h +++ b/src/codec/SkBmpCodec.h @@ -38,8 +38,8 @@ public: protected: - SkBmpCodec(const SkImageInfo& info, SkStream* stream, uint16_t bitsPerPixel, - SkCodec::SkScanlineOrder rowOrder); + SkBmpCodec(int width, int height, const SkEncodedInfo& info, SkStream* stream, + uint16_t bitsPerPixel, SkCodec::SkScanlineOrder rowOrder); SkEncodedFormat onGetEncodedFormat() const override { return kBMP_SkEncodedFormat; } diff --git a/src/codec/SkBmpMaskCodec.cpp b/src/codec/SkBmpMaskCodec.cpp index 21d231b15f..7d2d398bb4 100644 --- a/src/codec/SkBmpMaskCodec.cpp +++ b/src/codec/SkBmpMaskCodec.cpp @@ -12,10 +12,10 @@ /* * Creates an instance of the decoder */ -SkBmpMaskCodec::SkBmpMaskCodec(const SkImageInfo& info, SkStream* stream, +SkBmpMaskCodec::SkBmpMaskCodec(int width, int height, const SkEncodedInfo& info, SkStream* stream, uint16_t bitsPerPixel, SkMasks* masks, SkCodec::SkScanlineOrder rowOrder) - : INHERITED(info, stream, bitsPerPixel, rowOrder) + : INHERITED(width, height, info, stream, bitsPerPixel, rowOrder) , fMasks(masks) , fMaskSwizzler(nullptr) , fSrcBuffer(new uint8_t [this->srcRowBytes()]) diff --git a/src/codec/SkBmpMaskCodec.h b/src/codec/SkBmpMaskCodec.h index 93b3bca5a0..cc8af856e8 100644 --- a/src/codec/SkBmpMaskCodec.h +++ b/src/codec/SkBmpMaskCodec.h @@ -22,13 +22,13 @@ public: * Called only by SkBmpCodec::NewFromStream * There should be no other callers despite this being public * - * @param srcInfo contains the source width and height + * @param info contains properties of the encoded data * @param stream the stream of encoded image data * @param bitsPerPixel the number of bits used to store each pixel * @param masks color masks for certain bmp formats * @param rowOrder indicates whether rows are ordered top-down or bottom-up */ - SkBmpMaskCodec(const SkImageInfo& srcInfo, SkStream* stream, + SkBmpMaskCodec(int width, int height, const SkEncodedInfo& info, SkStream* stream, uint16_t bitsPerPixel, SkMasks* masks, SkCodec::SkScanlineOrder rowOrder); diff --git a/src/codec/SkBmpRLECodec.cpp b/src/codec/SkBmpRLECodec.cpp index 793bbfd260..d80dd1a18a 100644 --- a/src/codec/SkBmpRLECodec.cpp +++ b/src/codec/SkBmpRLECodec.cpp @@ -14,12 +14,12 @@ * Creates an instance of the decoder * Called only by NewFromStream */ -SkBmpRLECodec::SkBmpRLECodec(const SkImageInfo& info, SkStream* stream, +SkBmpRLECodec::SkBmpRLECodec(int width, int height, const SkEncodedInfo& info, SkStream* stream, uint16_t bitsPerPixel, uint32_t numColors, uint32_t bytesPerColor, uint32_t offset, SkCodec::SkScanlineOrder rowOrder, size_t RLEBytes) - : INHERITED(info, stream, bitsPerPixel, rowOrder) + : INHERITED(width, height, info, stream, bitsPerPixel, rowOrder) , fColorTable(nullptr) , fNumColors(numColors) , fBytesPerColor(bytesPerColor) diff --git a/src/codec/SkBmpRLECodec.h b/src/codec/SkBmpRLECodec.h index 2ddf8d8b90..e0afccd927 100644 --- a/src/codec/SkBmpRLECodec.h +++ b/src/codec/SkBmpRLECodec.h @@ -23,7 +23,7 @@ public: * Called only by SkBmpCodec::NewFromStream * There should be no other callers despite this being public * - * @param srcInfo contains the source width and height + * @param info contains properties of the encoded data * @param stream the stream of encoded image data * @param bitsPerPixel the number of bits used to store each pixel * @param numColors the number of colors in the color table @@ -35,7 +35,7 @@ public: * @param RLEBytes indicates the amount of data left in the stream * after decoding the headers */ - SkBmpRLECodec(const SkImageInfo& srcInfo, SkStream* stream, + SkBmpRLECodec(int width, int height, const SkEncodedInfo& info, SkStream* stream, uint16_t bitsPerPixel, uint32_t numColors, uint32_t bytesPerColor, uint32_t offset, SkCodec::SkScanlineOrder rowOrder, size_t RLEBytes); diff --git a/src/codec/SkBmpStandardCodec.cpp b/src/codec/SkBmpStandardCodec.cpp index 80a989ae4d..a509c75b6d 100644 --- a/src/codec/SkBmpStandardCodec.cpp +++ b/src/codec/SkBmpStandardCodec.cpp @@ -14,12 +14,12 @@ * Creates an instance of the decoder * Called only by NewFromStream */ -SkBmpStandardCodec::SkBmpStandardCodec(const SkImageInfo& info, SkStream* stream, - uint16_t bitsPerPixel, uint32_t numColors, +SkBmpStandardCodec::SkBmpStandardCodec(int width, int height, const SkEncodedInfo& info, + SkStream* stream, uint16_t bitsPerPixel, uint32_t numColors, uint32_t bytesPerColor, uint32_t offset, SkCodec::SkScanlineOrder rowOrder, bool isOpaque, bool inIco) - : INHERITED(info, stream, bitsPerPixel, rowOrder) + : INHERITED(width, height, info, stream, bitsPerPixel, rowOrder) , fColorTable(nullptr) , fNumColors(numColors) , fBytesPerColor(bytesPerColor) diff --git a/src/codec/SkBmpStandardCodec.h b/src/codec/SkBmpStandardCodec.h index 557f6535c9..b2b53df6c8 100644 --- a/src/codec/SkBmpStandardCodec.h +++ b/src/codec/SkBmpStandardCodec.h @@ -24,7 +24,7 @@ public: * Called only by SkBmpCodec::NewFromStream * There should be no other callers despite this being public * - * @param srcInfo contains the source width and height + * @param info contains properties of the encoded data * @param stream the stream of encoded image data * @param bitsPerPixel the number of bits used to store each pixel * @param numColors the number of colors in the color table @@ -37,7 +37,7 @@ public: * the icp mask, if there is one) * @param inIco indicates if the bmp is embedded in an ico file */ - SkBmpStandardCodec(const SkImageInfo& srcInfo, SkStream* stream, + SkBmpStandardCodec(int width, int height, const SkEncodedInfo& info, SkStream* stream, uint16_t bitsPerPixel, uint32_t numColors, uint32_t bytesPerColor, uint32_t offset, SkCodec::SkScanlineOrder rowOrder, bool isOpaque, bool inIco); diff --git a/src/codec/SkCodec.cpp b/src/codec/SkCodec.cpp index 7bc831a6ac..8468f8a099 100644 --- a/src/codec/SkCodec.cpp +++ b/src/codec/SkCodec.cpp @@ -114,9 +114,10 @@ SkCodec* SkCodec::NewFromData(SkData* data, SkPngChunkReader* reader) { return NewFromStream(new SkMemoryStream(data), reader); } -SkCodec::SkCodec(const SkImageInfo& info, SkStream* stream, sk_sp colorSpace, - Origin origin) - : fSrcInfo(info) +SkCodec::SkCodec(int width, int height, const SkEncodedInfo& info, SkStream* stream, + sk_sp colorSpace, Origin origin) + : fEncodedInfo(info) + , fSrcInfo(info.makeImageInfo(width, height)) , fStream(stream) , fNeedsRewind(false) , fColorSpace(colorSpace) diff --git a/src/codec/SkGifCodec.cpp b/src/codec/SkGifCodec.cpp index 2233c66c19..cdd9d088f1 100644 --- a/src/codec/SkGifCodec.cpp +++ b/src/codec/SkGifCodec.cpp @@ -199,25 +199,23 @@ bool SkGifCodec::ReadHeader(SkStream* stream, SkCodec** codecOut, GifFileType** } bool frameIsSubset = (size != frameRect.size()); - // Determine the recommended alpha type. The transIndex might be valid if it less + // Determine the encoded alpha type. The transIndex might be valid if it less // than 256. We are not certain that the index is valid until we process the color // table, since some gifs have color tables with less than 256 colors. If // there might be a valid transparent index, we must indicate that the image has // alpha. - // In the case where we must support alpha, we have the option to set the - // suggested alpha type to kPremul or kUnpremul. Both are valid since the alpha - // component will always be 0xFF or the entire 32-bit pixel will be set to zero. - // We prefer kPremul because we support kPremul, and it is more efficient to use - // kPremul directly even when kUnpremul is supported. - SkAlphaType alphaType = (transIndex < 256) ? kPremul_SkAlphaType : kOpaque_SkAlphaType; + // In the case where we must support alpha, we indicate kBinary, since every + // pixel will either be fully opaque or fully transparent. + SkEncodedInfo::Alpha alpha = (transIndex < 256) ? SkEncodedInfo::kBinary_Alpha : + SkEncodedInfo::kOpaque_Alpha; // Return the codec - // kIndex is the most natural color type for gifs, so we set this as - // the default. - SkImageInfo imageInfo = SkImageInfo::Make(size.width(), size.height(), kIndex_8_SkColorType, - alphaType); - *codecOut = new SkGifCodec(imageInfo, streamDeleter.release(), gif.release(), transIndex, - frameRect, frameIsSubset); + // Use kPalette since Gifs are encoded with a color table. + // Use 8-bits per component, since this is the output we get from giflib. + // FIXME: Gifs can actually be encoded with 4-bits per pixel. Can we support this? + SkEncodedInfo info = SkEncodedInfo::Make(SkEncodedInfo::kPalette_Color, alpha, 8); + *codecOut = new SkGifCodec(size.width(), size.height(), info, streamDeleter.release(), + gif.release(), transIndex, frameRect, frameIsSubset); } else { SkASSERT(nullptr != gifOut); streamDeleter.release(); @@ -239,9 +237,9 @@ SkCodec* SkGifCodec::NewFromStream(SkStream* stream) { return nullptr; } -SkGifCodec::SkGifCodec(const SkImageInfo& srcInfo, SkStream* stream, GifFileType* gif, - uint32_t transIndex, const SkIRect& frameRect, bool frameIsSubset) - : INHERITED(srcInfo, stream) +SkGifCodec::SkGifCodec(int width, int height, const SkEncodedInfo& info, SkStream* stream, + GifFileType* gif, uint32_t transIndex, const SkIRect& frameRect, bool frameIsSubset) + : INHERITED(width, height, info, stream) , fGif(gif) , fSrcBuffer(new uint8_t[this->getInfo().width()]) , fFrameRect(frameRect) diff --git a/src/codec/SkGifCodec.h b/src/codec/SkGifCodec.h index a08e7ee552..984bceafd1 100644 --- a/src/codec/SkGifCodec.h +++ b/src/codec/SkGifCodec.h @@ -182,15 +182,15 @@ private: * Creates an instance of the decoder * Called only by NewFromStream * - * @param srcInfo contains the source width and height + * @param info contains properties of the encoded data * @param stream the stream of image data * @param gif pointer to library type that manages gif decode * takes ownership * @param transIndex The transparent index. An invalid value * indicates that there is no transparent index. */ - SkGifCodec(const SkImageInfo& srcInfo, SkStream* stream, GifFileType* gif, uint32_t transIndex, - const SkIRect& frameRect, bool frameIsSubset); + SkGifCodec(int width, int height, const SkEncodedInfo& info, SkStream* stream, + GifFileType* gif, uint32_t transIndex, const SkIRect& frameRect, bool frameIsSubset); SkAutoTCallVProc fGif; // owned SkAutoTDeleteArray fSrcBuffer; diff --git a/src/codec/SkIcoCodec.cpp b/src/codec/SkIcoCodec.cpp index d74c150ff5..0e81b72407 100644 --- a/src/codec/SkIcoCodec.cpp +++ b/src/codec/SkIcoCodec.cpp @@ -168,20 +168,22 @@ SkCodec* SkIcoCodec::NewFromStream(SkStream* stream) { maxIndex = i; } } - SkImageInfo info = codecs->operator[](maxIndex)->getInfo(); + int width = codecs->operator[](maxIndex)->getInfo().width(); + int height = codecs->operator[](maxIndex)->getInfo().height(); + SkEncodedInfo info = codecs->operator[](maxIndex)->getEncodedInfo(); // Note that stream is owned by the embedded codec, the ico does not need // direct access to the stream. - return new SkIcoCodec(info, codecs.release()); + return new SkIcoCodec(width, height, info, codecs.release()); } /* * Creates an instance of the decoder * Called only by NewFromStream */ -SkIcoCodec::SkIcoCodec(const SkImageInfo& info, +SkIcoCodec::SkIcoCodec(int width, int height, const SkEncodedInfo& info, SkTArray, true>* codecs) - : INHERITED(info, nullptr) + : INHERITED(width, height, info, nullptr) , fEmbeddedCodecs(codecs) , fCurrScanlineCodec(nullptr) {} diff --git a/src/codec/SkIcoCodec.h b/src/codec/SkIcoCodec.h index 9a3f248af5..8c56aee4c6 100644 --- a/src/codec/SkIcoCodec.h +++ b/src/codec/SkIcoCodec.h @@ -71,7 +71,8 @@ private: * Constructor called by NewFromStream * @param embeddedCodecs codecs for the embedded images, takes ownership */ - SkIcoCodec(const SkImageInfo& srcInfo, SkTArray, true>* embeddedCodecs); + SkIcoCodec(int width, int height, const SkEncodedInfo& info, + SkTArray, true>* embeddedCodecs); SkAutoTDelete, true>> fEmbeddedCodecs; // owned diff --git a/src/codec/SkJpegCodec.cpp b/src/codec/SkJpegCodec.cpp index 76d2ee8572..6b97b2fe4a 100644 --- a/src/codec/SkJpegCodec.cpp +++ b/src/codec/SkJpegCodec.cpp @@ -211,17 +211,20 @@ bool SkJpegCodec::ReadHeader(SkStream* stream, SkCodec** codecOut, } if (codecOut) { - // Recommend the color type to decode to - const SkColorType colorType = decoderMgr->getColorType(); + // Get the encoded color type + SkEncodedInfo::Color color = decoderMgr->getEncodedColor(); + if (SkEncodedInfo::kUnknown_Color == color) { + return false; + } // Create image info object and the codec - const SkImageInfo& imageInfo = SkImageInfo::Make(decoderMgr->dinfo()->image_width, - decoderMgr->dinfo()->image_height, colorType, kOpaque_SkAlphaType); + SkEncodedInfo info = SkEncodedInfo::Make(color, SkEncodedInfo::kOpaque_Alpha, 8); Origin orientation = get_exif_orientation(decoderMgr->dinfo()); sk_sp colorSpace = get_icc_profile(decoderMgr->dinfo()); - *codecOut = new SkJpegCodec(imageInfo, stream, decoderMgr.release(), colorSpace, + *codecOut = new SkJpegCodec(decoderMgr->dinfo()->image_width, + decoderMgr->dinfo()->image_height, info, stream, decoderMgr.release(), colorSpace, orientation); } else { SkASSERT(nullptr != decoderMgrOut); @@ -242,9 +245,9 @@ SkCodec* SkJpegCodec::NewFromStream(SkStream* stream) { return nullptr; } -SkJpegCodec::SkJpegCodec(const SkImageInfo& srcInfo, SkStream* stream, +SkJpegCodec::SkJpegCodec(int width, int height, const SkEncodedInfo& info, SkStream* stream, JpegDecoderMgr* decoderMgr, sk_sp colorSpace, Origin origin) - : INHERITED(srcInfo, stream, colorSpace, origin) + : INHERITED(width, height, info, stream, colorSpace, origin) , fDecoderMgr(decoderMgr) , fReadyState(decoderMgr->dinfo()->global_state) , fSwizzlerSubset(SkIRect::MakeEmpty()) diff --git a/src/codec/SkJpegCodec.h b/src/codec/SkJpegCodec.h index d3ea132da7..f8cddd0221 100644 --- a/src/codec/SkJpegCodec.h +++ b/src/codec/SkJpegCodec.h @@ -86,13 +86,13 @@ private: * Creates an instance of the decoder * Called only by NewFromStream * - * @param srcInfo contains the source width and height + * @param info contains properties of the encoded data * @param stream the encoded image data * @param decoderMgr holds decompress struct, src manager, and error manager * takes ownership */ - SkJpegCodec(const SkImageInfo& srcInfo, SkStream* stream, JpegDecoderMgr* decoderMgr, - sk_sp colorSpace, Origin origin); + SkJpegCodec(int width, int height, const SkEncodedInfo& info, SkStream* stream, + JpegDecoderMgr* decoderMgr, sk_sp colorSpace, Origin origin); /* * Checks if the conversion between the input image and the requested output diff --git a/src/codec/SkJpegDecoderMgr.cpp b/src/codec/SkJpegDecoderMgr.cpp index 63228bb585..8517e0dac2 100644 --- a/src/codec/SkJpegDecoderMgr.cpp +++ b/src/codec/SkJpegDecoderMgr.cpp @@ -35,12 +35,20 @@ SkCodec::Result JpegDecoderMgr::returnFailure(const char caller[], SkCodec::Resu return result; } -SkColorType JpegDecoderMgr::getColorType() { +SkEncodedInfo::Color JpegDecoderMgr::getEncodedColor() { switch (fDInfo.jpeg_color_space) { case JCS_GRAYSCALE: - return kGray_8_SkColorType; + return SkEncodedInfo::kGray_Color; + case JCS_YCbCr: + return SkEncodedInfo::kYUV_Color; + case JCS_RGB: + return SkEncodedInfo::kRGB_Color; + case JCS_YCCK: + return SkEncodedInfo::kYCCK_Color; + case JCS_CMYK: + return SkEncodedInfo::kInvertedCMYK_Color; default: - return kN32_SkColorType; + return SkEncodedInfo::kUnknown_Color; } } diff --git a/src/codec/SkJpegDecoderMgr.h b/src/codec/SkJpegDecoderMgr.h index e1127bad34..a5078bb2d3 100644 --- a/src/codec/SkJpegDecoderMgr.h +++ b/src/codec/SkJpegDecoderMgr.h @@ -43,9 +43,10 @@ public: void init(); /* - * Recommend a color type based on the encoded format + * Returns the encoded color type of the jpeg, or kUnknown if the + * color type can't be determined */ - SkColorType getColorType(); + SkEncodedInfo::Color getEncodedColor(); /* * Free memory used by the decode manager diff --git a/src/codec/SkPngCodec.cpp b/src/codec/SkPngCodec.cpp index 8ae2360f25..33c3b6095b 100644 --- a/src/codec/SkPngCodec.cpp +++ b/src/codec/SkPngCodec.cpp @@ -279,7 +279,7 @@ sk_sp read_color_space(png_structp png_ptr, png_infop info_ptr) { // png_structp on success. // @param info_ptrp Optional output variable. If non-NULL, will be set to a new // png_infop on success; -// @param imageInfo Optional output variable. If non-NULL, will be set to +// @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. @@ -290,7 +290,8 @@ sk_sp read_color_space(png_structp png_ptr, png_infop info_ptr) { // 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, - SkImageInfo* imageInfo, int* bitDepthPtr, int* numberPassesPtr) { + int* width, int* height, SkEncodedInfo* info, int* bitDepthPtr, + int* numberPassesPtr) { // 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); @@ -348,8 +349,8 @@ static bool read_header(SkStream* stream, SkPngChunkReader* chunkReader, // 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; + SkEncodedInfo::Color color; + SkEncodedInfo::Alpha alpha; switch (encodedColorType) { case PNG_COLOR_TYPE_PALETTE: // Extract multiple pixels with bit depths of 1, 2, and 4 from a single @@ -359,20 +360,21 @@ static bool read_header(SkStream* stream, SkPngChunkReader* chunkReader, 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; + color = SkEncodedInfo::kPalette_Color; + // Set the alpha depending on if a transparency chunk exists. + alpha = png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) ? + SkEncodedInfo::kUnpremul_Alpha : SkEncodedInfo::kOpaque_Alpha; break; case PNG_COLOR_TYPE_RGB: 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); - alphaType = kUnpremul_SkAlphaType; + color = SkEncodedInfo::kRGBA_Color; + alpha = SkEncodedInfo::kBinary_Alpha; } else { - alphaType = kOpaque_SkAlphaType; + color = SkEncodedInfo::kRGB_Color; + alpha = SkEncodedInfo::kOpaque_Alpha; } - colorType = kN32_SkColorType; break; case PNG_COLOR_TYPE_GRAY: // Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel. @@ -383,29 +385,26 @@ static bool read_header(SkStream* stream, SkPngChunkReader* chunkReader, if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(png_ptr); - - // We will recommend kN32 here since we do not support kGray - // with alpha. - colorType = kN32_SkColorType; - alphaType = kUnpremul_SkAlphaType; + color = SkEncodedInfo::kGrayAlpha_Color; + alpha = SkEncodedInfo::kBinary_Alpha; } else { - colorType = kGray_8_SkColorType; - alphaType = kOpaque_SkAlphaType; + color = SkEncodedInfo::kGray_Color; + alpha = SkEncodedInfo::kOpaque_Alpha; } break; case PNG_COLOR_TYPE_GRAY_ALPHA: - // We will recommend kN32 here since we do not support anything - // similar to GRAY_ALPHA. - colorType = kN32_SkColorType; - alphaType = kUnpremul_SkAlphaType; + color = SkEncodedInfo::kGrayAlpha_Color; + alpha = SkEncodedInfo::kUnpremul_Alpha; break; case PNG_COLOR_TYPE_RGBA: - colorType = kN32_SkColorType; - alphaType = kUnpremul_SkAlphaType; + color = SkEncodedInfo::kRGBA_Color; + alpha = SkEncodedInfo::kUnpremul_Alpha; break; default: // All the color types have been covered above. SkASSERT(false); + color = SkEncodedInfo::kRGBA_Color; + alpha = SkEncodedInfo::kUnpremul_Alpha; } int numberPasses = png_set_interlace_handling(png_ptr); @@ -413,13 +412,14 @@ static bool read_header(SkStream* stream, SkPngChunkReader* chunkReader, *numberPassesPtr = numberPasses; } - SkColorProfileType profileType = kLinear_SkColorProfileType; - if (png_get_valid(png_ptr, info_ptr, PNG_INFO_sRGB)) { - profileType = kSRGB_SkColorProfileType; + if (info) { + *info = SkEncodedInfo::Make(color, alpha, 8); } - - if (imageInfo) { - *imageInfo = SkImageInfo::Make(origWidth, origHeight, colorType, alphaType, profileType); + if (width) { + *width = origWidth; + } + if (height) { + *height = origHeight; } autoClean.release(); if (png_ptrp) { @@ -432,10 +432,10 @@ static bool read_header(SkStream* stream, SkPngChunkReader* chunkReader, return true; } -SkPngCodec::SkPngCodec(const SkImageInfo& info, SkStream* stream, SkPngChunkReader* chunkReader, - png_structp png_ptr, png_infop info_ptr, int bitDepth, int numberPasses, - sk_sp colorSpace) - : INHERITED(info, stream, colorSpace) +SkPngCodec::SkPngCodec(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 colorSpace) + : INHERITED(width, height, info, stream, colorSpace) , fPngChunkReader(SkSafeRef(chunkReader)) , fPng_ptr(png_ptr) , fInfo_ptr(info_ptr) @@ -538,7 +538,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, nullptr, nullptr, nullptr)) { return false; } @@ -644,10 +644,11 @@ uint32_t SkPngCodec::onGetFillValue(SkColorType colorType) const { // Subclass of SkPngCodec which supports scanline decoding class SkPngScanlineDecoder : public SkPngCodec { public: - SkPngScanlineDecoder(const SkImageInfo& srcInfo, SkStream* stream, + SkPngScanlineDecoder(int width, int height, const SkEncodedInfo& info, SkStream* stream, SkPngChunkReader* chunkReader, png_structp png_ptr, png_infop info_ptr, int bitDepth, sk_sp colorSpace) - : INHERITED(srcInfo, stream, chunkReader, png_ptr, info_ptr, bitDepth, 1, colorSpace) + : INHERITED(width, height, info, stream, chunkReader, png_ptr, info_ptr, bitDepth, 1, + colorSpace) , fSrcRow(nullptr) {} @@ -710,11 +711,11 @@ private: class SkPngInterlacedScanlineDecoder : public SkPngCodec { public: - SkPngInterlacedScanlineDecoder(const SkImageInfo& srcInfo, SkStream* stream, - SkPngChunkReader* chunkReader, png_structp png_ptr, png_infop info_ptr, - int bitDepth, int numberPasses, sk_sp colorSpace) - : INHERITED(srcInfo, stream, chunkReader, png_ptr, info_ptr, bitDepth, numberPasses, - colorSpace) + 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 colorSpace) + : INHERITED(width, height, info, stream, chunkReader, png_ptr, info_ptr, bitDepth, + numberPasses, colorSpace) , fHeight(-1) , fCanSkipRewind(false) { @@ -836,23 +837,24 @@ SkCodec* SkPngCodec::NewFromStream(SkStream* stream, SkPngChunkReader* chunkRead SkAutoTDelete streamDeleter(stream); png_structp png_ptr; png_infop info_ptr; - SkImageInfo imageInfo; + int width, height; + SkEncodedInfo imageInfo; int bitDepth; int numberPasses; - if (!read_header(stream, chunkReader, &png_ptr, &info_ptr, &imageInfo, &bitDepth, - &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(imageInfo, streamDeleter.release(), chunkReader, - png_ptr, info_ptr, bitDepth, colorSpace); + return new SkPngScanlineDecoder(width, height, imageInfo, streamDeleter.release(), + chunkReader, png_ptr, info_ptr, bitDepth, colorSpace); } - return new SkPngInterlacedScanlineDecoder(imageInfo, streamDeleter.release(), chunkReader, - png_ptr, info_ptr, bitDepth, numberPasses, - colorSpace); + return new SkPngInterlacedScanlineDecoder(width, height, imageInfo, streamDeleter.release(), + chunkReader, png_ptr, info_ptr, bitDepth, + numberPasses, colorSpace); } diff --git a/src/codec/SkPngCodec.h b/src/codec/SkPngCodec.h index 5673e5b4fa..8587bf8a14 100644 --- a/src/codec/SkPngCodec.h +++ b/src/codec/SkPngCodec.h @@ -41,8 +41,8 @@ protected: return fSwizzler; } - SkPngCodec(const SkImageInfo&, SkStream*, SkPngChunkReader*, png_structp, png_infop, int, int, - sk_sp); + SkPngCodec(int width, int height, const SkEncodedInfo&, SkStream*, SkPngChunkReader*, + png_structp, png_infop, int, int, sk_sp); png_structp png_ptr() { return fPng_ptr; } SkSwizzler* swizzler() { return fSwizzler; } diff --git a/src/codec/SkRawCodec.cpp b/src/codec/SkRawCodec.cpp index ef8ba700a4..51de2fcec0 100644 --- a/src/codec/SkRawCodec.cpp +++ b/src/codec/SkRawCodec.cpp @@ -515,8 +515,16 @@ public: } } - const SkImageInfo& getImageInfo() const { - return fImageInfo; + const SkEncodedInfo& getEncodedInfo() const { + return fEncodedInfo; + } + + int width() const { + return fWidth; + } + + int height() const { + return fHeight; } bool isScalable() const { @@ -545,8 +553,11 @@ private: return 0x2A == get_endian_short(header + 2, littleEndian); } - void init(const int width, const int height, const dng_point& cfaPatternSize) { - fImageInfo = SkImageInfo::Make(width, height, kN32_SkColorType, kOpaque_SkAlphaType); + void init(int width, int height, const dng_point& cfaPatternSize) { + fWidth = width; + fHeight = height; + fEncodedInfo = SkEncodedInfo::Make(SkEncodedInfo::kRGB_Color, + SkEncodedInfo::kOpaque_Alpha, 8); // The DNG SDK scales only during demosaicing, so scaling is only possible when // a mosaic info is available. @@ -616,7 +627,9 @@ private: SkAutoTDelete fNegative; SkAutoTDelete fDngStream; - SkImageInfo fImageInfo; + int fWidth; + int fHeight; + SkEncodedInfo fEncodedInfo; bool fIsScalable; bool fIsXtransImage; }; @@ -764,5 +777,5 @@ bool SkRawCodec::onDimensionsSupported(const SkISize& dim) { SkRawCodec::~SkRawCodec() {} SkRawCodec::SkRawCodec(SkDngImage* dngImage) - : INHERITED(dngImage->getImageInfo(), nullptr) + : INHERITED(dngImage->width(), dngImage->height(), dngImage->getEncodedInfo(), nullptr) , fDngImage(dngImage) {} diff --git a/src/codec/SkWbmpCodec.cpp b/src/codec/SkWbmpCodec.cpp index 90ee322b1f..9a842ac91f 100644 --- a/src/codec/SkWbmpCodec.cpp +++ b/src/codec/SkWbmpCodec.cpp @@ -104,8 +104,8 @@ bool SkWbmpCodec::readRow(uint8_t* row) { return this->stream()->read(row, fSrcRowBytes) == fSrcRowBytes; } -SkWbmpCodec::SkWbmpCodec(const SkImageInfo& info, SkStream* stream) - : INHERITED(info, stream) +SkWbmpCodec::SkWbmpCodec(int width, int height, const SkEncodedInfo& info, SkStream* stream) + : INHERITED(width, height, info, stream) , fSrcRowBytes(get_src_row_bytes(this->getInfo().width())) , fSwizzler(nullptr) , fColorTable(nullptr) @@ -166,9 +166,9 @@ SkCodec* SkWbmpCodec::NewFromStream(SkStream* stream) { if (!read_header(stream, &size)) { return nullptr; } - SkImageInfo info = SkImageInfo::Make(size.width(), size.height(), - kGray_8_SkColorType, kOpaque_SkAlphaType); - return new SkWbmpCodec(info, streamDeleter.release()); + SkEncodedInfo info = SkEncodedInfo::Make(SkEncodedInfo::kGray_Color, + SkEncodedInfo::kOpaque_Alpha, 1); + return new SkWbmpCodec(size.width(), size.height(), info, streamDeleter.release()); } int SkWbmpCodec::onGetScanlines(void* dst, int count, size_t dstRowBytes) { diff --git a/src/codec/SkWbmpCodec.h b/src/codec/SkWbmpCodec.h index f43f615ed2..9f29237e23 100644 --- a/src/codec/SkWbmpCodec.h +++ b/src/codec/SkWbmpCodec.h @@ -44,7 +44,7 @@ private: */ bool readRow(uint8_t* row); - SkWbmpCodec(const SkImageInfo&, SkStream*); + SkWbmpCodec(int width, int height, const SkEncodedInfo&, SkStream*); const size_t fSrcRowBytes; diff --git a/src/codec/SkWebpCodec.cpp b/src/codec/SkWebpCodec.cpp index 77af8e5e8f..e40c3f2377 100644 --- a/src/codec/SkWebpCodec.cpp +++ b/src/codec/SkWebpCodec.cpp @@ -31,7 +31,7 @@ bool SkWebpCodec::IsWebp(const void* buf, size_t bytesRead) { // Parse headers of RIFF container, and check for valid Webp (VP8) content. // NOTE: This calls peek instead of read, since onGetPixels will need these // bytes again. -static bool webp_parse_header(SkStream* stream, SkImageInfo* info) { +static bool webp_parse_header(SkStream* stream, int* width, int* height, SkEncodedInfo* info) { unsigned char buffer[WEBP_VP8_HEADER_SIZE]; SkASSERT(WEBP_VP8_HEADER_SIZE <= SkCodec::MinBufferedBytesNeeded()); @@ -62,22 +62,55 @@ static bool webp_parse_header(SkStream* stream, SkImageInfo* info) { } if (info) { - // FIXME: Is N32 the right type? - // Is unpremul the right type? Clients of SkCodec may assume it's the - // best type, when Skia currently cannot draw unpremul (and raster is faster - // with premul). - *info = SkImageInfo::Make(features.width, features.height, kN32_SkColorType, - SkToBool(features.has_alpha) ? kUnpremul_SkAlphaType - : kOpaque_SkAlphaType); + SkEncodedInfo::Color color; + SkEncodedInfo::Alpha alpha; + switch (features.format) { + case 0: + // This indicates a "mixed" format. We would see this for + // animated webps or for webps encoded in multiple fragments. + // I believe that this is a rare case. + // We could also guess kYUV here, but I think it makes more + // sense to guess kBGRA which is likely closer to the final + // output. Otherwise, we might end up converting + // BGRA->YUVA->BGRA. + color = SkEncodedInfo::kBGRA_Color; + alpha = SkEncodedInfo::kUnpremul_Alpha; + break; + case 1: + // This is the lossy format (YUV). + if (SkToBool(features.has_alpha)) { + color = SkEncodedInfo::kYUVA_Color; + alpha = SkEncodedInfo::kUnpremul_Alpha; + } else { + color = SkEncodedInfo::kYUV_Color; + alpha = SkEncodedInfo::kOpaque_Alpha; + } + break; + case 2: + // This is the lossless format (BGRA). + // FIXME: Should we check the has_alpha flag here? It looks + // like the image is encoded with an alpha channel + // regardless of whether or not the alpha flag is set. + color = SkEncodedInfo::kBGRA_Color; + alpha = SkEncodedInfo::kUnpremul_Alpha; + break; + default: + return false; + } + + *width = features.width; + *height = features.height; + *info = SkEncodedInfo::Make(color, alpha, 8); } return true; } SkCodec* SkWebpCodec::NewFromStream(SkStream* stream) { SkAutoTDelete streamDeleter(stream); - SkImageInfo info; - if (webp_parse_header(stream, &info)) { - return new SkWebpCodec(info, streamDeleter.release()); + int width, height; + SkEncodedInfo info; + if (webp_parse_header(stream, &width, &height, &info)) { + return new SkWebpCodec(width, height, info, streamDeleter.release()); } return nullptr; } @@ -252,7 +285,7 @@ SkCodec::Result SkWebpCodec::onGetPixels(const SkImageInfo& dstInfo, void* dst, } } -SkWebpCodec::SkWebpCodec(const SkImageInfo& info, SkStream* stream) +SkWebpCodec::SkWebpCodec(int width, int height, const SkEncodedInfo& info, SkStream* stream) // The spec says an unmarked image is sRGB, so we return that space here. // TODO: Add support for parsing ICC profiles from webps. - : INHERITED(info, stream, SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named)) {} + : INHERITED(width, height, info, stream, SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named)) {} diff --git a/src/codec/SkWebpCodec.h b/src/codec/SkWebpCodec.h index 2d81cf3d9c..908bf2cd4f 100644 --- a/src/codec/SkWebpCodec.h +++ b/src/codec/SkWebpCodec.h @@ -34,7 +34,7 @@ protected: bool onGetValidSubset(SkIRect* /* desiredSubset */) const override; private: - SkWebpCodec(const SkImageInfo&, SkStream*); + SkWebpCodec(int width, int height, const SkEncodedInfo&, SkStream*); typedef SkCodec INHERITED; }; -- cgit v1.2.3