aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar Brian Osman <brianosman@google.com>2018-03-26 17:05:48 -0400
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-03-27 13:15:24 +0000
commit094fba9cd6075a81bb039baed31abacb3c34bb18 (patch)
treec5c08264571b30b35a88dbc7dc42ec80665f332b /src
parentc26be9c50f27aa53a547f2dac46074f09637f306 (diff)
Add SkColorSpaceXform_skcms
Currently only enabled in Skia dev builds. Has some diffs in GMs and images, but (hopefully) nothing major. Bug: skia: Change-Id: Ifdf5d2804e59f555a3dc84f657e438dd589a2751 Reviewed-on: https://skia-review.googlesource.com/116520 Commit-Queue: Mike Klein <mtklein@google.com> Reviewed-by: Mike Klein <mtklein@chromium.org>
Diffstat (limited to 'src')
-rw-r--r--src/core/SkColorSpacePriv.h4
-rw-r--r--src/core/SkColorSpaceXform.cpp4
-rw-r--r--src/core/SkColorSpaceXform_Base.h5
-rw-r--r--src/core/SkColorSpaceXform_skcms.cpp119
4 files changed, 129 insertions, 3 deletions
diff --git a/src/core/SkColorSpacePriv.h b/src/core/SkColorSpacePriv.h
index 80046bb232..7b1b97dc03 100644
--- a/src/core/SkColorSpacePriv.h
+++ b/src/core/SkColorSpacePriv.h
@@ -48,10 +48,8 @@ static constexpr SkColorSpaceTransferFn gSRGB_TransferFn =
static constexpr SkColorSpaceTransferFn g2Dot2_TransferFn =
{ 2.2f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
-// gLinear_TransferFn.fD > 1.0f: Make sure that we use the linear segment of
-// the transfer function even when the x-value is 1.0f.
static constexpr SkColorSpaceTransferFn gLinear_TransferFn =
- { 0.0f, 0.0f, 0.0f, 1.0f, 1.0000001f, 0.0f, 0.0f };
+ { 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
static constexpr SkColorSpaceTransferFn gDCIP3_TransferFn =
{ 2.399994f, 0.947998047f, 0.0520019531f, 0.0769958496f, 0.0390014648f, 0.0f, 0.0f };
diff --git a/src/core/SkColorSpaceXform.cpp b/src/core/SkColorSpaceXform.cpp
index 7c53ed52dc..70a5beb15b 100644
--- a/src/core/SkColorSpaceXform.cpp
+++ b/src/core/SkColorSpaceXform.cpp
@@ -316,6 +316,9 @@ std::unique_ptr<SkColorSpaceXform> SkColorSpaceXform_Base::New(
return nullptr;
}
+#if defined(SK_USE_SKCMS)
+ return MakeSkcmsXform(src, dst, premulBehavior);
+#else
if (src->toXYZD50()) {
return skstd::make_unique<SkColorSpaceXform_XYZ>(static_cast<SkColorSpace_XYZ*>(src),
static_cast<SkColorSpace_XYZ*>(dst),
@@ -323,6 +326,7 @@ std::unique_ptr<SkColorSpaceXform> SkColorSpaceXform_Base::New(
}
return skstd::make_unique<SkColorSpaceXform_A2B>(static_cast<SkColorSpace_A2B*>(src),
static_cast<SkColorSpace_XYZ*>(dst));
+#endif
}
///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/core/SkColorSpaceXform_Base.h b/src/core/SkColorSpaceXform_Base.h
index f931cde8e0..2e0202360e 100644
--- a/src/core/SkColorSpaceXform_Base.h
+++ b/src/core/SkColorSpaceXform_Base.h
@@ -71,4 +71,9 @@ private:
// For testing. Bypasses opts for when src and dst color spaces are equal.
std::unique_ptr<SkColorSpaceXform> SlowIdentityXform(SkColorSpace_XYZ* space);
+#if defined(SK_USE_SKCMS)
+std::unique_ptr<SkColorSpaceXform> MakeSkcmsXform(SkColorSpace* src, SkColorSpace* dst,
+ SkTransferFunctionBehavior premulBehavior);
+#endif
+
#endif
diff --git a/src/core/SkColorSpaceXform_skcms.cpp b/src/core/SkColorSpaceXform_skcms.cpp
new file mode 100644
index 0000000000..34afaaa7c5
--- /dev/null
+++ b/src/core/SkColorSpaceXform_skcms.cpp
@@ -0,0 +1,119 @@
+/*
+ * 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 "SkColorSpaceXform.h"
+#include "SkData.h"
+#include "SkMakeUnique.h"
+#include "skcms.h"
+
+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);
+}
+
+static bool cs_to_profile(const SkColorSpace* cs, skcms_ICCProfile* profile) {
+ if (cs->profileData()) {
+ bool result = skcms_Parse(cs->profileData()->data(), cs->profileData()->size(), profile);
+ // We shouldn't encounter color spaces that were constructed from invalid profiles!
+ SkASSERT(result);
+ return result;
+ }
+
+ SkMatrix44 toXYZ;
+ SkColorSpaceTransferFn tf;
+ if (cs->toXYZD50(&toXYZ) && cs->isNumericalTransferFn(&tf)) {
+ memset(profile, 0, sizeof(*profile));
+
+ profile->has_trc = true;
+ profile->trc[0].parametric.g = tf.fG;
+ profile->trc[0].parametric.a = tf.fA;
+ profile->trc[0].parametric.b = tf.fB;
+ profile->trc[0].parametric.c = tf.fC;
+ profile->trc[0].parametric.d = tf.fD;
+ profile->trc[0].parametric.e = tf.fE;
+ profile->trc[0].parametric.f = tf.fF;
+ profile->trc[1].parametric = profile->trc[0].parametric;
+ profile->trc[2].parametric = profile->trc[0].parametric;
+
+ profile->has_toXYZD50 = true;
+ for (int r = 0; r < 3; ++r) {
+ for (int c = 0; c < 3; ++c) {
+ profile->toXYZD50.vals[r][c] = toXYZ.get(r, c);
+ }
+ }
+
+ return true;
+ }
+
+ // It should be impossible to make a color space that gets here with our available factories.
+ // All ICC-based profiles have profileData. All remaining factories produce XYZ spaces with
+ // a single (numerical) transfer function.
+ SkDEBUGFAIL("How did we get here?");
+ return false;
+}
+
+std::unique_ptr<SkColorSpaceXform> MakeSkcmsXform(SkColorSpace* src, SkColorSpace* dst,
+ SkTransferFunctionBehavior premulBehavior) {
+ // Construct skcms_ICCProfiles from each color space. For now, support A2B and XYZ.
+ // Eventually, only need to support XYZ. Map premulBehavior to one of the two premul formats
+ // in skcms.
+ skcms_ICCProfile srcProfile, dstProfile;
+
+ if (!cs_to_profile(src, &srcProfile) || !cs_to_profile(dst, &dstProfile)) {
+ return nullptr;
+ }
+
+ skcms_AlphaFormat premulFormat = SkTransferFunctionBehavior::kRespect == premulBehavior
+ ? skcms_AlphaFormat_PremulLinear : skcms_AlphaFormat_PremulAsEncoded;
+ return skstd::make_unique<SkColorSpaceXform_skcms>(srcProfile, dstProfile, premulFormat);
+}