SkColorSpace_A2B.h revision e9edf8cc50e50998f7074023f974ec034cfcec4c
1/*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#ifndef SkColorSpace_A2B_DEFINED
9#define SkColorSpace_A2B_DEFINED
10
11#include "SkColorSpace_Base.h"
12
13#include <vector>
14
15// An alternative SkColorSpace that represents all the color space data that
16// is stored in an A2B0 ICC tag. This allows us to use alternative profile
17// connection spaces (CIELAB instead of just CIEXYZ), use color-lookup-tables
18// to do color space transformations not representable as TRC functions or
19// matrix operations, as well as have multiple TRC functions. The CLUT also
20// allows conversion between non-3-channel input color spaces ie CMYK(4) to
21// a workable PCS (ie XYZ).
22//
23// AtoBType, lut8Type and lut16Type A2B0 tag types are supported. There are
24// also MPET (multi-processing-elements) A2B0 tags in the standard which allow
25// you to combine these 3 primitives (TRC, CLUT, matrix) in any order/quantity.
26// MPET tags are currently unsupported by the MakeICC parser, could be supported
27// here by the nature of the design.
28class SkColorSpace_A2B : public SkColorSpace_Base {
29public:
30    const SkMatrix44* onToXYZD50() const override {
31        // the matrix specified in A2B0 profiles is not necessarily
32        // a to-XYZ matrix, as to-Lab is supported as well so returning
33        // that could be misleading. Additionally, B-curves are applied
34        // after the matrix is, but a toXYZD50 matrix is the last thing
35        // applied in order to get into the (XYZ) profile connection space.
36        return nullptr;
37    }
38
39    uint32_t onToXYZD50Hash() const override {
40        // See onToXYZD50()'s comment.
41        return 0;
42    }
43
44    const SkMatrix44* onFromXYZD50() const override {
45        // See onToXYZD50()'s comment. Also, A2B0 profiles are not supported
46        // as destination color spaces, so an inverse matrix is never wanted.
47        return nullptr;
48    }
49
50    // There is no single gamma curve in an A2B0 profile
51    SkGammaNamed onGammaNamed() const override { return kNonStandard_SkGammaNamed; }
52    bool onGammaCloseToSRGB() const override { return false; }
53    bool onGammaIsLinear() const override { return false; }
54    bool onIsNumericalTransferFn(SkColorSpaceTransferFn* coeffs) const override { return false; }
55
56    bool onIsCMYK() const override { return SkColorSpace::kCMYK_Type == fICCType; }
57
58    const SkData* onProfileData() const override { return fProfileData.get(); }
59
60    sk_sp<SkColorSpace> makeLinearGamma() const override {
61        // TODO: Analyze the extrema of our projection into XYZ and use suitable primaries?
62        // For now, just fall back to a default, because we don't have a good answer.
63        return SkColorSpace::MakeSRGBLinear();
64    }
65
66    sk_sp<SkColorSpace> makeSRGBGamma() const override {
67        // See comment in makeLinearGamma
68        return SkColorSpace::MakeSRGB();
69    }
70
71    Type type() const override { return Type::kA2B; }
72
73    class Element {
74    public:
75        Element(SkGammaNamed gammaNamed, int channelCount)
76            : fType(Type::kGammaNamed)
77            , fGammaNamed(gammaNamed)
78            , fMatrix(SkMatrix44::kUninitialized_Constructor)
79            , fInputChannels(channelCount)
80            , fOutputChannels(channelCount) {
81            SkASSERT(gammaNamed != kNonStandard_SkGammaNamed);
82        }
83
84        explicit Element(sk_sp<SkGammas> gammas)
85            : fType(Type::kGammas)
86            , fGammas(std::move(gammas))
87            , fMatrix(SkMatrix44::kUninitialized_Constructor)
88            , fInputChannels(fGammas->channels())
89            , fOutputChannels(fGammas->channels()) {
90            for (int i = 0; i < fGammas->channels(); ++i) {
91                if (SkGammas::Type::kTable_Type == fGammas->type(i)) {
92                    SkASSERT(fGammas->data(i).fTable.fSize >= 2);
93                }
94            }
95        }
96
97        explicit Element(sk_sp<SkColorLookUpTable> colorLUT)
98            : fType(Type::kCLUT)
99            , fCLUT(std::move(colorLUT))
100            , fMatrix(SkMatrix44::kUninitialized_Constructor)
101            , fInputChannels(fCLUT->inputChannels())
102            , fOutputChannels(fCLUT->outputChannels())
103        {}
104
105        explicit Element(const SkMatrix44& matrix)
106            : fType(Type::kMatrix)
107            , fMatrix(matrix)
108            , fInputChannels(3)
109            , fOutputChannels(3)
110        {}
111
112        enum class Type {
113            kGammaNamed,
114            kGammas,
115            kCLUT,
116            kMatrix
117        };
118
119        Type type() const { return fType; }
120
121        SkGammaNamed gammaNamed() const {
122            SkASSERT(Type::kGammaNamed == fType);
123            return fGammaNamed;
124        }
125
126        const SkGammas& gammas() const {
127            SkASSERT(Type::kGammas == fType);
128            return *fGammas;
129        }
130
131        const SkColorLookUpTable& colorLUT() const {
132            SkASSERT(Type::kCLUT == fType);
133            return *fCLUT;
134        }
135
136        const SkMatrix44& matrix() const {
137            SkASSERT(Type::kMatrix == fType);
138            return fMatrix;
139        }
140
141        int inputChannels() const { return fInputChannels; }
142
143        int outputChannels() const { return fOutputChannels; }
144
145    private:
146        Type                      fType;
147        SkGammaNamed              fGammaNamed;
148        sk_sp<SkGammas>           fGammas;
149        sk_sp<SkColorLookUpTable> fCLUT;
150        SkMatrix44                fMatrix;
151        int                       fInputChannels;
152        int                       fOutputChannels;
153    };
154    const Element& element(int i) const { return fElements[i]; }
155
156    int count() const { return (int)fElements.size(); }
157
158    // the intermediate profile connection space that this color space
159    // represents the transformation to
160    enum class PCS : uint8_t {
161        kLAB, // CIELAB
162        kXYZ  // CIEXYZ
163    };
164
165    PCS pcs() const { return fPCS; }
166
167    SkColorSpace::Type iccType() const { return fICCType; }
168
169    SkColorSpace_A2B(SkColorSpace::Type iccType, std::vector<Element> elements, PCS pcs,
170                     sk_sp<SkData> profileData);
171
172private:
173    sk_sp<SkData>        fProfileData;
174
175    SkColorSpace::Type   fICCType;
176    std::vector<Element> fElements;
177    PCS                  fPCS;
178
179    friend class SkColorSpace_Base;
180    friend class ColorSpaceXformTest;
181    typedef SkColorSpace_Base INHERITED;
182};
183
184#endif
185