aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/SkColorSpaceXform.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/SkColorSpaceXform.cpp')
-rw-r--r--src/core/SkColorSpaceXform.cpp139
1 files changed, 127 insertions, 12 deletions
diff --git a/src/core/SkColorSpaceXform.cpp b/src/core/SkColorSpaceXform.cpp
index b2228fc464..213e5b501e 100644
--- a/src/core/SkColorSpaceXform.cpp
+++ b/src/core/SkColorSpaceXform.cpp
@@ -7,23 +7,14 @@
#include "SkColorSpaceXform.h"
#include "SkColorSpaceXformPriv.h"
+#include "SkData.h"
+#include "SkMakeUnique.h"
+#include "../../third_party/skcms/skcms.h"
std::unique_ptr<SkColorSpaceXform> SkColorSpaceXform::New(SkColorSpace* src, SkColorSpace* dst) {
return SkMakeColorSpaceXform(src, dst, SkTransferFunctionBehavior::kRespect);
}
-std::unique_ptr<SkColorSpaceXform> SkMakeColorSpaceXform(
- SkColorSpace* src,
- SkColorSpace* dst,
- SkTransferFunctionBehavior premulBehavior) {
-#if defined(SK_USE_SKCMS)
- if (src && dst && dst->toXYZD50()) {
- return SkMakeColorSpaceXform_skcms(src, dst, premulBehavior);
- }
-#endif
- return nullptr;
-}
-
bool SkColorSpaceXform::Apply(SkColorSpace* dstCS, ColorFormat dstFormat, void* dst,
SkColorSpace* srcCS, ColorFormat srcFormat, const void* src,
int len, AlphaOp op) {
@@ -35,3 +26,127 @@ bool SkColorSpaceXform::Apply(SkColorSpace* dstCS, ColorFormat dstFormat, void*
}
return SkColorSpaceXform::New(srcCS, dstCS)->apply(dstFormat, dst, srcFormat, src, len, at);
}
+
+class SkColorSpaceXform_skcms : public SkColorSpaceXform {
+public:
+ SkColorSpaceXform_skcms(const skcms_ICCProfile& srcProfile,
+ const skcms_ICCProfile& dstProfile,
+ skcms_AlphaFormat premulFormat)
+ : fSrcProfile(srcProfile)
+ , fDstProfile(dstProfile)
+ , fPremulFormat(premulFormat) {
+ }
+
+ bool apply(ColorFormat, void*, ColorFormat, const void*, int, SkAlphaType) const override;
+
+private:
+ skcms_ICCProfile fSrcProfile;
+ skcms_ICCProfile fDstProfile;
+ skcms_AlphaFormat fPremulFormat;
+};
+
+static skcms_PixelFormat get_skcms_format(SkColorSpaceXform::ColorFormat fmt) {
+ switch (fmt) {
+ case SkColorSpaceXform::kRGBA_8888_ColorFormat:
+ return skcms_PixelFormat_RGBA_8888;
+ case SkColorSpaceXform::kBGRA_8888_ColorFormat:
+ return skcms_PixelFormat_BGRA_8888;
+ case SkColorSpaceXform::kRGB_U16_BE_ColorFormat:
+ return skcms_PixelFormat_RGB_161616;
+ case SkColorSpaceXform::kRGBA_U16_BE_ColorFormat:
+ return skcms_PixelFormat_RGBA_16161616;
+ case SkColorSpaceXform::kRGBA_F16_ColorFormat:
+ return skcms_PixelFormat_RGBA_hhhh;
+ case SkColorSpaceXform::kRGBA_F32_ColorFormat:
+ return skcms_PixelFormat_RGBA_ffff;
+ case SkColorSpaceXform::kBGR_565_ColorFormat:
+ return skcms_PixelFormat_BGR_565;
+ default:
+ SkDEBUGFAIL("Invalid ColorFormat");
+ return skcms_PixelFormat_RGBA_8888;
+ }
+}
+
+bool SkColorSpaceXform_skcms::apply(ColorFormat dstFormat, void* dst,
+ ColorFormat srcFormat, const void* src,
+ int count, SkAlphaType alphaType) const {
+ skcms_AlphaFormat srcAlpha = skcms_AlphaFormat_Unpremul;
+ skcms_AlphaFormat dstAlpha = kPremul_SkAlphaType == alphaType ? fPremulFormat
+ : skcms_AlphaFormat_Unpremul;
+
+ return skcms_Transform(src, get_skcms_format(srcFormat), srcAlpha, &fSrcProfile,
+ dst, get_skcms_format(dstFormat), dstAlpha, &fDstProfile, count);
+}
+
+void SkColorSpace::toProfile(skcms_ICCProfile* profile) const {
+ if (auto blob = this->onProfileData()) {
+ SkAssertResult(skcms_Parse(blob->data(), blob->size(), profile));
+ } else {
+ SkMatrix44 toXYZ(SkMatrix44::kUninitialized_Constructor);
+ SkColorSpaceTransferFn tf;
+ SkAssertResult(this->toXYZD50(&toXYZ) && this->isNumericalTransferFn(&tf));
+
+ skcms_Matrix3x3 m = { {
+ { toXYZ.get(0, 0), toXYZ.get(0, 1), toXYZ.get(0, 2) },
+ { toXYZ.get(1, 0), toXYZ.get(1, 1), toXYZ.get(1, 2) },
+ { toXYZ.get(2, 0), toXYZ.get(2, 1), toXYZ.get(2, 2) },
+ } };
+
+ skcms_Init(profile);
+ skcms_SetTransferFunction(profile, (const skcms_TransferFunction*)&tf);
+ skcms_SetXYZD50(profile, &m);
+ }
+}
+
+std::unique_ptr<SkColorSpaceXform> SkMakeColorSpaceXform(SkColorSpace* src, SkColorSpace* dst,
+ SkTransferFunctionBehavior premul) {
+ if (src && dst && dst->toXYZD50()) {
+ // Construct skcms_ICCProfiles from each color space. For now, support A2B and XYZ.
+ // Eventually, only need to support XYZ. Map premul to one of the two premul formats
+ // in skcms.
+ skcms_ICCProfile srcProfile, dstProfile;
+
+ src->toProfile(&srcProfile);
+ dst->toProfile(&dstProfile);
+
+ if (!skcms_MakeUsableAsDestination(&dstProfile)) {
+ return nullptr;
+ }
+
+ skcms_AlphaFormat premulFormat = SkTransferFunctionBehavior::kRespect == premul
+ ? skcms_AlphaFormat_PremulLinear
+ : skcms_AlphaFormat_PremulAsEncoded;
+ return skstd::make_unique<SkColorSpaceXform_skcms>(srcProfile, dstProfile, premulFormat);
+ }
+ return nullptr;
+}
+
+sk_sp<SkColorSpace> SkColorSpace::Make(const skcms_ICCProfile& profile) {
+ if (!profile.has_toXYZD50 || !profile.has_trc) {
+ return nullptr;
+ }
+
+ if (skcms_ApproximatelyEqualProfiles(&profile, skcms_sRGB_profile())) {
+ return SkColorSpace::MakeSRGB();
+ }
+
+ SkMatrix44 toXYZD50(SkMatrix44::kUninitialized_Constructor);
+ toXYZD50.set3x3RowMajorf(&profile.toXYZD50.vals[0][0]);
+ if (!toXYZD50.invert(nullptr)) {
+ return nullptr;
+ }
+
+ const skcms_Curve* trc = profile.trc;
+ if (trc[0].table_entries ||
+ trc[1].table_entries ||
+ trc[2].table_entries ||
+ memcmp(&trc[0].parametric, &trc[1].parametric, sizeof(trc[0].parametric)) ||
+ memcmp(&trc[0].parametric, &trc[2].parametric, sizeof(trc[0].parametric))) {
+ return nullptr;
+ }
+
+ SkColorSpaceTransferFn skia_tf;
+ memcpy(&skia_tf, &profile.trc[0].parametric, sizeof(skia_tf));
+
+ return SkColorSpace::MakeRGB(skia_tf, toXYZD50);
+}