diff options
author | Brian Osman <brianosman@google.com> | 2018-03-12 15:44:22 -0400 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2018-03-12 20:26:19 +0000 |
commit | 67f62b1a61016ad07b44ae5a0bbf79d97adc9ba9 (patch) | |
tree | 4211f82ca909ca48a7d86baac4f646f28fba8fb7 | |
parent | 501c17cb914ea7c0bba230789a9888f0b7889203 (diff) |
Add SkColorSpaceXform_skcms
Currently only enabled in Skia dev builds. Passes all unit
tests. Has some GM differences, but nothing major.
Bug: skia:
Change-Id: Ib87f8cff44649c731e829f063ccef448d67d1910
Reviewed-on: https://skia-review.googlesource.com/112520
Commit-Queue: Brian Osman <brianosman@google.com>
Reviewed-by: Mike Klein <mtklein@google.com>
-rw-r--r-- | BUILD.gn | 3 | ||||
-rw-r--r-- | include/core/SkColorSpace.h | 6 | ||||
-rw-r--r-- | src/core/SkColorSpacePriv.h | 4 | ||||
-rw-r--r-- | src/core/SkColorSpaceXform.cpp | 5 | ||||
-rw-r--r-- | src/core/SkColorSpaceXform_Base.h | 5 | ||||
-rw-r--r-- | src/core/SkColorSpaceXform_skcms.cpp | 119 |
6 files changed, 138 insertions, 4 deletions
@@ -726,11 +726,12 @@ optional("raw") { optional("skcms") { enabled = skia_use_skcms + public_defines = [ "SK_USE_SKCMS" ] deps = [ "//third_party/skcms", ] sources = [ - # TODO + "src/core/SkColorSpaceXform_skcms.cpp", ] } diff --git a/include/core/SkColorSpace.h b/include/core/SkColorSpace.h index 2908268306..35466fde23 100644 --- a/include/core/SkColorSpace.h +++ b/include/core/SkColorSpace.h @@ -241,6 +241,12 @@ public: */ static bool Equals(const SkColorSpace* src, const SkColorSpace* dst); + /** + * If this color space was constructed from an ICC profile, return that profile data. + * Otherise, return nullptr. + */ + const SkData* profileData() const { return this->onProfileData(); } + private: virtual const SkMatrix44* onToXYZD50() const = 0; virtual uint32_t onToXYZD50Hash() const = 0; 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..a850767291 100644 --- a/src/core/SkColorSpaceXform.cpp +++ b/src/core/SkColorSpaceXform.cpp @@ -317,9 +317,14 @@ std::unique_ptr<SkColorSpaceXform> SkColorSpaceXform_Base::New( } if (src->toXYZD50()) { +#if defined(SK_USE_SKCMS) + // TODO: Use this unconditionally, once A2B transform is implemented in skcms. + return MakeSkcmsXform(src, dst, premulBehavior); +#else return skstd::make_unique<SkColorSpaceXform_XYZ>(static_cast<SkColorSpace_XYZ*>(src), static_cast<SkColorSpace_XYZ*>(dst), premulBehavior); +#endif } return skstd::make_unique<SkColorSpaceXform_A2B>(static_cast<SkColorSpace_A2B*>(src), static_cast<SkColorSpace_XYZ*>(dst)); 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); +} |