Revert "Switch SkCodec to use skcms" and follow on change
This reverts commit 81886e8f9461c7049751c6a2c194a1df632dd362 and
f8ae5ce20cf6df2dab4149fb2838d9d8dc6bd1af
("Fix CMYK handling in JPEG codec")
This fixes the Android build, which was failing a CTS test with this
change.
Bug: skia:6839
Bug: skia:8052
TBR=djsollen@google.com
As with the original, no API change
Change-Id: Ic744a610e9f431707f871de44f9f64040bc60d14
Reviewed-on: https://skia-review.googlesource.com/148810
Reviewed-by: Leon Scroggins <scroggo@google.com>
Commit-Queue: Leon Scroggins <scroggo@google.com>
diff --git a/BUILD.gn b/BUILD.gn
index 3369a9a..9019cea 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -863,7 +863,6 @@
"src/codec/SkCodec.cpp",
"src/codec/SkCodecImageGenerator.cpp",
"src/codec/SkColorTable.cpp",
- "src/codec/SkEncodedInfo.cpp",
"src/codec/SkGifCodec.cpp",
"src/codec/SkMaskSwizzler.cpp",
"src/codec/SkMasks.cpp",
diff --git a/gn/tests.gni b/gn/tests.gni
index e829c70..9731514 100644
--- a/gn/tests.gni
+++ b/gn/tests.gni
@@ -64,7 +64,6 @@
"$_tests/EGLImageTest.cpp",
"$_tests/EmptyPathTest.cpp",
"$_tests/EncodeTest.cpp",
- "$_tests/EncodedInfoTest.cpp",
"$_tests/ExifTest.cpp",
"$_tests/F16StagesTest.cpp",
"$_tests/FillPathTest.cpp",
diff --git a/include/codec/SkCodec.h b/include/codec/SkCodec.h
index 2e263ea..ecb762e 100644
--- a/include/codec/SkCodec.h
+++ b/include/codec/SkCodec.h
@@ -13,6 +13,7 @@
#include "../private/SkEncodedInfo.h"
#include "SkCodecAnimation.h"
#include "SkColor.h"
+#include "SkColorSpaceXform.h"
#include "SkEncodedImageFormat.h"
#include "SkEncodedOrigin.h"
#include "SkImageInfo.h"
@@ -670,9 +671,21 @@
protected:
const SkEncodedInfo& getEncodedInfo() const { return fEncodedInfo; }
- using XformFormat = skcms_PixelFormat;
+ using XformFormat = SkColorSpaceXform::ColorFormat;
- SkCodec(SkEncodedInfo&&,
+ SkCodec(int width,
+ int height,
+ const SkEncodedInfo&,
+ XformFormat srcFormat,
+ std::unique_ptr<SkStream>,
+ sk_sp<SkColorSpace>,
+ SkEncodedOrigin = kTopLeft_SkEncodedOrigin);
+
+ /**
+ * Allows the subclass to set the recommended SkImageInfo
+ */
+ SkCodec(const SkEncodedInfo&,
+ const SkImageInfo&,
XformFormat srcFormat,
std::unique_ptr<SkStream>,
SkEncodedOrigin = kTopLeft_SkEncodedOrigin);
@@ -767,14 +780,16 @@
virtual int onOutputScanline(int inputScanline) const;
+ bool initializeColorXform(const SkImageInfo& dstInfo, SkEncodedInfo::Alpha);
// Some classes never need a colorXform e.g.
// - ICO uses its embedded codec's colorXform
// - WBMP is just Black/White
virtual bool usesColorXform() const { return true; }
+ void applyColorXform(void* dst, const void* src, int count, SkAlphaType) const;
void applyColorXform(void* dst, const void* src, int count) const;
- bool colorXform() const { return fXformTime != kNo_XformTime; }
- bool xformOnDecode() const { return fXformTime == kDecodeRow_XformTime; }
+ SkColorSpaceXform* colorXform() const { return fColorXform.get(); }
+ bool xformOnDecode() const { return fXformOnDecode; }
virtual int onGetFrameCount() {
return 1;
@@ -798,16 +813,9 @@
SkImageInfo fDstInfo;
Options fOptions;
-
- enum XformTime {
- kNo_XformTime,
- kPalette_XformTime,
- kDecodeRow_XformTime,
- };
- XformTime fXformTime;
XformFormat fDstXformFormat; // Based on fDstInfo.
- skcms_ICCProfile fDstProfile;
- skcms_AlphaFormat fDstXformAlphaFormat;
+ std::unique_ptr<SkColorSpaceXform> fColorXform;
+ bool fXformOnDecode;
// Only meaningful during scanline decodes.
int fCurrScanline;
@@ -815,15 +823,12 @@
bool fStartedIncrementalDecode;
/**
- * Return whether we can convert to dst.
+ * Return whether {srcColor, srcIsOpaque, srcCS} can convert to dst.
*
* Will be called for the appropriate frame, prior to initializing the colorXform.
*/
virtual bool conversionSupported(const SkImageInfo& dst, SkColorType srcColor,
- bool srcIsOpaque, bool needsColorXform);
-
- bool initializeColorXform(const SkImageInfo& dstInfo, SkEncodedInfo::Alpha, bool srcIsOpaque);
-
+ bool srcIsOpaque, const SkColorSpace* srcCS) const;
/**
* Return whether these dimensions are supported as a scale.
*
diff --git a/include/private/SkEncodedInfo.h b/include/private/SkEncodedInfo.h
index 5d6dabe..217b859 100644
--- a/include/private/SkEncodedInfo.h
+++ b/include/private/SkEncodedInfo.h
@@ -8,25 +8,12 @@
#ifndef SkEncodedInfo_DEFINED
#define SkEncodedInfo_DEFINED
-#include "SkData.h"
#include "SkImageInfo.h"
-#include "../../third_party/skcms/skcms.h"
+
+class SkColorSpace;
struct SkEncodedInfo {
public:
- class ICCProfile {
- public:
- static std::unique_ptr<ICCProfile> Make(sk_sp<SkData>);
- static std::unique_ptr<ICCProfile> MakeSRGB();
- static std::unique_ptr<ICCProfile> Make(const skcms_ICCProfile&);
-
- const skcms_ICCProfile* profile() const { return &fProfile; }
- private:
- ICCProfile(const skcms_ICCProfile&, sk_sp<SkData> = nullptr);
-
- skcms_ICCProfile fProfile;
- sk_sp<SkData> fData;
- };
enum Alpha {
kOpaque_Alpha,
@@ -52,20 +39,6 @@
// PNG
kGrayAlpha_Color,
- // PNG with Skia-specific sBIT
- // Like kGrayAlpha, except this expects to be treated as
- // kAlpha_8_SkColorType, which ignores the gray component. If
- // decoded to full color (e.g. kN32), the gray component is respected
- // (so it can share code with kGrayAlpha).
- kXAlpha_Color,
-
- // PNG
- // 565 images may be encoded to PNG by specifying the number of
- // significant bits for each channel. This is a strange 565
- // representation because the image is still encoded with 8 bits per
- // component.
- k565_Color,
-
// PNG, GIF, BMP
kPalette_Color,
@@ -94,18 +67,7 @@
kYCCK_Color,
};
- static SkEncodedInfo Make(int width, int height, Color color, Alpha alpha,
- int bitsPerComponent) {
- return Make(width, height, color, alpha, bitsPerComponent, nullptr);
- }
-
- static SkEncodedInfo MakeSRGB(int width, int height, Color color, Alpha alpha,
- int bitsPerComponent) {
- return Make(width, height, color, alpha, bitsPerComponent, ICCProfile::MakeSRGB());
- }
-
- static SkEncodedInfo Make(int width, int height, Color color, Alpha alpha,
- int bitsPerComponent, std::unique_ptr<ICCProfile> profile) {
+ static SkEncodedInfo Make(Color color, Alpha alpha, int bitsPerComponent) {
SkASSERT(1 == bitsPerComponent ||
2 == bitsPerComponent ||
4 == bitsPerComponent ||
@@ -143,51 +105,29 @@
SkASSERT(kOpaque_Alpha != alpha);
SkASSERT(8 == bitsPerComponent);
break;
- case kXAlpha_Color:
- SkASSERT(kUnpremul_Alpha == alpha);
- SkASSERT(8 == bitsPerComponent);
- break;
- case k565_Color:
- SkASSERT(kOpaque_Alpha == alpha);
- SkASSERT(8 == bitsPerComponent);
- break;
default:
SkASSERT(false);
break;
}
- return SkEncodedInfo(width, height, color, alpha, bitsPerComponent, std::move(profile));
+ return SkEncodedInfo(color, alpha, bitsPerComponent);
}
/*
- * Returns a recommended SkImageInfo.
- *
- * TODO: Leave this up to the client.
+ * Returns an SkImageInfo with Skia color and alpha types that are the
+ * closest possible match to the encoded info.
*/
- SkImageInfo makeImageInfo() const {
- auto ct = kGray_Color == fColor ? kGray_8_SkColorType :
- kXAlpha_Color == fColor ? kAlpha_8_SkColorType :
- k565_Color == fColor ? kRGB_565_SkColorType :
- kN32_SkColorType ;
+ SkImageInfo makeImageInfo(int width, int height, sk_sp<SkColorSpace> colorSpace) const {
+ auto ct = kGray_Color == fColor ? kGray_8_SkColorType :
+ kN32_SkColorType ;
auto alpha = kOpaque_Alpha == fAlpha ? kOpaque_SkAlphaType
: kUnpremul_SkAlphaType;
- sk_sp<SkColorSpace> cs = fProfile ? SkColorSpace::Make(*fProfile->profile())
- : nullptr;
- if (!cs) {
- cs = SkColorSpace::MakeSRGB();
- }
- return SkImageInfo::Make(fWidth, fHeight, ct, alpha, std::move(cs));
+ return SkImageInfo::Make(width, height, ct, alpha, std::move(colorSpace));
}
- int width() const { return fWidth; }
- int height() const { return fHeight; }
- Color color() const { return fColor; }
- Alpha alpha() const { return fAlpha; }
+ Color color() const { return fColor; }
+ Alpha alpha() const { return fAlpha; }
bool opaque() const { return fAlpha == kOpaque_Alpha; }
- const skcms_ICCProfile* profile() const {
- if (!fProfile) return nullptr;
- return fProfile->profile();
- }
uint8_t bitsPerComponent() const { return fBitsPerComponent; }
@@ -195,7 +135,6 @@
switch (fColor) {
case kGray_Color:
return fBitsPerComponent;
- case kXAlpha_Color:
case kGrayAlpha_Color:
return 2 * fBitsPerComponent;
case kPalette_Color:
@@ -203,7 +142,6 @@
case kRGB_Color:
case kBGR_Color:
case kYUV_Color:
- case k565_Color:
return 3 * fBitsPerComponent;
case kRGBA_Color:
case kBGRA_Color:
@@ -218,38 +156,17 @@
}
}
- SkEncodedInfo(const SkEncodedInfo& orig) = delete;
- SkEncodedInfo& operator=(const SkEncodedInfo&) = delete;
-
- SkEncodedInfo(SkEncodedInfo&& orig) = default;
- SkEncodedInfo& operator=(SkEncodedInfo&&) = default;
-
- // Explicit copy method, to avoid accidental copying.
- SkEncodedInfo copy() const {
- auto copy = SkEncodedInfo::Make(fWidth, fHeight, fColor, fAlpha, fBitsPerComponent);
- if (fProfile) {
- copy.fProfile.reset(new ICCProfile(*fProfile.get()));
- }
- return copy;
- }
-
private:
- SkEncodedInfo(int width, int height, Color color, Alpha alpha,
- uint8_t bitsPerComponent, std::unique_ptr<ICCProfile> profile)
- : fWidth(width)
- , fHeight(height)
- , fColor(color)
+
+ SkEncodedInfo(Color color, Alpha alpha, uint8_t bitsPerComponent)
+ : fColor(color)
, fAlpha(alpha)
, fBitsPerComponent(bitsPerComponent)
- , fProfile(std::move(profile))
{}
- int fWidth;
- int fHeight;
- Color fColor;
- Alpha fAlpha;
- uint8_t fBitsPerComponent;
- std::unique_ptr<ICCProfile> fProfile;
+ Color fColor;
+ Alpha fAlpha;
+ uint8_t fBitsPerComponent;
};
#endif
diff --git a/resources/images/mandrill_cmyk.jpg b/resources/images/mandrill_cmyk.jpg
deleted file mode 100644
index 0a7f29b..0000000
--- a/resources/images/mandrill_cmyk.jpg
+++ /dev/null
Binary files differ
diff --git a/src/codec/SkBmpBaseCodec.cpp b/src/codec/SkBmpBaseCodec.cpp
index 2b0ed1f..c548514 100644
--- a/src/codec/SkBmpBaseCodec.cpp
+++ b/src/codec/SkBmpBaseCodec.cpp
@@ -9,8 +9,9 @@
SkBmpBaseCodec::~SkBmpBaseCodec() {}
-SkBmpBaseCodec::SkBmpBaseCodec(SkEncodedInfo&& info, std::unique_ptr<SkStream> stream,
+SkBmpBaseCodec::SkBmpBaseCodec(int width, int height, const SkEncodedInfo& info,
+ std::unique_ptr<SkStream> stream,
uint16_t bitsPerPixel, SkCodec::SkScanlineOrder rowOrder)
- : INHERITED(std::move(info), std::move(stream), bitsPerPixel, rowOrder)
+ : INHERITED(width, height, info, std::move(stream), bitsPerPixel, rowOrder)
, fSrcBuffer(sk_malloc_canfail(this->srcRowBytes()))
{}
diff --git a/src/codec/SkBmpBaseCodec.h b/src/codec/SkBmpBaseCodec.h
index 8a076a5..24277fc 100644
--- a/src/codec/SkBmpBaseCodec.h
+++ b/src/codec/SkBmpBaseCodec.h
@@ -25,7 +25,7 @@
bool didCreateSrcBuffer() const { return fSrcBuffer != nullptr; }
protected:
- SkBmpBaseCodec(SkEncodedInfo&& info, std::unique_ptr<SkStream>,
+ SkBmpBaseCodec(int width, int height, const SkEncodedInfo& info, std::unique_ptr<SkStream>,
uint16_t bitsPerPixel, SkCodec::SkScanlineOrder rowOrder);
uint8_t* srcBuffer() { return reinterpret_cast<uint8_t*>(fSrcBuffer.get()); }
diff --git a/src/codec/SkBmpCodec.cpp b/src/codec/SkBmpCodec.cpp
index 02d13dd..7dd49a5 100644
--- a/src/codec/SkBmpCodec.cpp
+++ b/src/codec/SkBmpCodec.cpp
@@ -481,8 +481,8 @@
SkASSERT(!inIco || nullptr != stream->getMemoryBase());
// Set the image info and create a codec.
- auto info = SkEncodedInfo::MakeSRGB(width, height, color, alpha, bitsPerComponent);
- codecOut->reset(new SkBmpStandardCodec(std::move(info),
+ const SkEncodedInfo info = SkEncodedInfo::Make(color, alpha, bitsPerComponent);
+ codecOut->reset(new SkBmpStandardCodec(width, height, info,
std::unique_ptr<SkStream>(stream),
bitsPerPixel, numColors, bytesPerColor,
offset - bytesRead, rowOrder, isOpaque,
@@ -539,8 +539,8 @@
color = SkEncodedInfo::kBGR_Color;
alpha = SkEncodedInfo::kOpaque_Alpha;
}
- auto info = SkEncodedInfo::MakeSRGB(width, height, color, alpha, 8);
- codecOut->reset(new SkBmpMaskCodec(std::move(info),
+ const SkEncodedInfo info = SkEncodedInfo::Make(color, alpha, 8);
+ codecOut->reset(new SkBmpMaskCodec(width, height, info,
std::unique_ptr<SkStream>(stream), bitsPerPixel,
masks.release(), rowOrder));
return static_cast<SkBmpMaskCodec*>(codecOut->get())->didCreateSrcBuffer()
@@ -570,9 +570,9 @@
// is uncommon, but we cannot be certain that an RLE bmp will be
// opaque or that we will be able to represent it with a palette.
// For that reason, we always indicate that we are kBGRA.
- auto info = SkEncodedInfo::MakeSRGB(width, height, SkEncodedInfo::kBGRA_Color,
- SkEncodedInfo::kBinary_Alpha, 8);
- codecOut->reset(new SkBmpRLECodec(std::move(info),
+ const SkEncodedInfo info = SkEncodedInfo::Make(SkEncodedInfo::kBGRA_Color,
+ SkEncodedInfo::kBinary_Alpha, 8);
+ codecOut->reset(new SkBmpRLECodec(width, height, info,
std::unique_ptr<SkStream>(stream), bitsPerPixel,
numColors, bytesPerColor, offset - bytesRead,
rowOrder));
@@ -600,12 +600,14 @@
return kSuccess == *result ? std::move(codec) : nullptr;
}
-SkBmpCodec::SkBmpCodec(SkEncodedInfo&& info, std::unique_ptr<SkStream> stream,
+SkBmpCodec::SkBmpCodec(int width, int height, const SkEncodedInfo& info,
+ std::unique_ptr<SkStream> stream,
uint16_t bitsPerPixel, SkCodec::SkScanlineOrder rowOrder)
- : INHERITED(std::move(info), kXformSrcColorFormat, std::move(stream))
+ : INHERITED(width, height, info, kXformSrcColorFormat, std::move(stream),
+ SkColorSpace::MakeSRGB())
, fBitsPerPixel(bitsPerPixel)
, fRowOrder(rowOrder)
- , fSrcRowBytes(SkAlign4(compute_row_bytes(this->getEncodedInfo().width(), fBitsPerPixel)))
+ , fSrcRowBytes(SkAlign4(compute_row_bytes(width, fBitsPerPixel)))
, fXformBuffer(nullptr)
{}
diff --git a/src/codec/SkBmpCodec.h b/src/codec/SkBmpCodec.h
index eff1891..3196ae1 100644
--- a/src/codec/SkBmpCodec.h
+++ b/src/codec/SkBmpCodec.h
@@ -38,7 +38,7 @@
protected:
- SkBmpCodec(SkEncodedInfo&& info, std::unique_ptr<SkStream>,
+ SkBmpCodec(int width, int height, const SkEncodedInfo& info, std::unique_ptr<SkStream>,
uint16_t bitsPerPixel, SkCodec::SkScanlineOrder rowOrder);
SkEncodedImageFormat onGetEncodedFormat() const override { return SkEncodedImageFormat::kBMP; }
@@ -103,7 +103,7 @@
* than RGBA.
*/
static constexpr SkColorType kXformSrcColorType = kBGRA_8888_SkColorType;
- static constexpr auto kXformSrcColorFormat = skcms_PixelFormat_BGRA_8888;
+ static constexpr auto kXformSrcColorFormat = SkColorSpaceXform::kBGRA_8888_ColorFormat;
private:
diff --git a/src/codec/SkBmpMaskCodec.cpp b/src/codec/SkBmpMaskCodec.cpp
index 0cb0924..ddcc47b 100644
--- a/src/codec/SkBmpMaskCodec.cpp
+++ b/src/codec/SkBmpMaskCodec.cpp
@@ -12,11 +12,11 @@
/*
* Creates an instance of the decoder
*/
-SkBmpMaskCodec::SkBmpMaskCodec(SkEncodedInfo&& info,
+SkBmpMaskCodec::SkBmpMaskCodec(int width, int height, const SkEncodedInfo& info,
std::unique_ptr<SkStream> stream,
uint16_t bitsPerPixel, SkMasks* masks,
SkCodec::SkScanlineOrder rowOrder)
- : INHERITED(std::move(info), std::move(stream), bitsPerPixel, rowOrder)
+ : INHERITED(width, height, info, std::move(stream), bitsPerPixel, rowOrder)
, fMasks(masks)
, fMaskSwizzler(nullptr)
{}
diff --git a/src/codec/SkBmpMaskCodec.h b/src/codec/SkBmpMaskCodec.h
index 370cddb..4b0dbde 100644
--- a/src/codec/SkBmpMaskCodec.h
+++ b/src/codec/SkBmpMaskCodec.h
@@ -31,7 +31,7 @@
* @param masks color masks for certain bmp formats
* @param rowOrder indicates whether rows are ordered top-down or bottom-up
*/
- SkBmpMaskCodec(SkEncodedInfo&& info, std::unique_ptr<SkStream>,
+ SkBmpMaskCodec(int width, int height, const SkEncodedInfo& info, std::unique_ptr<SkStream>,
uint16_t bitsPerPixel, SkMasks* masks,
SkCodec::SkScanlineOrder rowOrder);
diff --git a/src/codec/SkBmpRLECodec.cpp b/src/codec/SkBmpRLECodec.cpp
index 8a7fb9e8..3fe7a03 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(SkEncodedInfo&& info,
+SkBmpRLECodec::SkBmpRLECodec(int width, int height, const SkEncodedInfo& info,
std::unique_ptr<SkStream> stream,
uint16_t bitsPerPixel, uint32_t numColors,
uint32_t bytesPerColor, uint32_t offset,
SkCodec::SkScanlineOrder rowOrder)
- : INHERITED(std::move(info), std::move(stream), bitsPerPixel, rowOrder)
+ : INHERITED(width, height, info, std::move(stream), bitsPerPixel, rowOrder)
, fColorTable(nullptr)
, fNumColors(numColors)
, fBytesPerColor(bytesPerColor)
diff --git a/src/codec/SkBmpRLECodec.h b/src/codec/SkBmpRLECodec.h
index dc6f26d..70e97a7 100644
--- a/src/codec/SkBmpRLECodec.h
+++ b/src/codec/SkBmpRLECodec.h
@@ -35,7 +35,7 @@
* headers
* @param rowOrder indicates whether rows are ordered top-down or bottom-up
*/
- SkBmpRLECodec(SkEncodedInfo&& info, std::unique_ptr<SkStream>,
+ SkBmpRLECodec(int width, int height, const SkEncodedInfo& info, std::unique_ptr<SkStream>,
uint16_t bitsPerPixel, uint32_t numColors, uint32_t bytesPerColor,
uint32_t offset, SkCodec::SkScanlineOrder rowOrder);
diff --git a/src/codec/SkBmpStandardCodec.cpp b/src/codec/SkBmpStandardCodec.cpp
index dd71535..153d081 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(SkEncodedInfo&& info, std::unique_ptr<SkStream> stream,
- uint16_t bitsPerPixel, uint32_t numColors,
- uint32_t bytesPerColor, uint32_t offset,
+SkBmpStandardCodec::SkBmpStandardCodec(int width, int height, const SkEncodedInfo& info,
+ std::unique_ptr<SkStream> stream, uint16_t bitsPerPixel,
+ uint32_t numColors, uint32_t bytesPerColor, uint32_t offset,
SkCodec::SkScanlineOrder rowOrder,
bool isOpaque, bool inIco)
- : INHERITED(std::move(info), std::move(stream), bitsPerPixel, rowOrder)
+ : INHERITED(width, height, info, std::move(stream), bitsPerPixel, rowOrder)
, fColorTable(nullptr)
, fNumColors(numColors)
, fBytesPerColor(bytesPerColor)
@@ -146,33 +146,20 @@
return true;
}
-static SkEncodedInfo make_info(SkEncodedInfo::Color color,
- SkEncodedInfo::Alpha alpha, int bitsPerPixel) {
- // This is just used for the swizzler, which does not need the width or height.
- return SkEncodedInfo::Make(0, 0, color, alpha, bitsPerPixel);
-}
-
-SkEncodedInfo SkBmpStandardCodec::swizzlerInfo() const {
- const auto& info = this->getEncodedInfo();
- if (fInIco) {
- if (this->bitsPerPixel() <= 8) {
- return make_info(SkEncodedInfo::kPalette_Color,
- info.alpha(), this->bitsPerPixel());
- }
- if (this->bitsPerPixel() == 24) {
- return make_info(SkEncodedInfo::kBGR_Color,
- SkEncodedInfo::kOpaque_Alpha, 8);
- }
- }
-
- return make_info(info.color(), info.alpha(), info.bitsPerComponent());
-}
-
void SkBmpStandardCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options& opts) {
// In the case of bmp-in-icos, we will report BGRA to the client,
// since we may be required to apply an alpha mask after the decode.
// However, the swizzler needs to know the actual format of the bmp.
- SkEncodedInfo encodedInfo = this->swizzlerInfo();
+ SkEncodedInfo encodedInfo = this->getEncodedInfo();
+ if (fInIco) {
+ if (this->bitsPerPixel() <= 8) {
+ encodedInfo = SkEncodedInfo::Make(SkEncodedInfo::kPalette_Color,
+ encodedInfo.alpha(), this->bitsPerPixel());
+ } else if (this->bitsPerPixel() == 24) {
+ encodedInfo = SkEncodedInfo::Make(SkEncodedInfo::kBGR_Color,
+ SkEncodedInfo::kOpaque_Alpha, 8);
+ }
+ }
// Get a pointer to the color table if it exists
const SkPMColor* colorPtr = get_color_ptr(fColorTable.get());
diff --git a/src/codec/SkBmpStandardCodec.h b/src/codec/SkBmpStandardCodec.h
index 84a1299..1790692 100644
--- a/src/codec/SkBmpStandardCodec.h
+++ b/src/codec/SkBmpStandardCodec.h
@@ -39,9 +39,9 @@
* the icp mask, if there is one)
* @param inIco indicates if the bmp is embedded in an ico file
*/
- SkBmpStandardCodec(SkEncodedInfo&& info, std::unique_ptr<SkStream> stream,
- uint16_t bitsPerPixel, uint32_t numColors, uint32_t bytesPerColor,
- uint32_t offset, SkCodec::SkScanlineOrder rowOrder,
+ SkBmpStandardCodec(int width, int height, const SkEncodedInfo& info,
+ std::unique_ptr<SkStream> stream, uint16_t bitsPerPixel, uint32_t numColors,
+ uint32_t bytesPerColor, uint32_t offset, SkCodec::SkScanlineOrder rowOrder,
bool isOpaque, bool inIco);
protected:
@@ -63,8 +63,12 @@
}
private:
+
+ /*
+ * Creates the color table
+ */
bool createColorTable(SkColorType colorType, SkAlphaType alphaType);
- SkEncodedInfo swizzlerInfo() const;
+
void initializeSwizzler(const SkImageInfo& dstInfo, const Options& opts);
int decodeRows(const SkImageInfo& dstInfo, void* dst, size_t dstRowBytes,
diff --git a/src/codec/SkCodec.cpp b/src/codec/SkCodec.cpp
index d12646a..5564e89 100644
--- a/src/codec/SkCodec.cpp
+++ b/src/codec/SkCodec.cpp
@@ -9,6 +9,7 @@
#include "SkCodec.h"
#include "SkCodecPriv.h"
#include "SkColorSpace.h"
+#include "SkColorSpaceXformPriv.h"
#include "SkData.h"
#include "SkFrameHolder.h"
#include "SkGifCodec.h"
@@ -125,10 +126,26 @@
return MakeFromStream(SkMemoryStream::Make(std::move(data)), nullptr, reader);
}
-SkCodec::SkCodec(SkEncodedInfo&& info, XformFormat srcFormat, std::unique_ptr<SkStream> stream,
- SkEncodedOrigin origin)
- : fEncodedInfo(std::move(info))
- , fSrcInfo(fEncodedInfo.makeImageInfo())
+SkCodec::SkCodec(int width, int height, const SkEncodedInfo& info,
+ XformFormat srcFormat, std::unique_ptr<SkStream> stream,
+ sk_sp<SkColorSpace> colorSpace, SkEncodedOrigin origin)
+ : fEncodedInfo(info)
+ , fSrcInfo(info.makeImageInfo(width, height, std::move(colorSpace)))
+ , fSrcXformFormat(srcFormat)
+ , fStream(std::move(stream))
+ , fNeedsRewind(false)
+ , fOrigin(origin)
+ , fDstInfo()
+ , fOptions()
+ , fCurrScanline(-1)
+ , fStartedIncrementalDecode(false)
+{}
+
+SkCodec::SkCodec(const SkEncodedInfo& info, const SkImageInfo& imageInfo,
+ XformFormat srcFormat, std::unique_ptr<SkStream> stream,
+ SkEncodedOrigin origin)
+ : fEncodedInfo(info)
+ , fSrcInfo(imageInfo)
, fSrcXformFormat(srcFormat)
, fStream(std::move(stream))
, fNeedsRewind(false)
@@ -142,7 +159,7 @@
SkCodec::~SkCodec() {}
bool SkCodec::conversionSupported(const SkImageInfo& dst, SkColorType srcColor,
- bool srcIsOpaque, bool needsColorXform) {
+ bool srcIsOpaque, const SkColorSpace* srcCS) const {
if (!valid_alpha(dst.alphaType(), srcIsOpaque)) {
return false;
}
@@ -156,8 +173,8 @@
case kRGB_565_SkColorType:
return srcIsOpaque;
case kGray_8_SkColorType:
- SkASSERT(!needsColorXform);
- return kGray_8_SkColorType == srcColor && srcIsOpaque;
+ return kGray_8_SkColorType == srcColor && srcIsOpaque &&
+ !needs_color_xform(dst, srcCS);
case kAlpha_8_SkColorType:
// conceptually we can convert anything into alpha_8, but we haven't actually coded
// all of those other conversions yet, so only return true for the case we have codec.
@@ -165,6 +182,7 @@
default:
return false;
}
+
}
bool SkCodec::rewindIfNeeded() {
@@ -227,8 +245,13 @@
const Options& options) {
const int index = options.fFrameIndex;
if (0 == index) {
- return this->initializeColorXform(info, fEncodedInfo.alpha(), fEncodedInfo.opaque())
- ? kSuccess : kInvalidConversion;
+ if (!this->conversionSupported(info, fSrcInfo.colorType(), fEncodedInfo.opaque(),
+ fSrcInfo.colorSpace())
+ || !this->initializeColorXform(info, fEncodedInfo.alpha()))
+ {
+ return kInvalidConversion;
+ }
+ return kSuccess;
}
if (index < 0) {
@@ -251,6 +274,11 @@
const auto* frame = frameHolder->getFrame(index);
SkASSERT(frame);
+ if (!this->conversionSupported(info, fSrcInfo.colorType(), !frame->hasAlpha(),
+ fSrcInfo.colorSpace())) {
+ return kInvalidConversion;
+ }
+
const int requiredFrame = frame->getRequiredFrame();
if (requiredFrame != kNoFrame) {
if (options.fPriorFrame != kNoFrame) {
@@ -296,8 +324,7 @@
}
}
- return this->initializeColorXform(info, frame->reportedAlpha(), !frame->hasAlpha())
- ? kSuccess : kInvalidConversion;
+ return this->initializeColorXform(info, frame->reportedAlpha()) ? kSuccess : kInvalidConversion;
}
SkCodec::Result SkCodec::getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
@@ -585,80 +612,63 @@
}
}
-static inline bool select_xform_format(SkColorType colorType, bool forColorTable,
- skcms_PixelFormat* outFormat) {
- SkASSERT(outFormat);
-
+static inline SkColorSpaceXform::ColorFormat select_xform_format_ct(SkColorType colorType) {
switch (colorType) {
case kRGBA_8888_SkColorType:
- *outFormat = skcms_PixelFormat_RGBA_8888;
- break;
+ return SkColorSpaceXform::kRGBA_8888_ColorFormat;
case kBGRA_8888_SkColorType:
- *outFormat = skcms_PixelFormat_BGRA_8888;
- break;
+ return SkColorSpaceXform::kBGRA_8888_ColorFormat;
case kRGB_565_SkColorType:
- if (forColorTable) {
#ifdef SK_PMCOLOR_IS_RGBA
- *outFormat = skcms_PixelFormat_RGBA_8888;
+ return SkColorSpaceXform::kRGBA_8888_ColorFormat;
#else
- *outFormat = skcms_PixelFormat_BGRA_8888;
+ return SkColorSpaceXform::kBGRA_8888_ColorFormat;
#endif
- break;
- }
- *outFormat = skcms_PixelFormat_BGR_565;
- break;
- case kRGBA_F16_SkColorType:
- *outFormat = skcms_PixelFormat_RGBA_hhhh;
- break;
default:
- return false;
+ SkASSERT(false);
+ return SkColorSpaceXform::kRGBA_8888_ColorFormat;
}
+}
+
+bool SkCodec::initializeColorXform(const SkImageInfo& dstInfo, SkEncodedInfo::Alpha encodedAlpha) {
+ fColorXform = nullptr;
+ fXformOnDecode = false;
+ if (!this->usesColorXform()) {
+ return true;
+ }
+ // FIXME: In SkWebpCodec, if a frame is blending with a prior frame, we don't need
+ // a colorXform to do a color correct premul, since the blend step will handle
+ // premultiplication. But there is no way to know whether we need to blend from
+ // inside this call.
+ if (needs_color_xform(dstInfo, fSrcInfo.colorSpace())) {
+ fColorXform = SkMakeColorSpaceXform(fSrcInfo.colorSpace(), dstInfo.colorSpace());
+ if (!fColorXform) {
+ return false;
+ }
+
+ // We will apply the color xform when reading the color table unless F16 is requested.
+ fXformOnDecode = SkEncodedInfo::kPalette_Color != fEncodedInfo.color()
+ || kRGBA_F16_SkColorType == dstInfo.colorType();
+ if (fXformOnDecode) {
+ fDstXformFormat = select_xform_format(dstInfo.colorType());
+ } else {
+ fDstXformFormat = select_xform_format_ct(dstInfo.colorType());
+ }
+ }
+
return true;
}
-bool SkCodec::initializeColorXform(const SkImageInfo& dstInfo, SkEncodedInfo::Alpha encodedAlpha,
- bool srcIsOpaque) {
- fXformTime = kNo_XformTime;
- bool needsColorXform = false;
- if (this->usesColorXform() && dstInfo.colorSpace()) {
- dstInfo.colorSpace()->toProfile(&fDstProfile);
- if (kRGBA_F16_SkColorType == dstInfo.colorType()
- || !skcms_ApproximatelyEqualProfiles(fEncodedInfo.profile(), &fDstProfile) ) {
- needsColorXform = true;
- if (kGray_8_SkColorType == dstInfo.colorType()) {
- return false;
- }
- }
- }
-
- if (!this->conversionSupported(dstInfo, fSrcInfo.colorType(), srcIsOpaque, needsColorXform)) {
- return false;
- }
-
- if (needsColorXform) {
- fXformTime = SkEncodedInfo::kPalette_Color != fEncodedInfo.color()
- || kRGBA_F16_SkColorType == dstInfo.colorType()
- ? kDecodeRow_XformTime : kPalette_XformTime;
- if (!select_xform_format(dstInfo.colorType(), fXformTime == kPalette_XformTime,
- &fDstXformFormat)) {
- return false;
- }
- if (encodedAlpha == SkEncodedInfo::kUnpremul_Alpha
- && dstInfo.alphaType() == kPremul_SkAlphaType) {
- fDstXformAlphaFormat = skcms_AlphaFormat_PremulAsEncoded;
- } else {
- fDstXformAlphaFormat = skcms_AlphaFormat_Unpremul;
- }
- }
- return true;
+void SkCodec::applyColorXform(void* dst, const void* src, int count, SkAlphaType at) const {
+ SkASSERT(fColorXform);
+ SkAssertResult(fColorXform->apply(fDstXformFormat, dst,
+ fSrcXformFormat, src,
+ count, at));
}
void SkCodec::applyColorXform(void* dst, const void* src, int count) const {
- const auto* srcProfile = fEncodedInfo.profile();
- SkASSERT(srcProfile);
- SkAssertResult(skcms_Transform(src, fSrcXformFormat, skcms_AlphaFormat_Unpremul, srcProfile,
- dst, fDstXformFormat, fDstXformAlphaFormat, &fDstProfile,
- count));
+ auto alphaType = select_xform_alpha(fDstInfo.alphaType(), fSrcInfo.alphaType());
+ this->applyColorXform(dst, src, count, alphaType);
}
std::vector<SkCodec::FrameInfo> SkCodec::getFrameInfo() {
diff --git a/src/codec/SkCodecPriv.h b/src/codec/SkCodecPriv.h
index 10bd064..d7db89f 100644
--- a/src/codec/SkCodecPriv.h
+++ b/src/codec/SkCodecPriv.h
@@ -9,6 +9,8 @@
#define SkCodecPriv_DEFINED
#include "SkColorData.h"
+#include "SkColorSpaceXform.h"
+#include "SkColorSpaceXformPriv.h"
#include "SkColorTable.h"
#include "SkEncodedInfo.h"
#include "SkEncodedOrigin.h"
@@ -241,6 +243,30 @@
}
}
+static inline bool needs_premul(SkAlphaType dstAT, SkEncodedInfo::Alpha encodedAlpha) {
+ return kPremul_SkAlphaType == dstAT && SkEncodedInfo::kUnpremul_Alpha == encodedAlpha;
+}
+
+static inline bool needs_color_xform(const SkImageInfo& dstInfo, const SkColorSpace* srcCS) {
+ // We never perform a color xform in legacy mode.
+ if (!dstInfo.colorSpace()) {
+ return false;
+ }
+
+ // None of the codecs we have output F16 natively, so if we're trying to decode to F16,
+ // we'll have to use SkColorSpaceXform to get there.
+ bool isF16 = kRGBA_F16_SkColorType == dstInfo.colorType();
+
+ // Need a color xform when dst space does not match the src.
+ bool srcDstNotEqual = !SkColorSpace::Equals(srcCS, dstInfo.colorSpace());
+
+ return isF16 || srcDstNotEqual;
+}
+
+static inline SkAlphaType select_xform_alpha(SkAlphaType dstAlphaType, SkAlphaType srcAlphaType) {
+ return (kOpaque_SkAlphaType == srcAlphaType) ? kOpaque_SkAlphaType : dstAlphaType;
+}
+
bool is_orientation_marker(const uint8_t* data, size_t data_length, SkEncodedOrigin* orientation);
#endif // SkCodecPriv_DEFINED
diff --git a/src/codec/SkEncodedInfo.cpp b/src/codec/SkEncodedInfo.cpp
index 75c5062..63c52b3 100644
--- a/src/codec/SkEncodedInfo.cpp
+++ b/src/codec/SkEncodedInfo.cpp
@@ -5,28 +5,4 @@
* found in the LICENSE file.
*/
-#include "SkEncodedInfo.h"
-
-std::unique_ptr<SkEncodedInfo::ICCProfile> SkEncodedInfo::ICCProfile::Make(sk_sp<SkData> data) {
- if (data) {
- skcms_ICCProfile profile;
- if (skcms_Parse(data->data(), data->size(), &profile)) {
- return std::unique_ptr<ICCProfile>(new ICCProfile(profile, std::move(data)));
- }
- }
- return nullptr;
-}
-
-std::unique_ptr<SkEncodedInfo::ICCProfile> SkEncodedInfo::ICCProfile::MakeSRGB() {
- return std::unique_ptr<ICCProfile>(new ICCProfile(*skcms_sRGB_profile()));
-}
-
-std::unique_ptr<SkEncodedInfo::ICCProfile> SkEncodedInfo::ICCProfile::Make(
- const skcms_ICCProfile& profile) {
- return std::unique_ptr<ICCProfile>(new ICCProfile(profile));
-}
-
-SkEncodedInfo::ICCProfile::ICCProfile(const skcms_ICCProfile& profile, sk_sp<SkData> data)
- : fProfile(profile)
- , fData(std::move(data))
-{}
+// Dummy file to assist in landing https://skia-review.googlesource.com/c/skia/+/136062
diff --git a/src/codec/SkGifCodec.cpp b/src/codec/SkGifCodec.cpp
index 77160cb..3ac5ed3 100644
--- a/src/codec/SkGifCodec.cpp
+++ b/src/codec/SkGifCodec.cpp
@@ -91,9 +91,18 @@
// Use kPalette since Gifs are encoded with a color table.
// FIXME: Gifs can actually be encoded with 4-bits per pixel. Using 8 works, but we could skip
// expanding to 8 bits and take advantage of the SkSwizzler to work from 4.
- auto encodedInfo = SkEncodedInfo::MakeSRGB(reader->screenWidth(), reader->screenHeight(),
- SkEncodedInfo::kPalette_Color, alpha, 8);
- return std::unique_ptr<SkCodec>(new SkGifCodec(std::move(encodedInfo), reader.release()));
+ const auto encodedInfo = SkEncodedInfo::Make(SkEncodedInfo::kPalette_Color, alpha, 8);
+
+ // The choice of unpremul versus premul is arbitrary, since all colors are either fully
+ // opaque or fully transparent (i.e. kBinary), but we stored the transparent colors as all
+ // zeroes, which is arguably premultiplied.
+ const auto alphaType = reader->firstFrameHasAlpha() ? kUnpremul_SkAlphaType
+ : kOpaque_SkAlphaType;
+
+ const auto imageInfo = SkImageInfo::Make(reader->screenWidth(), reader->screenHeight(),
+ kN32_SkColorType, alphaType,
+ SkColorSpace::MakeSRGB());
+ return std::unique_ptr<SkCodec>(new SkGifCodec(encodedInfo, imageInfo, reader.release()));
}
bool SkGifCodec::onRewind() {
@@ -101,8 +110,9 @@
return true;
}
-SkGifCodec::SkGifCodec(SkEncodedInfo&& encodedInfo, SkGifImageReader* reader)
- : INHERITED(std::move(encodedInfo), skcms_PixelFormat_RGBA_8888, nullptr)
+SkGifCodec::SkGifCodec(const SkEncodedInfo& encodedInfo, const SkImageInfo& imageInfo,
+ SkGifImageReader* reader)
+ : INHERITED(encodedInfo, imageInfo, SkColorSpaceXform::kRGBA_8888_ColorFormat, nullptr)
, fReader(reader)
, fTmpBuffer(nullptr)
, fSwizzler(nullptr)
@@ -147,6 +157,7 @@
}
static constexpr SkColorType kXformSrcColorType = kRGBA_8888_SkColorType;
+static constexpr SkAlphaType kXformAlphaType = kUnpremul_SkAlphaType;
void SkGifCodec::initializeColorTable(const SkImageInfo& dstInfo, int frameIndex) {
SkColorType colorTableColorType = dstInfo.colorType();
@@ -162,8 +173,8 @@
fCurrColorTable.reset(new SkColorTable(&color, 1));
} else if (this->colorXform() && !this->xformOnDecode()) {
SkPMColor dstColors[256];
- this->applyColorXform(dstColors, currColorTable->readColors(),
- currColorTable->count());
+ this->applyColorXform(dstColors, currColorTable->readColors(), currColorTable->count(),
+ kXformAlphaType);
fCurrColorTable.reset(new SkColorTable(dstColors, currColorTable->count()));
} else {
fCurrColorTable = std::move(currColorTable);
@@ -391,7 +402,7 @@
fSwizzler->swizzle(fXformBuffer.get(), src);
const int xformWidth = get_scaled_dimension(dstInfo.width(), fSwizzler->sampleX());
- this->applyColorXform(dst, fXformBuffer.get(), xformWidth);
+ this->applyColorXform(dst, fXformBuffer.get(), xformWidth, kXformAlphaType);
} else {
fSwizzler->swizzle(dst, src);
}
diff --git a/src/codec/SkGifCodec.h b/src/codec/SkGifCodec.h
index 4dd1f0b..21dfd2b 100644
--- a/src/codec/SkGifCodec.h
+++ b/src/codec/SkGifCodec.h
@@ -126,7 +126,7 @@
* Called only by NewFromStream
* Takes ownership of the SkGifImageReader
*/
- SkGifCodec(SkEncodedInfo&&, SkGifImageReader*);
+ SkGifCodec(const SkEncodedInfo&, const SkImageInfo&, SkGifImageReader*);
std::unique_ptr<SkGifImageReader> fReader;
std::unique_ptr<uint8_t[]> fTmpBuffer;
diff --git a/src/codec/SkHeifCodec.cpp b/src/codec/SkHeifCodec.cpp
index f5785d6..31057a0 100644
--- a/src/codec/SkHeifCodec.cpp
+++ b/src/codec/SkHeifCodec.cpp
@@ -133,37 +133,40 @@
return nullptr;
}
- std::unique_ptr<SkEncodedInfo::ICCProfile> profile = nullptr;
- if ((frameInfo.mIccSize > 0) && (frameInfo.mIccData != nullptr)) {
- // FIXME: Would it be possible to use MakeWithoutCopy?
- auto icc = SkData::MakeWithCopy(frameInfo.mIccData.get(), frameInfo.mIccSize);
- profile = SkEncodedInfo::ICCProfile::Make(std::move(icc));
- }
- if (!profile || profile->profile()->data_color_space != skcms_Signature_RGB) {
- profile = SkEncodedInfo::ICCProfile::MakeSRGB();
- }
+ SkEncodedInfo info = SkEncodedInfo::Make(
+ SkEncodedInfo::kYUV_Color, SkEncodedInfo::kOpaque_Alpha, 8);
- SkEncodedInfo info = SkEncodedInfo::Make(frameInfo.mWidth, frameInfo.mHeight,
- SkEncodedInfo::kYUV_Color, SkEncodedInfo::kOpaque_Alpha, 8, std::move(profile));
SkEncodedOrigin orientation = get_orientation(frameInfo);
+ sk_sp<SkColorSpace> colorSpace = nullptr;
+ if ((frameInfo.mIccSize > 0) && (frameInfo.mIccData != nullptr)) {
+ colorSpace = SkColorSpace::MakeICC(frameInfo.mIccData.get(),
+ frameInfo.mIccSize);
+ }
+ if (!colorSpace || colorSpace->type() != SkColorSpace::kRGB_Type) {
+ colorSpace = SkColorSpace::MakeSRGB();
+ }
+
*result = kSuccess;
- return std::unique_ptr<SkCodec>(new SkHeifCodec(std::move(info), heifDecoder.release(),
- orientation));
+ return std::unique_ptr<SkCodec>(new SkHeifCodec(frameInfo.mWidth, frameInfo.mHeight,
+ info, heifDecoder.release(), std::move(colorSpace), orientation));
}
-SkHeifCodec::SkHeifCodec(SkEncodedInfo&& info, HeifDecoder* heifDecoder, SkEncodedOrigin origin)
- : INHERITED(std::move(info), skcms_PixelFormat_RGBA_8888, nullptr, origin)
+SkHeifCodec::SkHeifCodec(int width, int height, const SkEncodedInfo& info,
+ HeifDecoder* heifDecoder, sk_sp<SkColorSpace> colorSpace, SkEncodedOrigin origin)
+ : INHERITED(width, height, info, SkColorSpaceXform::kRGBA_8888_ColorFormat,
+ nullptr, std::move(colorSpace), origin)
, fHeifDecoder(heifDecoder)
, fSwizzleSrcRow(nullptr)
, fColorXformSrcRow(nullptr)
{}
-
-bool SkHeifCodec::conversionSupported(const SkImageInfo& dstInfo, SkColorType /*srcColorType*/,
- bool srcIsOpaque, bool needsColorXform) {
- SkASSERT(srcIsOpaque);
-
+/*
+ * Checks if the conversion between the input image and the requested output
+ * image has been implemented
+ * Sets the output color format
+ */
+bool SkHeifCodec::setOutputColorFormat(const SkImageInfo& dstInfo) {
if (kUnknown_SkAlphaType == dstInfo.alphaType()) {
return false;
}
@@ -181,14 +184,14 @@
return fHeifDecoder->setOutputColor(kHeifColorFormat_BGRA_8888);
case kRGB_565_SkColorType:
- if (needsColorXform) {
+ if (this->colorXform()) {
return fHeifDecoder->setOutputColor(kHeifColorFormat_RGBA_8888);
} else {
return fHeifDecoder->setOutputColor(kHeifColorFormat_RGB565);
}
case kRGBA_F16_SkColorType:
- SkASSERT(needsColorXform);
+ SkASSERT(this->colorXform());
return fHeifDecoder->setOutputColor(kHeifColorFormat_RGBA_8888);
default:
@@ -237,7 +240,7 @@
}
if (this->colorXform()) {
- this->applyColorXform(dst, swizzleDst, dstWidth);
+ this->applyColorXform(dst, swizzleDst, dstWidth, kOpaque_SkAlphaType);
dst = SkTAddOffset<void>(dst, rowBytes);
}
@@ -262,6 +265,11 @@
return kUnimplemented;
}
+ // Check if we can decode to the requested destination and set the output color space
+ if (!this->setOutputColorFormat(dstInfo)) {
+ return kInvalidConversion;
+ }
+
if (!fHeifDecoder->decode(&fFrameInfo)) {
return kInvalidInput;
}
@@ -305,13 +313,15 @@
void SkHeifCodec::initializeSwizzler(
const SkImageInfo& dstInfo, const Options& options) {
+ SkEncodedInfo swizzlerInfo = this->getEncodedInfo();
+
SkImageInfo swizzlerDstInfo = dstInfo;
if (this->colorXform()) {
// The color xform will be expecting RGBA 8888 input.
swizzlerDstInfo = swizzlerDstInfo.makeColorType(kRGBA_8888_SkColorType);
}
- fSwizzler.reset(SkSwizzler::CreateSwizzler(this->getEncodedInfo(), nullptr,
+ fSwizzler.reset(SkSwizzler::CreateSwizzler(swizzlerInfo, nullptr,
swizzlerDstInfo, options, nullptr, true));
SkASSERT(fSwizzler);
}
@@ -329,6 +339,11 @@
SkCodec::Result SkHeifCodec::onStartScanlineDecode(
const SkImageInfo& dstInfo, const Options& options) {
+ // Check if we can decode to the requested destination and set the output color space
+ if (!this->setOutputColorFormat(dstInfo)) {
+ return kInvalidConversion;
+ }
+
// TODO: For now, just decode the whole thing even when there is a subset.
// If the heif image has tiles, we could potentially do this much faster,
// but the tile configuration needs to be retrieved from the metadata.
diff --git a/src/codec/SkHeifCodec.h b/src/codec/SkHeifCodec.h
index 0796805..cdae706 100644
--- a/src/codec/SkHeifCodec.h
+++ b/src/codec/SkHeifCodec.h
@@ -9,6 +9,8 @@
#define SkHeifCodec_DEFINED
#include "SkCodec.h"
+#include "SkColorSpace.h"
+#include "SkColorSpaceXform.h"
#include "SkEncodedOrigin.h"
#include "SkImageInfo.h"
#include "SkSwizzler.h"
@@ -41,14 +43,27 @@
return SkEncodedImageFormat::kHEIF;
}
- bool conversionSupported(const SkImageInfo&, SkColorType, bool, bool) override;
+ bool conversionSupported(const SkImageInfo&, SkColorType, bool,
+ const SkColorSpace*) const override {
+ // This class checks for conversion after creating colorXform.
+ return true;
+ }
private:
/*
* Creates an instance of the decoder
* Called only by NewFromStream
*/
- SkHeifCodec(SkEncodedInfo&&, HeifDecoder*, SkEncodedOrigin);
+ SkHeifCodec(int width, int height, const SkEncodedInfo&,
+ HeifDecoder*, sk_sp<SkColorSpace>, SkEncodedOrigin);
+
+ /*
+ * Checks if the conversion between the input image and the requested output
+ * image has been implemented.
+ *
+ * Sets the output color format.
+ */
+ bool setOutputColorFormat(const SkImageInfo& dst);
void initializeSwizzler(const SkImageInfo& dstInfo, const Options& options);
void allocateStorage(const SkImageInfo& dstInfo);
diff --git a/src/codec/SkIcoCodec.cpp b/src/codec/SkIcoCodec.cpp
index d838079..8ff4088 100644
--- a/src/codec/SkIcoCodec.cpp
+++ b/src/codec/SkIcoCodec.cpp
@@ -179,19 +179,29 @@
maxIndex = i;
}
}
-
- auto maxInfo = codecs->operator[](maxIndex)->getEncodedInfo().copy();
+ int width = codecs->operator[](maxIndex)->getInfo().width();
+ int height = codecs->operator[](maxIndex)->getInfo().height();
+ SkEncodedInfo info = codecs->operator[](maxIndex)->getEncodedInfo();
+ SkColorSpace* colorSpace = codecs->operator[](maxIndex)->getInfo().colorSpace();
*result = kSuccess;
// The original stream is no longer needed, because the embedded codecs own their
// own streams.
- return std::unique_ptr<SkCodec>(new SkIcoCodec(std::move(maxInfo), codecs.release()));
+ return std::unique_ptr<SkCodec>(new SkIcoCodec(width, height, info, codecs.release(),
+ sk_ref_sp(colorSpace)));
}
-SkIcoCodec::SkIcoCodec(SkEncodedInfo&& info, SkTArray<std::unique_ptr<SkCodec>, true>* codecs)
- // The source skcms_PixelFormat will not be used. The embedded
+/*
+ * Creates an instance of the decoder
+ * Called only by NewFromStream
+ */
+SkIcoCodec::SkIcoCodec(int width, int height, const SkEncodedInfo& info,
+ SkTArray<std::unique_ptr<SkCodec>, true>* codecs,
+ sk_sp<SkColorSpace> colorSpace)
+ // The source SkColorSpaceXform::ColorFormat will not be used. The embedded
// codec's will be used instead.
- : INHERITED(std::move(info), skcms_PixelFormat(), nullptr)
+ : INHERITED(width, height, info, SkColorSpaceXform::ColorFormat(), nullptr,
+ std::move(colorSpace))
, fEmbeddedCodecs(codecs)
, fCurrCodec(nullptr)
{}
diff --git a/src/codec/SkIcoCodec.h b/src/codec/SkIcoCodec.h
index e733e9f..c43fcf8c 100644
--- a/src/codec/SkIcoCodec.h
+++ b/src/codec/SkIcoCodec.h
@@ -48,7 +48,8 @@
SkScanlineOrder onGetScanlineOrder() const override;
- bool conversionSupported(const SkImageInfo&, SkColorType, bool, bool) override {
+ bool conversionSupported(const SkImageInfo&, SkColorType, bool,
+ const SkColorSpace*) const override {
// This will be checked by the embedded codec.
return true;
}
@@ -86,7 +87,8 @@
* Constructor called by NewFromStream
* @param embeddedCodecs codecs for the embedded images, takes ownership
*/
- SkIcoCodec(SkEncodedInfo&& info, SkTArray<std::unique_ptr<SkCodec>, true>* embeddedCodecs);
+ SkIcoCodec(int width, int height, const SkEncodedInfo& info,
+ SkTArray<std::unique_ptr<SkCodec>, true>* embeddedCodecs, sk_sp<SkColorSpace> colorSpace);
std::unique_ptr<SkTArray<std::unique_ptr<SkCodec>, true>> fEmbeddedCodecs;
diff --git a/src/codec/SkJpegCodec.cpp b/src/codec/SkJpegCodec.cpp
index a0fa009..fd95590 100644
--- a/src/codec/SkJpegCodec.cpp
+++ b/src/codec/SkJpegCodec.cpp
@@ -10,7 +10,6 @@
#include "SkCodec.h"
#include "SkCodecPriv.h"
#include "SkColorData.h"
-#include "SkColorSpace.h"
#include "SkJpegDecoderMgr.h"
#include "SkJpegInfo.h"
#include "SkStream.h"
@@ -132,8 +131,7 @@
* (1) Discover all ICC profile markers and verify that they are numbered properly.
* (2) Copy the data from each marker into a contiguous ICC profile.
*/
-static std::unique_ptr<SkEncodedInfo::ICCProfile> read_color_profile(jpeg_decompress_struct* dinfo)
-{
+static sk_sp<SkColorSpace> read_color_space(jpeg_decompress_struct* dinfo) {
// Note that 256 will be enough storage space since each markerIndex is stored in 8-bits.
jpeg_marker_struct* markerSequence[256];
memset(markerSequence, 0, sizeof(markerSequence));
@@ -193,12 +191,11 @@
dst = SkTAddOffset<void>(dst, bytes);
}
- return SkEncodedInfo::ICCProfile::Make(std::move(iccData));
+ return SkColorSpace::MakeICC(iccData->data(), iccData->size());
}
SkCodec::Result SkJpegCodec::ReadHeader(SkStream* stream, SkCodec** codecOut,
- JpegDecoderMgr** decoderMgrOut,
- std::unique_ptr<SkEncodedInfo::ICCProfile> defaultColorProfile) {
+ JpegDecoderMgr** decoderMgrOut, sk_sp<SkColorSpace> defaultColorSpace) {
// Create a JpegDecoderMgr to own all of the decompress information
std::unique_ptr<JpegDecoderMgr> decoderMgr(new JpegDecoderMgr(stream));
@@ -211,18 +208,17 @@
// Initialize the decompress info and the source manager
decoderMgr->init();
- auto* dinfo = decoderMgr->dinfo();
// Instruct jpeg library to save the markers that we care about. Since
// the orientation and color profile will not change, we can skip this
// step on rewinds.
if (codecOut) {
- jpeg_save_markers(dinfo, kExifMarker, 0xFFFF);
- jpeg_save_markers(dinfo, kICCMarker, 0xFFFF);
+ jpeg_save_markers(decoderMgr->dinfo(), kExifMarker, 0xFFFF);
+ jpeg_save_markers(decoderMgr->dinfo(), kICCMarker, 0xFFFF);
}
// Read the jpeg header
- switch (jpeg_read_header(dinfo, true)) {
+ switch (jpeg_read_header(decoderMgr->dinfo(), true)) {
case JPEG_HEADER_OK:
break;
case JPEG_SUSPENDED:
@@ -238,41 +234,42 @@
return kInvalidInput;
}
- SkEncodedOrigin orientation = get_exif_orientation(dinfo);
- auto profile = read_color_profile(dinfo);
- if (profile) {
- auto type = profile->profile()->data_color_space;
+ // Create image info object and the codec
+ SkEncodedInfo info = SkEncodedInfo::Make(color, SkEncodedInfo::kOpaque_Alpha, 8);
+
+ SkEncodedOrigin orientation = get_exif_orientation(decoderMgr->dinfo());
+ sk_sp<SkColorSpace> colorSpace = read_color_space(decoderMgr->dinfo());
+ if (colorSpace) {
switch (decoderMgr->dinfo()->jpeg_color_space) {
case JCS_CMYK:
case JCS_YCCK:
- if (type != skcms_Signature_CMYK) {
- profile = nullptr;
+ if (colorSpace->type() != SkColorSpace::kCMYK_Type) {
+ colorSpace = nullptr;
}
break;
case JCS_GRAYSCALE:
- if (type != skcms_Signature_Gray &&
- type != skcms_Signature_RGB)
+ if (colorSpace->type() != SkColorSpace::kGray_Type &&
+ colorSpace->type() != SkColorSpace::kRGB_Type)
{
- profile = nullptr;
+ colorSpace = nullptr;
}
break;
default:
- if (type != skcms_Signature_RGB) {
- profile = nullptr;
+ if (colorSpace->type() != SkColorSpace::kRGB_Type) {
+ colorSpace = nullptr;
}
break;
}
}
- if (!profile) {
- profile = std::move(defaultColorProfile);
+ if (!colorSpace) {
+ colorSpace = defaultColorSpace;
}
- SkEncodedInfo info = SkEncodedInfo::Make(dinfo->image_width, dinfo->image_height,
- color, SkEncodedInfo::kOpaque_Alpha, 8,
- std::move(profile));
-
- SkJpegCodec* codec = new SkJpegCodec(std::move(info), std::unique_ptr<SkStream>(stream),
- decoderMgr.release(), orientation);
+ const int width = decoderMgr->dinfo()->image_width;
+ const int height = decoderMgr->dinfo()->image_height;
+ SkJpegCodec* codec = new SkJpegCodec(width, height, info, std::unique_ptr<SkStream>(stream),
+ decoderMgr.release(), std::move(colorSpace),
+ orientation);
*codecOut = codec;
} else {
SkASSERT(nullptr != decoderMgrOut);
@@ -283,15 +280,14 @@
std::unique_ptr<SkCodec> SkJpegCodec::MakeFromStream(std::unique_ptr<SkStream> stream,
Result* result) {
- return SkJpegCodec::MakeFromStream(std::move(stream), result,
- // FIXME: This may not be used. Can we skip creating it?
- SkEncodedInfo::ICCProfile::MakeSRGB());
+ return SkJpegCodec::MakeFromStream(std::move(stream), result, SkColorSpace::MakeSRGB());
}
std::unique_ptr<SkCodec> SkJpegCodec::MakeFromStream(std::unique_ptr<SkStream> stream,
- Result* result, std::unique_ptr<SkEncodedInfo::ICCProfile> defaultColorProfile) {
+ Result* result,
+ sk_sp<SkColorSpace> defaultColorSpace) {
SkCodec* codec = nullptr;
- *result = ReadHeader(stream.get(), &codec, nullptr, std::move(defaultColorProfile));
+ *result = ReadHeader(stream.get(), &codec, nullptr, std::move(defaultColorSpace));
if (kSuccess == *result) {
// Codec has taken ownership of the stream, we do not need to delete it
SkASSERT(codec);
@@ -301,10 +297,11 @@
return nullptr;
}
-SkJpegCodec::SkJpegCodec(SkEncodedInfo&& info, std::unique_ptr<SkStream> stream,
- JpegDecoderMgr* decoderMgr, SkEncodedOrigin origin)
- : INHERITED(std::move(info), skcms_PixelFormat_RGBA_8888, std::move(stream),
- origin)
+SkJpegCodec::SkJpegCodec(int width, int height, const SkEncodedInfo& info,
+ std::unique_ptr<SkStream> stream, JpegDecoderMgr* decoderMgr,
+ sk_sp<SkColorSpace> colorSpace, SkEncodedOrigin origin)
+ : INHERITED(width, height, info, SkColorSpaceXform::kRGBA_8888_ColorFormat, std::move(stream),
+ std::move(colorSpace), origin)
, fDecoderMgr(decoderMgr)
, fReadyState(decoderMgr->dinfo()->global_state)
, fSwizzleSrcRow(nullptr)
@@ -389,10 +386,12 @@
return true;
}
-bool SkJpegCodec::conversionSupported(const SkImageInfo& dstInfo, SkColorType srcCT,
- bool srcIsOpaque, bool needsColorXform) {
- SkASSERT(srcIsOpaque);
-
+/*
+ * Checks if the conversion between the input image and the requested output
+ * image has been implemented
+ * Sets the output color space
+ */
+bool SkJpegCodec::setOutputColorSpace(const SkImageInfo& dstInfo) {
if (kUnknown_SkAlphaType == dstInfo.alphaType()) {
return false;
}
@@ -410,7 +409,7 @@
fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA;
break;
case kBGRA_8888_SkColorType:
- if (needsColorXform) {
+ if (this->colorXform()) {
// Always using RGBA as the input format for color xforms makes the
// implementation a little simpler.
fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA;
@@ -419,7 +418,7 @@
}
break;
case kRGB_565_SkColorType:
- if (needsColorXform) {
+ if (this->colorXform()) {
fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA;
} else {
fDecoderMgr->dinfo()->dither_mode = JDITHER_NONE;
@@ -427,15 +426,14 @@
}
break;
case kGray_8_SkColorType:
- SkASSERT(!needsColorXform);
- if (JCS_GRAYSCALE != encodedColorType) {
+ if (this->colorXform() || JCS_GRAYSCALE != encodedColorType) {
return false;
}
fDecoderMgr->dinfo()->out_color_space = JCS_GRAYSCALE;
break;
case kRGBA_F16_SkColorType:
- SkASSERT(needsColorXform);
+ SkASSERT(this->colorXform());
fDecoderMgr->dinfo()->out_color_space = JCS_EXT_RGBA;
break;
default:
@@ -541,7 +539,7 @@
}
if (this->colorXform()) {
- this->applyColorXform(dst, swizzleDst, dstWidth);
+ this->applyColorXform(dst, swizzleDst, dstWidth, kOpaque_SkAlphaType);
dst = SkTAddOffset<void>(dst, rowBytes);
}
@@ -555,17 +553,16 @@
/*
* This is a bit tricky. We only need the swizzler to do format conversion if the jpeg is
* encoded as CMYK.
- * And even then we still may not need it. If the jpeg has a CMYK color profile and a color
+ * And even then we still may not need it. If the jpeg has a CMYK color space and a color
* xform, the color xform will handle the CMYK->RGB conversion.
*/
static inline bool needs_swizzler_to_convert_from_cmyk(J_COLOR_SPACE jpegColorType,
- const skcms_ICCProfile* srcProfile,
- bool hasColorSpaceXform) {
+ const SkImageInfo& srcInfo, bool hasColorSpaceXform) {
if (JCS_CMYK != jpegColorType) {
return false;
}
- bool hasCMYKColorSpace = srcProfile && srcProfile->data_color_space == skcms_Signature_CMYK;
+ bool hasCMYKColorSpace = SkColorSpace::kCMYK_Type == srcInfo.colorSpace()->type();
return !hasCMYKColorSpace || !hasColorSpaceXform;
}
@@ -590,6 +587,11 @@
return fDecoderMgr->returnFailure("setjmp", kInvalidInput);
}
+ // Check if we can decode to the requested destination and set the output color space
+ if (!this->setOutputColorSpace(dstInfo)) {
+ return fDecoderMgr->returnFailure("setOutputColorSpace", kInvalidConversion);
+ }
+
if (!jpeg_start_decompress(dinfo)) {
return fDecoderMgr->returnFailure("startDecompress", kInvalidInput);
}
@@ -598,8 +600,8 @@
// If it's not, we want to know because it means our strategy is not optimal.
SkASSERT(1 == dinfo->rec_outbuf_height);
- if (needs_swizzler_to_convert_from_cmyk(dinfo->out_color_space,
- this->getEncodedInfo().profile(), this->colorXform())) {
+ if (needs_swizzler_to_convert_from_cmyk(dinfo->out_color_space, this->getInfo(),
+ this->colorXform())) {
this->initializeSwizzler(dstInfo, options, true);
}
@@ -639,16 +641,14 @@
}
}
-static SkEncodedInfo make_info(const SkEncodedInfo& orig, bool needsCMYKToRGB) {
- auto color = needsCMYKToRGB ? SkEncodedInfo::kInvertedCMYK_Color
- : orig.color();
- // The swizzler does not need the width or height
- return SkEncodedInfo::Make(0, 0, color, orig.alpha(), orig.bitsPerComponent());
-}
-
void SkJpegCodec::initializeSwizzler(const SkImageInfo& dstInfo, const Options& options,
bool needsCMYKToRGB) {
- SkEncodedInfo swizzlerInfo = make_info(this->getEncodedInfo(), needsCMYKToRGB);
+ SkEncodedInfo swizzlerInfo = this->getEncodedInfo();
+ if (needsCMYKToRGB) {
+ swizzlerInfo = SkEncodedInfo::Make(SkEncodedInfo::kInvertedCMYK_Color,
+ swizzlerInfo.alpha(),
+ swizzlerInfo.bitsPerComponent());
+ }
Options swizzlerOptions = options;
if (options.fSubset) {
@@ -678,8 +678,7 @@
}
bool needsCMYKToRGB = needs_swizzler_to_convert_from_cmyk(
- fDecoderMgr->dinfo()->out_color_space, this->getEncodedInfo().profile(),
- this->colorXform());
+ fDecoderMgr->dinfo()->out_color_space, this->getInfo(), this->colorXform());
this->initializeSwizzler(this->dstInfo(), this->options(), needsCMYKToRGB);
this->allocateStorage(this->dstInfo());
return fSwizzler.get();
@@ -694,14 +693,18 @@
return kInvalidInput;
}
+ // Check if we can decode to the requested destination and set the output color space
+ if (!this->setOutputColorSpace(dstInfo)) {
+ return fDecoderMgr->returnFailure("setOutputColorSpace", kInvalidConversion);
+ }
+
if (!jpeg_start_decompress(fDecoderMgr->dinfo())) {
SkCodecPrintf("start decompress failed\n");
return kInvalidInput;
}
bool needsCMYKToRGB = needs_swizzler_to_convert_from_cmyk(
- fDecoderMgr->dinfo()->out_color_space, this->getEncodedInfo().profile(),
- this->colorXform());
+ fDecoderMgr->dinfo()->out_color_space, this->getInfo(), this->colorXform());
if (options.fSubset) {
uint32_t startX = options.fSubset->x();
uint32_t width = options.fSubset->width();
diff --git a/src/codec/SkJpegCodec.h b/src/codec/SkJpegCodec.h
index e6ec2ce..7fab209 100644
--- a/src/codec/SkJpegCodec.h
+++ b/src/codec/SkJpegCodec.h
@@ -9,13 +9,14 @@
#define SkJpegCodec_DEFINED
#include "SkCodec.h"
+#include "SkColorSpace.h"
+#include "SkColorSpaceXform.h"
#include "SkImageInfo.h"
#include "SkSwizzler.h"
#include "SkStream.h"
#include "SkTemplates.h"
class JpegDecoderMgr;
-class SkColorSpace;
/*
*
@@ -57,14 +58,19 @@
bool onDimensionsSupported(const SkISize&) override;
- bool conversionSupported(const SkImageInfo&, SkColorType, bool, bool) override;
+ bool conversionSupported(const SkImageInfo&, SkColorType, bool,
+ const SkColorSpace*) const override {
+ // This class checks for conversion after creating colorXform.
+ return true;
+ }
private:
+
/*
- * Allows SkRawCodec to communicate the color profile from the exif data.
+ * Allows SkRawCodec to communicate the color space from the exif data.
*/
static std::unique_ptr<SkCodec> MakeFromStream(std::unique_ptr<SkStream>, Result*,
- std::unique_ptr<SkEncodedInfo::ICCProfile> defaultColorProfile);
+ sk_sp<SkColorSpace> defaultColorSpace);
/*
* Read enough of the stream to initialize the SkJpegCodec.
@@ -84,13 +90,12 @@
* codecOut will take ownership of it in the case where we created a codec.
* Ownership is unchanged when we set decoderMgrOut.
*
- * @param defaultColorProfile
- * If the jpeg does not have an embedded color profile, the image data should
- * be tagged with this color profile.
+ * @param defaultColorSpace
+ * If the jpeg does not have an embedded color space, the image data should
+ * be tagged with this color space.
*/
static Result ReadHeader(SkStream* stream, SkCodec** codecOut,
- JpegDecoderMgr** decoderMgrOut,
- std::unique_ptr<SkEncodedInfo::ICCProfile> defaultColorProfile);
+ JpegDecoderMgr** decoderMgrOut, sk_sp<SkColorSpace> defaultColorSpace);
/*
* Creates an instance of the decoder
@@ -101,8 +106,16 @@
* @param decoderMgr holds decompress struct, src manager, and error manager
* takes ownership
*/
- SkJpegCodec(SkEncodedInfo&& info, std::unique_ptr<SkStream> stream,
- JpegDecoderMgr* decoderMgr, SkEncodedOrigin origin);
+ SkJpegCodec(int width, int height, const SkEncodedInfo& info, std::unique_ptr<SkStream> stream,
+ JpegDecoderMgr* decoderMgr, sk_sp<SkColorSpace> colorSpace, SkEncodedOrigin origin);
+
+ /*
+ * Checks if the conversion between the input image and the requested output
+ * image has been implemented.
+ *
+ * Sets the output color space.
+ */
+ bool setOutputColorSpace(const SkImageInfo& dst);
void initializeSwizzler(const SkImageInfo& dstInfo, const Options& options,
bool needsCMYKToRGB);
diff --git a/src/codec/SkPngCodec.cpp b/src/codec/SkPngCodec.cpp
index 21046d4..e9972cc 100644
--- a/src/codec/SkPngCodec.cpp
+++ b/src/codec/SkPngCodec.cpp
@@ -9,6 +9,7 @@
#include "SkCodecPriv.h"
#include "SkColorData.h"
#include "SkColorSpace.h"
+#include "SkColorSpacePriv.h"
#include "SkColorTable.h"
#include "SkMacros.h"
#include "SkMath.h"
@@ -247,10 +248,6 @@
static constexpr SkColorType kXformSrcColorType = kRGBA_8888_SkColorType;
-static inline bool needs_premul(SkAlphaType dstAT, SkEncodedInfo::Alpha encodedAlpha) {
- return kPremul_SkAlphaType == dstAT && SkEncodedInfo::kUnpremul_Alpha == encodedAlpha;
-}
-
// Note: SkColorTable claims to store SkPMColors, which is not necessarily the case here.
bool SkPngCodec::createColorTable(const SkImageInfo& dstInfo) {
@@ -268,7 +265,10 @@
png_bytep alphas;
int numColorsWithAlpha = 0;
if (png_get_tRNS(fPng_ptr, fInfo_ptr, &alphas, &numColorsWithAlpha, nullptr)) {
- bool premultiply = needs_premul(dstInfo.alphaType(), this->getEncodedInfo().alpha());
+ // If we are performing a color xform, it will handle the premultiply. Otherwise,
+ // we'll do it here.
+ bool premultiply = !this->colorXform() && needs_premul(dstInfo.alphaType(),
+ this->getEncodedInfo().alpha());
// 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.
@@ -342,11 +342,13 @@
#endif // LIBPNG >= 1.6
-// If there is no color profile information, it will use sRGB.
-std::unique_ptr<SkEncodedInfo::ICCProfile> read_color_profile(png_structp png_ptr,
- png_infop info_ptr) {
+// Returns a colorSpace object that represents any color space information in
+// the encoded data. If the encoded data contains an invalid/unsupported color space,
+// this will return NULL. If there is no color space information, it will guess sRGB
+sk_sp<SkColorSpace> read_color_space(png_structp png_ptr, png_infop info_ptr) {
#if (PNG_LIBPNG_VER_MAJOR > 1) || (PNG_LIBPNG_VER_MAJOR == 1 && PNG_LIBPNG_VER_MINOR >= 6)
+
// First check for an ICC profile
png_bytep profile;
png_uint_32 length;
@@ -360,70 +362,74 @@
int compression;
if (PNG_INFO_iCCP == png_get_iCCP(png_ptr, info_ptr, &name, &compression, &profile,
&length)) {
- auto data = SkData::MakeWithCopy(profile, length);
- return SkEncodedInfo::ICCProfile::Make(std::move(data));
+ return SkColorSpace::MakeICC(profile, length);
}
// Second, check for sRGB.
- // Note that Blink does this first. This code checks ICC first, with the thinking that
- // an image has both truly wants the potentially more specific ICC chunk, with sRGB as a
- // backup in case the decoder does not support full color management.
if (png_get_valid(png_ptr, info_ptr, PNG_INFO_sRGB)) {
+
// sRGB chunks also store a rendering intent: Absolute, Relative,
// Perceptual, and Saturation.
// FIXME (msarett): Extract this information from the sRGB chunk once
// we are able to handle this information in
// SkColorSpace.
- return SkEncodedInfo::ICCProfile::MakeSRGB();
+ return SkColorSpace::MakeSRGB();
}
- // Default to SRGB gamut.
- skcms_Matrix3x3 toXYZD50 = skcms_sRGB_profile()->toXYZD50;
// Next, check for chromaticities.
png_fixed_point chrm[8];
png_fixed_point gamma;
if (png_get_cHRM_fixed(png_ptr, info_ptr, &chrm[0], &chrm[1], &chrm[2], &chrm[3], &chrm[4],
&chrm[5], &chrm[6], &chrm[7]))
{
- float rx = png_fixed_point_to_float(chrm[2]);
- float ry = png_fixed_point_to_float(chrm[3]);
- float gx = png_fixed_point_to_float(chrm[4]);
- float gy = png_fixed_point_to_float(chrm[5]);
- float bx = png_fixed_point_to_float(chrm[6]);
- float by = png_fixed_point_to_float(chrm[7]);
- float wx = png_fixed_point_to_float(chrm[0]);
- float wy = png_fixed_point_to_float(chrm[1]);
+ SkColorSpacePrimaries primaries;
+ primaries.fRX = png_fixed_point_to_float(chrm[2]);
+ primaries.fRY = png_fixed_point_to_float(chrm[3]);
+ primaries.fGX = png_fixed_point_to_float(chrm[4]);
+ primaries.fGY = png_fixed_point_to_float(chrm[5]);
+ primaries.fBX = png_fixed_point_to_float(chrm[6]);
+ primaries.fBY = png_fixed_point_to_float(chrm[7]);
+ primaries.fWX = png_fixed_point_to_float(chrm[0]);
+ primaries.fWY = png_fixed_point_to_float(chrm[1]);
- skcms_Matrix3x3 tmp;
- if (skcms_PrimariesToXYZD50(rx, ry, gx, gy, bx, by, wx, wy, &tmp)) {
- toXYZD50 = tmp;
- } else {
- // Note that Blink simply returns nullptr in this case. We'll fall
- // back to srgb.
+ SkMatrix44 toXYZD50(SkMatrix44::kUninitialized_Constructor);
+ if (!primaries.toXYZD50(&toXYZD50)) {
+ toXYZD50.set3x3RowMajorf(gSRGB_toXYZD50);
}
- }
- skcms_TransferFunction fn;
- if (PNG_INFO_gAMA == png_get_gAMA_fixed(png_ptr, info_ptr, &gamma)) {
- fn.a = 1.0f;
- fn.b = fn.c = fn.d = fn.e = fn.f = 0.0f;
- fn.g = png_inverted_fixed_point_to_float(gamma);
- } else {
+ if (PNG_INFO_gAMA == png_get_gAMA_fixed(png_ptr, info_ptr, &gamma)) {
+ SkColorSpaceTransferFn fn;
+ fn.fA = 1.0f;
+ fn.fB = fn.fC = fn.fD = fn.fE = fn.fF = 0.0f;
+ fn.fG = png_inverted_fixed_point_to_float(gamma);
+
+ return SkColorSpace::MakeRGB(fn, toXYZD50);
+ }
+
// Default to sRGB gamma if the image has color space information,
// but does not specify gamma.
- // Note that Blink would again return nullptr in this case.
- fn = *skcms_sRGB_TransferFunction();
+ return SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma, toXYZD50);
}
- skcms_ICCProfile skcmsProfile;
- skcms_Init(&skcmsProfile);
- skcms_SetTransferFunction(&skcmsProfile, &fn);
- skcms_SetXYZD50(&skcmsProfile, &toXYZD50);
+ // Last, check for gamma.
+ if (PNG_INFO_gAMA == png_get_gAMA_fixed(png_ptr, info_ptr, &gamma)) {
+ SkColorSpaceTransferFn fn;
+ fn.fA = 1.0f;
+ fn.fB = fn.fC = fn.fD = fn.fE = fn.fF = 0.0f;
+ fn.fG = png_inverted_fixed_point_to_float(gamma);
- return SkEncodedInfo::ICCProfile::Make(skcmsProfile);
-#else // LIBPNG >= 1.6
- return SkEncodedInfo::ICCProfile::MakeSRGB();
+ // Since there is no cHRM, we will guess sRGB gamut.
+ SkMatrix44 toXYZD50(SkMatrix44::kUninitialized_Constructor);
+ toXYZD50.set3x3RowMajorf(gSRGB_toXYZD50);
+
+ return SkColorSpace::MakeRGB(fn, toXYZD50);
+ }
+
#endif // LIBPNG >= 1.6
+
+ // Report that there is no color space information in the PNG.
+ // Guess sRGB in this case.
+ return SkColorSpace::MakeSRGB();
}
void SkPngCodec::allocateStorage(const SkImageInfo& dstInfo) {
@@ -448,17 +454,17 @@
}
}
-static skcms_PixelFormat png_select_xform_format(const SkEncodedInfo& info) {
+static SkColorSpaceXform::ColorFormat png_select_xform_format(const SkEncodedInfo& info) {
// We use kRGB and kRGBA formats because color PNGs are always RGB or RGBA.
if (16 == info.bitsPerComponent()) {
if (SkEncodedInfo::kRGBA_Color == info.color()) {
- return skcms_PixelFormat_RGBA_16161616;
+ return SkColorSpaceXform::kRGBA_U16_BE_ColorFormat;
} else if (SkEncodedInfo::kRGB_Color == info.color()) {
- return skcms_PixelFormat_RGB_161616;
+ return SkColorSpaceXform::kRGB_U16_BE_ColorFormat;
}
}
- return skcms_PixelFormat_RGBA_8888;
+ return SkColorSpaceXform::kRGBA_8888_ColorFormat;
}
void SkPngCodec::applyXformRow(void* dst, const void* src) {
@@ -478,9 +484,10 @@
class SkPngNormalDecoder : public SkPngCodec {
public:
- SkPngNormalDecoder(SkEncodedInfo&& info, std::unique_ptr<SkStream> stream,
- SkPngChunkReader* reader, png_structp png_ptr, png_infop info_ptr, int bitDepth)
- : INHERITED(std::move(info), std::move(stream), reader, png_ptr, info_ptr, bitDepth)
+ SkPngNormalDecoder(const SkEncodedInfo& info, const SkImageInfo& imageInfo,
+ std::unique_ptr<SkStream> stream, SkPngChunkReader* reader,
+ png_structp png_ptr, png_infop info_ptr, int bitDepth)
+ : INHERITED(info, imageInfo, std::move(stream), reader, png_ptr, info_ptr, bitDepth)
, fRowsWrittenToOutput(0)
, fDst(nullptr)
, fRowBytes(0)
@@ -600,10 +607,10 @@
class SkPngInterlacedDecoder : public SkPngCodec {
public:
- SkPngInterlacedDecoder(SkEncodedInfo&& info, std::unique_ptr<SkStream> stream,
- SkPngChunkReader* reader, png_structp png_ptr,
+ SkPngInterlacedDecoder(const SkEncodedInfo& info, const SkImageInfo& imageInfo,
+ std::unique_ptr<SkStream> stream, SkPngChunkReader* reader, png_structp png_ptr,
png_infop info_ptr, int bitDepth, int numberPasses)
- : INHERITED(std::move(info), std::move(stream), reader, png_ptr, info_ptr, bitDepth)
+ : INHERITED(info, imageInfo, std::move(stream), reader, png_ptr, info_ptr, bitDepth)
, fNumberPasses(numberPasses)
, fFirstRow(0)
, fLastRow(0)
@@ -911,33 +918,36 @@
if (fOutCodec) {
SkASSERT(nullptr == *fOutCodec);
- auto profile = read_color_profile(fPng_ptr, fInfo_ptr);
- if (profile) {
- switch (profile->profile()->data_color_space) {
- case skcms_Signature_CMYK:
- profile = nullptr;
+ sk_sp<SkColorSpace> colorSpace = read_color_space(fPng_ptr, fInfo_ptr);
+ if (colorSpace) {
+ switch (colorSpace->type()) {
+ case SkColorSpace::kCMYK_Type:
+ colorSpace = nullptr;
break;
- case skcms_Signature_Gray:
+ case SkColorSpace::kGray_Type:
if (SkEncodedInfo::kGray_Color != color &&
SkEncodedInfo::kGrayAlpha_Color != color)
{
- profile = nullptr;
+ colorSpace = nullptr;
}
break;
- default:
+ case SkColorSpace::kRGB_Type:
break;
}
}
- if (!profile) {
+ if (!colorSpace) {
// Treat unsupported/invalid color spaces as sRGB.
- profile = SkEncodedInfo::ICCProfile::MakeSRGB();
+ colorSpace = SkColorSpace::MakeSRGB();
}
+ SkEncodedInfo encodedInfo = SkEncodedInfo::Make(color, alpha, bitDepth);
+ SkImageInfo imageInfo = encodedInfo.makeImageInfo(origWidth, origHeight, colorSpace);
+
if (encodedColorType == PNG_COLOR_TYPE_GRAY_ALPHA) {
png_color_8p sigBits;
if (png_get_sBIT(fPng_ptr, fInfo_ptr, &sigBits)) {
if (8 == sigBits->alpha && kGraySigBit_GrayAlphaIsJustAlpha == sigBits->gray) {
- color = SkEncodedInfo::kXAlpha_Color;
+ imageInfo = imageInfo.makeColorType(kAlpha_8_SkColorType);
}
}
} else if (SkEncodedInfo::kOpaque_Alpha == alpha) {
@@ -945,18 +955,16 @@
if (png_get_sBIT(fPng_ptr, fInfo_ptr, &sigBits)) {
if (5 == sigBits->red && 6 == sigBits->green && 5 == sigBits->blue) {
// Recommend a decode to 565 if the sBIT indicates 565.
- color = SkEncodedInfo::k565_Color;
+ imageInfo = imageInfo.makeColorType(kRGB_565_SkColorType);
}
}
}
- SkEncodedInfo encodedInfo = SkEncodedInfo::Make(origWidth, origHeight, color, alpha,
- bitDepth, std::move(profile));
if (1 == numberPasses) {
- *fOutCodec = new SkPngNormalDecoder(std::move(encodedInfo),
+ *fOutCodec = new SkPngNormalDecoder(encodedInfo, imageInfo,
std::unique_ptr<SkStream>(fStream), fChunkReader, fPng_ptr, fInfo_ptr, bitDepth);
} else {
- *fOutCodec = new SkPngInterlacedDecoder(std::move(encodedInfo),
+ *fOutCodec = new SkPngInterlacedDecoder(encodedInfo, imageInfo,
std::unique_ptr<SkStream>(fStream), fChunkReader, fPng_ptr, fInfo_ptr, bitDepth,
numberPasses);
}
@@ -968,9 +976,10 @@
this->releasePngPtrs();
}
-SkPngCodec::SkPngCodec(SkEncodedInfo&& encodedInfo, std::unique_ptr<SkStream> stream,
- SkPngChunkReader* chunkReader, void* png_ptr, void* info_ptr, int bitDepth)
- : INHERITED(std::move(encodedInfo), png_select_xform_format(encodedInfo), std::move(stream))
+SkPngCodec::SkPngCodec(const SkEncodedInfo& encodedInfo, const SkImageInfo& imageInfo,
+ std::unique_ptr<SkStream> stream, SkPngChunkReader* chunkReader,
+ void* png_ptr, void* info_ptr, int bitDepth)
+ : INHERITED(encodedInfo, imageInfo, png_select_xform_format(encodedInfo), std::move(stream))
, fPngChunkReader(SkSafeRef(chunkReader))
, fPng_ptr(png_ptr)
, fInfo_ptr(info_ptr)
diff --git a/src/codec/SkPngCodec.h b/src/codec/SkPngCodec.h
index bf068ea..075181c 100644
--- a/src/codec/SkPngCodec.h
+++ b/src/codec/SkPngCodec.h
@@ -8,6 +8,7 @@
#define SkPngCodec_DEFINED
#include "SkCodec.h"
+#include "SkColorSpaceXform.h"
#include "SkColorTable.h"
#include "SkPngChunkReader.h"
#include "SkEncodedImageFormat.h"
@@ -44,8 +45,8 @@
void* fPtr;
};
- SkPngCodec(SkEncodedInfo&&, std::unique_ptr<SkStream>, SkPngChunkReader*,
- void* png_ptr, void* info_ptr, int bitDepth);
+ SkPngCodec(const SkEncodedInfo&, const SkImageInfo&, std::unique_ptr<SkStream>,
+ SkPngChunkReader*, void* png_ptr, void* info_ptr, int bitDepth);
Result onGetPixels(const SkImageInfo&, void*, size_t, const Options&, int*)
override;
diff --git a/src/codec/SkRawCodec.cpp b/src/codec/SkRawCodec.cpp
index 30a3d7b..9eea78c 100644
--- a/src/codec/SkRawCodec.cpp
+++ b/src/codec/SkRawCodec.cpp
@@ -504,6 +504,10 @@
}
}
+ const SkEncodedInfo& getEncodedInfo() const {
+ return fEncodedInfo;
+ }
+
int width() const {
return fWidth;
}
@@ -598,6 +602,8 @@
SkDngImage(SkRawStream* stream)
: fStream(stream)
+ , fEncodedInfo(SkEncodedInfo::Make(SkEncodedInfo::kRGB_Color,
+ SkEncodedInfo::kOpaque_Alpha, 8))
{}
dng_memory_allocator fAllocator;
@@ -609,21 +615,11 @@
int fWidth;
int fHeight;
+ SkEncodedInfo fEncodedInfo;
bool fIsScalable;
bool fIsXtransImage;
};
-static constexpr skcms_Matrix3x3 gAdobe_RGB_to_XYZD50 = {{
- // ICC fixed-point (16.16) repesentation of:
- // 0.60974, 0.20528, 0.14919,
- // 0.31111, 0.62567, 0.06322,
- // 0.01947, 0.06087, 0.74457,
- { SkFixedToFloat(0x9c18), SkFixedToFloat(0x348d), SkFixedToFloat(0x2631) }, // Rx, Gx, Bx
- { SkFixedToFloat(0x4fa5), SkFixedToFloat(0xa02c), SkFixedToFloat(0x102f) }, // Ry, Gy, By
- { SkFixedToFloat(0x04fc), SkFixedToFloat(0x0f95), SkFixedToFloat(0xbe9c) }, // Rz, Gz, Bz
-}};
-
-
/*
* Tries to handle the image with PIEX. If PIEX returns kOk and finds the preview image, create a
* SkJpegCodec. If PIEX returns kFail, then the file is invalid, return nullptr. In other cases,
@@ -648,21 +644,15 @@
return nullptr;
}
- std::unique_ptr<SkEncodedInfo::ICCProfile> profile;
+ sk_sp<SkColorSpace> colorSpace;
switch (imageData.color_space) {
case ::piex::PreviewImageData::kSrgb:
- profile = SkEncodedInfo::ICCProfile::MakeSRGB();
+ colorSpace = SkColorSpace::MakeSRGB();
break;
- case ::piex::PreviewImageData::kAdobeRgb: {
- constexpr skcms_TransferFunction twoDotTwo =
- { 2.2f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
- skcms_ICCProfile skcmsProfile;
- skcms_Init(&skcmsProfile);
- skcms_SetTransferFunction(&skcmsProfile, &twoDotTwo);
- skcms_SetXYZD50(&skcmsProfile, &gAdobe_RGB_to_XYZD50);
- profile = SkEncodedInfo::ICCProfile::Make(skcmsProfile);
+ case ::piex::PreviewImageData::kAdobeRgb:
+ colorSpace = SkColorSpace::MakeRGB(g2Dot2_TransferFn,
+ SkColorSpace::kAdobeRGB_Gamut);
break;
- }
}
// Theoretically PIEX can return JPEG compressed image or uncompressed RGB image. We only
@@ -680,7 +670,7 @@
return nullptr;
}
return SkJpegCodec::MakeFromStream(std::move(memoryStream), result,
- std::move(profile));
+ std::move(colorSpace));
}
}
@@ -756,7 +746,7 @@
if (this->colorXform()) {
swizzler->swizzle(xformBuffer.get(), &srcRow[0]);
- this->applyColorXform(dstRow, xformBuffer.get(), dstInfo.width());
+ this->applyColorXform(dstRow, xformBuffer.get(), dstInfo.width(), kOpaque_SkAlphaType);
} else {
swizzler->swizzle(dstRow, &srcRow[0]);
}
@@ -806,8 +796,7 @@
SkRawCodec::~SkRawCodec() {}
SkRawCodec::SkRawCodec(SkDngImage* dngImage)
- : INHERITED(SkEncodedInfo::MakeSRGB(dngImage->width(), dngImage->height(),
- SkEncodedInfo::kRGB_Color,
- SkEncodedInfo::kOpaque_Alpha, 8),
- skcms_PixelFormat_RGBA_8888, nullptr)
+ : INHERITED(dngImage->width(), dngImage->height(), dngImage->getEncodedInfo(),
+ SkColorSpaceXform::kRGBA_8888_ColorFormat, nullptr,
+ SkColorSpace::MakeSRGB())
, fDngImage(dngImage) {}
diff --git a/src/codec/SkSwizzler.cpp b/src/codec/SkSwizzler.cpp
index cca8c41..4b350c4 100644
--- a/src/codec/SkSwizzler.cpp
+++ b/src/codec/SkSwizzler.cpp
@@ -890,7 +890,6 @@
return nullptr;
}
break;
- case SkEncodedInfo::kXAlpha_Color:
case SkEncodedInfo::kGrayAlpha_Color:
switch (dstInfo.colorType()) {
case kRGBA_8888_SkColorType:
@@ -964,10 +963,6 @@
return nullptr;
}
break;
- case SkEncodedInfo::k565_Color:
- // Treat 565 exactly like RGB (since it's still encoded as 8 bits per component).
- // We just mark as 565 when we have a hint that there are only 5/6/5 "significant"
- // bits in each channel.
case SkEncodedInfo::kRGB_Color:
switch (dstInfo.colorType()) {
case kRGBA_8888_SkColorType:
diff --git a/src/codec/SkWbmpCodec.cpp b/src/codec/SkWbmpCodec.cpp
index cc1462e..8d4beb1 100644
--- a/src/codec/SkWbmpCodec.cpp
+++ b/src/codec/SkWbmpCodec.cpp
@@ -97,10 +97,11 @@
return this->stream()->read(row, fSrcRowBytes) == fSrcRowBytes;
}
-SkWbmpCodec::SkWbmpCodec(SkEncodedInfo&& info, std::unique_ptr<SkStream> stream)
+SkWbmpCodec::SkWbmpCodec(int width, int height, const SkEncodedInfo& info,
+ std::unique_ptr<SkStream> stream)
// Wbmp does not need a colorXform, so choose an arbitrary srcFormat.
- : INHERITED(std::move(info), skcms_PixelFormat(),
- std::move(stream))
+ : INHERITED(width, height, info, SkColorSpaceXform::ColorFormat(),
+ std::move(stream), SkColorSpace::MakeSRGB())
, fSrcRowBytes(get_src_row_bytes(this->getInfo().width()))
, fSwizzler(nullptr)
{}
@@ -110,7 +111,7 @@
}
bool SkWbmpCodec::conversionSupported(const SkImageInfo& dst, SkColorType /*srcColor*/,
- bool srcIsOpaque, bool /*needsXform*/) {
+ bool srcIsOpaque, const SkColorSpace* srcCS) const {
return valid_color_type(dst) && valid_alpha(dst.alphaType(), srcIsOpaque);
}
@@ -158,9 +159,10 @@
return nullptr;
}
*result = kSuccess;
- auto info = SkEncodedInfo::Make(size.width(), size.height(), SkEncodedInfo::kGray_Color,
- SkEncodedInfo::kOpaque_Alpha, 1);
- return std::unique_ptr<SkCodec>(new SkWbmpCodec(std::move(info), std::move(stream)));
+ SkEncodedInfo info = SkEncodedInfo::Make(SkEncodedInfo::kGray_Color,
+ SkEncodedInfo::kOpaque_Alpha, 1);
+ return std::unique_ptr<SkCodec>(new SkWbmpCodec(size.width(), size.height(), info,
+ std::move(stream)));
}
int SkWbmpCodec::onGetScanlines(void* dst, int count, size_t dstRowBytes) {
diff --git a/src/codec/SkWbmpCodec.h b/src/codec/SkWbmpCodec.h
index b9df0b9..192189d 100644
--- a/src/codec/SkWbmpCodec.h
+++ b/src/codec/SkWbmpCodec.h
@@ -29,7 +29,7 @@
const Options&, int*) override;
bool onRewind() override;
bool conversionSupported(const SkImageInfo& dst, SkColorType srcColor,
- bool srcIsOpaque, bool needsXform) override;
+ bool srcIsOpaque, const SkColorSpace* srcCS) const override;
// No need to Xform; all pixels are either black or white.
bool usesColorXform() const override { return false; }
private:
@@ -48,7 +48,7 @@
*/
bool readRow(uint8_t* row);
- SkWbmpCodec(SkEncodedInfo&&, std::unique_ptr<SkStream>);
+ SkWbmpCodec(int width, int height, const SkEncodedInfo&, std::unique_ptr<SkStream>);
const size_t fSrcRowBytes;
diff --git a/src/codec/SkWebpCodec.cpp b/src/codec/SkWebpCodec.cpp
index ac1c9be..a9c0c32 100644
--- a/src/codec/SkWebpCodec.cpp
+++ b/src/codec/SkWebpCodec.cpp
@@ -13,6 +13,7 @@
#include "SkCodecAnimation.h"
#include "SkCodecAnimationPriv.h"
#include "SkCodecPriv.h"
+#include "SkColorSpaceXform.h"
#include "SkMakeUnique.h"
#include "SkRasterPipeline.h"
#include "SkSampler.h"
@@ -88,17 +89,15 @@
}
}
- std::unique_ptr<SkEncodedInfo::ICCProfile> profile = nullptr;
+ sk_sp<SkColorSpace> colorSpace = nullptr;
{
WebPChunkIterator chunkIterator;
SkAutoTCallVProc<WebPChunkIterator, WebPDemuxReleaseChunkIterator> autoCI(&chunkIterator);
if (WebPDemuxGetChunk(demux, "ICCP", 1, &chunkIterator)) {
- // FIXME: I think this could be MakeWithoutCopy
- auto chunk = SkData::MakeWithCopy(chunkIterator.chunk.bytes, chunkIterator.chunk.size);
- profile = SkEncodedInfo::ICCProfile::Make(std::move(chunk));
+ colorSpace = SkColorSpace::MakeICC(chunkIterator.chunk.bytes, chunkIterator.chunk.size);
}
- if (!profile || profile->profile()->data_color_space != skcms_Signature_RGB) {
- profile = SkEncodedInfo::ICCProfile::MakeSRGB();
+ if (!colorSpace || colorSpace->type() != SkColorSpace::kRGB_Type) {
+ colorSpace = SkColorSpace::MakeSRGB();
}
}
@@ -172,9 +171,10 @@
*result = kSuccess;
- SkEncodedInfo info = SkEncodedInfo::Make(width, height, color, alpha, 8, std::move(profile));
- return std::unique_ptr<SkCodec>(new SkWebpCodec(std::move(info), std::move(stream),
- demux.release(), std::move(data), origin));
+ SkEncodedInfo info = SkEncodedInfo::Make(color, alpha, 8);
+ return std::unique_ptr<SkCodec>(new SkWebpCodec(width, height, info, std::move(colorSpace),
+ std::move(stream), demux.release(), std::move(data),
+ origin));
}
SkISize SkWebpCodec::onGetScaledDimensions(float desiredScale) const {
@@ -543,8 +543,35 @@
webpDst.installPixels(webpInfo, dst, rowBytes);
}
- config.output.colorspace = webp_decode_mode(webpInfo.colorType(),
- frame.has_alpha && dstInfo.alphaType() == kPremul_SkAlphaType && !this->colorXform());
+ // Choose the step when we will perform premultiplication.
+ enum {
+ kNoPremul,
+ kBlendLine,
+ kColorXform,
+ kLibwebp,
+ };
+ auto choose_premul_step = [&]() {
+ if (!frame.has_alpha) {
+ // None necessary.
+ return kNoPremul;
+ }
+ if (blendWithPrevFrame) {
+ // Premultiply in blend_line, in a linear space.
+ return kBlendLine;
+ }
+ if (dstInfo.alphaType() != kPremul_SkAlphaType) {
+ // No blending is necessary, so we only need to premultiply if the
+ // client requested it.
+ return kNoPremul;
+ }
+ if (this->colorXform()) {
+ // Premultiply in the colorXform, in a linear space.
+ return kColorXform;
+ }
+ return kLibwebp;
+ };
+ const auto premulStep = choose_premul_step();
+ config.output.colorspace = webp_decode_mode(webpInfo.colorType(), premulStep == kLibwebp);
config.output.is_external_memory = 1;
config.output.u.RGBA.rgba = reinterpret_cast<uint8_t*>(webpDst.getAddr(dstX, dstY));
@@ -593,8 +620,11 @@
xformDst = dst;
}
+ const auto xformAlphaType = (premulStep == kColorXform) ? kPremul_SkAlphaType :
+ ( frame.has_alpha) ? kUnpremul_SkAlphaType :
+ kOpaque_SkAlphaType ;
for (int y = 0; y < rowsDecoded; y++) {
- this->applyColorXform(xformDst, xformSrc, scaledWidth);
+ this->applyColorXform(xformDst, xformSrc, scaledWidth, xformAlphaType);
if (blendWithPrevFrame) {
blend_line(dstCT, dst, dstCT, xformDst,
dstInfo.alphaType(), frame.has_alpha, scaledWidth);
@@ -618,14 +648,14 @@
return result;
}
-SkWebpCodec::SkWebpCodec(SkEncodedInfo&& info, std::unique_ptr<SkStream> stream,
+SkWebpCodec::SkWebpCodec(int width, int height, const SkEncodedInfo& info,
+ sk_sp<SkColorSpace> colorSpace, std::unique_ptr<SkStream> stream,
WebPDemuxer* demux, sk_sp<SkData> data, SkEncodedOrigin origin)
- : INHERITED(std::move(info), skcms_PixelFormat_BGRA_8888, std::move(stream),
- origin)
+ : INHERITED(width, height, info, SkColorSpaceXform::kBGRA_8888_ColorFormat, std::move(stream),
+ std::move(colorSpace), origin)
, fDemux(demux)
, fData(std::move(data))
, fFailed(false)
{
- const auto& eInfo = this->getEncodedInfo();
- fFrameHolder.setScreenSize(eInfo.width(), eInfo.height());
+ fFrameHolder.setScreenSize(width, height);
}
diff --git a/src/codec/SkWebpCodec.h b/src/codec/SkWebpCodec.h
index 4de5f38..fdd5422 100644
--- a/src/codec/SkWebpCodec.h
+++ b/src/codec/SkWebpCodec.h
@@ -9,6 +9,7 @@
#define SkWebpCodec_DEFINED
#include "SkCodec.h"
+#include "SkColorSpace.h"
#include "SkEncodedImageFormat.h"
#include "SkFrameHolder.h"
#include "SkImageInfo.h"
@@ -46,8 +47,8 @@
}
private:
- SkWebpCodec(SkEncodedInfo&&, std::unique_ptr<SkStream>, WebPDemuxer*, sk_sp<SkData>,
- SkEncodedOrigin);
+ SkWebpCodec(int width, int height, const SkEncodedInfo&, sk_sp<SkColorSpace>,
+ std::unique_ptr<SkStream>, WebPDemuxer*, sk_sp<SkData>, SkEncodedOrigin);
SkAutoTCallVProc<WebPDemuxer, WebPDemuxDelete> fDemux;
diff --git a/tests/CodecTest.cpp b/tests/CodecTest.cpp
index 7f50a41..9bbadc6 100644
--- a/tests/CodecTest.cpp
+++ b/tests/CodecTest.cpp
@@ -1608,25 +1608,6 @@
}
}
-DEF_TEST(Codec_A8, r) {
- if (GetResourcePath().isEmpty()) {
- return;
- }
-
- const char* file = "images/mandrill_cmyk.jpg";
- auto data = GetResourceAsData(file);
- if (!data) {
- ERRORF(r, "missing %s", file);
- return;
- }
-
- auto codec = SkCodec::MakeFromData(std::move(data));
- auto info = codec->getInfo().makeColorType(kAlpha_8_SkColorType);
- SkBitmap bm;
- bm.allocPixels(info);
- REPORTER_ASSERT(r, codec->getPixels(bm.pixmap()) == SkCodec::kInvalidConversion);
-}
-
DEF_TEST(Codec_crbug807324, r) {
if (GetResourcePath().isEmpty()) {
return;
diff --git a/tests/EncodedInfoTest.cpp b/tests/EncodedInfoTest.cpp
deleted file mode 100644
index 3149df8..0000000
--- a/tests/EncodedInfoTest.cpp
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright 2018 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "Resources.h"
-#include "Test.h"
-#include "sk_tool_utils.h"
-
-#include "SkBitmap.h"
-#include "SkCodec.h"
-#include "SkData.h"
-#include "SkEncodedImageFormat.h"
-#include "SkImageInfo.h"
-#include "SkImageEncoder.h"
-
-DEF_TEST(AlphaEncodedInfo, r) {
- auto codec = SkCodec::MakeFromStream(GetResourceAsStream("images/grayscale.jpg"));
- REPORTER_ASSERT(r, codec->getInfo().colorType() == kGray_8_SkColorType);
-
- SkBitmap bm;
- bm.allocPixels(codec->getInfo().makeColorType(kAlpha_8_SkColorType).makeColorSpace(nullptr));
- auto result = codec->getPixels(codec->getInfo(), bm.getPixels(), bm.rowBytes());
- REPORTER_ASSERT(r, result == SkCodec::kSuccess);
-
- auto data = SkEncodeBitmap(bm, SkEncodedImageFormat::kPNG, 100);
- REPORTER_ASSERT(r, data);
-
- codec = SkCodec::MakeFromData(std::move(data));
- REPORTER_ASSERT(r, codec);
- // TODO: Make SkEncodedInfo public and compare to its version of kAlpha_8.
- REPORTER_ASSERT(r, codec->getInfo().colorType() == kAlpha_8_SkColorType);
-
- SkBitmap bm2;
- bm2.allocPixels(codec->getInfo().makeColorSpace(nullptr));
- result = codec->getPixels(bm2.pixmap());
- REPORTER_ASSERT(r, result == SkCodec::kSuccess);
-
- REPORTER_ASSERT(r, sk_tool_utils::equal_pixels(bm.pixmap(), bm2.pixmap(), 0, true));
-}