SkColorSpace_A2B.h revision e9edf8cc50e50998f7074023f974ec034cfcec4c
19488833428e83c93a7e6002f4d056084fb57112fraftias/*
29488833428e83c93a7e6002f4d056084fb57112fraftias * Copyright 2016 Google Inc.
39488833428e83c93a7e6002f4d056084fb57112fraftias *
49488833428e83c93a7e6002f4d056084fb57112fraftias * Use of this source code is governed by a BSD-style license that can be
59488833428e83c93a7e6002f4d056084fb57112fraftias * found in the LICENSE file.
69488833428e83c93a7e6002f4d056084fb57112fraftias */
79488833428e83c93a7e6002f4d056084fb57112fraftias
89488833428e83c93a7e6002f4d056084fb57112fraftias#ifndef SkColorSpace_A2B_DEFINED
99488833428e83c93a7e6002f4d056084fb57112fraftias#define SkColorSpace_A2B_DEFINED
109488833428e83c93a7e6002f4d056084fb57112fraftias
119488833428e83c93a7e6002f4d056084fb57112fraftias#include "SkColorSpace_Base.h"
129488833428e83c93a7e6002f4d056084fb57112fraftias
13026f223d8641beeae19ed0bdbeca738be62256f5raftias#include <vector>
14026f223d8641beeae19ed0bdbeca738be62256f5raftias
159488833428e83c93a7e6002f4d056084fb57112fraftias// An alternative SkColorSpace that represents all the color space data that
169488833428e83c93a7e6002f4d056084fb57112fraftias// is stored in an A2B0 ICC tag. This allows us to use alternative profile
179488833428e83c93a7e6002f4d056084fb57112fraftias// connection spaces (CIELAB instead of just CIEXYZ), use color-lookup-tables
189488833428e83c93a7e6002f4d056084fb57112fraftias// to do color space transformations not representable as TRC functions or
195476128f0a88217414f05e6a7ee518cdb411d026raftias// matrix operations, as well as have multiple TRC functions. The CLUT also
205476128f0a88217414f05e6a7ee518cdb411d026raftias// allows conversion between non-3-channel input color spaces ie CMYK(4) to
215476128f0a88217414f05e6a7ee518cdb411d026raftias// a workable PCS (ie XYZ).
229488833428e83c93a7e6002f4d056084fb57112fraftias//
235476128f0a88217414f05e6a7ee518cdb411d026raftias// AtoBType, lut8Type and lut16Type A2B0 tag types are supported. There are
245476128f0a88217414f05e6a7ee518cdb411d026raftias// also MPET (multi-processing-elements) A2B0 tags in the standard which allow
255476128f0a88217414f05e6a7ee518cdb411d026raftias// you to combine these 3 primitives (TRC, CLUT, matrix) in any order/quantity.
265476128f0a88217414f05e6a7ee518cdb411d026raftias// MPET tags are currently unsupported by the MakeICC parser, could be supported
275476128f0a88217414f05e6a7ee518cdb411d026raftias// here by the nature of the design.
289488833428e83c93a7e6002f4d056084fb57112fraftiasclass SkColorSpace_A2B : public SkColorSpace_Base {
299488833428e83c93a7e6002f4d056084fb57112fraftiaspublic:
3036703d9d368050a20764b5336534bd718fd00a6eBrian Osman    const SkMatrix44* onToXYZD50() const override {
319488833428e83c93a7e6002f4d056084fb57112fraftias        // the matrix specified in A2B0 profiles is not necessarily
329488833428e83c93a7e6002f4d056084fb57112fraftias        // a to-XYZ matrix, as to-Lab is supported as well so returning
339488833428e83c93a7e6002f4d056084fb57112fraftias        // that could be misleading. Additionally, B-curves are applied
349488833428e83c93a7e6002f4d056084fb57112fraftias        // after the matrix is, but a toXYZD50 matrix is the last thing
359488833428e83c93a7e6002f4d056084fb57112fraftias        // applied in order to get into the (XYZ) profile connection space.
369488833428e83c93a7e6002f4d056084fb57112fraftias        return nullptr;
379488833428e83c93a7e6002f4d056084fb57112fraftias    }
389488833428e83c93a7e6002f4d056084fb57112fraftias
3936703d9d368050a20764b5336534bd718fd00a6eBrian Osman    uint32_t onToXYZD50Hash() const override {
4036703d9d368050a20764b5336534bd718fd00a6eBrian Osman        // See onToXYZD50()'s comment.
41bbf251bf225489a0939fff6df938035a290f4d16Brian Osman        return 0;
42bbf251bf225489a0939fff6df938035a290f4d16Brian Osman    }
43bbf251bf225489a0939fff6df938035a290f4d16Brian Osman
4436703d9d368050a20764b5336534bd718fd00a6eBrian Osman    const SkMatrix44* onFromXYZD50() const override {
4536703d9d368050a20764b5336534bd718fd00a6eBrian Osman        // See onToXYZD50()'s comment. Also, A2B0 profiles are not supported
469488833428e83c93a7e6002f4d056084fb57112fraftias        // as destination color spaces, so an inverse matrix is never wanted.
479488833428e83c93a7e6002f4d056084fb57112fraftias        return nullptr;
489488833428e83c93a7e6002f4d056084fb57112fraftias    }
495476128f0a88217414f05e6a7ee518cdb411d026raftias
50113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry    // There is no single gamma curve in an A2B0 profile
5136703d9d368050a20764b5336534bd718fd00a6eBrian Osman    SkGammaNamed onGammaNamed() const override { return kNonStandard_SkGammaNamed; }
52113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry    bool onGammaCloseToSRGB() const override { return false; }
53113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry    bool onGammaIsLinear() const override { return false; }
54113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry    bool onIsNumericalTransferFn(SkColorSpaceTransferFn* coeffs) const override { return false; }
559488833428e83c93a7e6002f4d056084fb57112fraftias
56f78b55cb94f4ac89b76a26d5a56d6380aa8fea6bLeon Scroggins III    bool onIsCMYK() const override { return SkColorSpace::kCMYK_Type == fICCType; }
577f15b682f4e3e0f61a56d3bbdb8163d3a54b997cMatt Sarett
58e9edf8cc50e50998f7074023f974ec034cfcec4cBrian Osman    const SkData* onProfileData() const override { return fProfileData.get(); }
59e9edf8cc50e50998f7074023f974ec034cfcec4cBrian Osman
60b1e6cfdb28b7a3db9ab64f90a709df725c1a9c43Mike Klein    sk_sp<SkColorSpace> makeLinearGamma() const override {
6112313f072b3563d652a789e28140f70b48e57e03Brian Osman        // TODO: Analyze the extrema of our projection into XYZ and use suitable primaries?
6212313f072b3563d652a789e28140f70b48e57e03Brian Osman        // For now, just fall back to a default, because we don't have a good answer.
6377a7a1b57c16c97f056c1e50c03bdc954947778cMatt Sarett        return SkColorSpace::MakeSRGBLinear();
6412313f072b3563d652a789e28140f70b48e57e03Brian Osman    }
6512313f072b3563d652a789e28140f70b48e57e03Brian Osman
66b1e6cfdb28b7a3db9ab64f90a709df725c1a9c43Mike Klein    sk_sp<SkColorSpace> makeSRGBGamma() const override {
6712313f072b3563d652a789e28140f70b48e57e03Brian Osman        // See comment in makeLinearGamma
6877a7a1b57c16c97f056c1e50c03bdc954947778cMatt Sarett        return SkColorSpace::MakeSRGB();
6912313f072b3563d652a789e28140f70b48e57e03Brian Osman    }
7012313f072b3563d652a789e28140f70b48e57e03Brian Osman
71026f223d8641beeae19ed0bdbeca738be62256f5raftias    Type type() const override { return Type::kA2B; }
729488833428e83c93a7e6002f4d056084fb57112fraftias
73026f223d8641beeae19ed0bdbeca738be62256f5raftias    class Element {
74026f223d8641beeae19ed0bdbeca738be62256f5raftias    public:
755476128f0a88217414f05e6a7ee518cdb411d026raftias        Element(SkGammaNamed gammaNamed, int channelCount)
76026f223d8641beeae19ed0bdbeca738be62256f5raftias            : fType(Type::kGammaNamed)
77026f223d8641beeae19ed0bdbeca738be62256f5raftias            , fGammaNamed(gammaNamed)
78026f223d8641beeae19ed0bdbeca738be62256f5raftias            , fMatrix(SkMatrix44::kUninitialized_Constructor)
795476128f0a88217414f05e6a7ee518cdb411d026raftias            , fInputChannels(channelCount)
80e8ea07a6127971aea8183303b9abfa9856b7a54craftias            , fOutputChannels(channelCount) {
81e8ea07a6127971aea8183303b9abfa9856b7a54craftias            SkASSERT(gammaNamed != kNonStandard_SkGammaNamed);
82e8ea07a6127971aea8183303b9abfa9856b7a54craftias        }
83026f223d8641beeae19ed0bdbeca738be62256f5raftias
84026f223d8641beeae19ed0bdbeca738be62256f5raftias        explicit Element(sk_sp<SkGammas> gammas)
85026f223d8641beeae19ed0bdbeca738be62256f5raftias            : fType(Type::kGammas)
86026f223d8641beeae19ed0bdbeca738be62256f5raftias            , fGammas(std::move(gammas))
875476128f0a88217414f05e6a7ee518cdb411d026raftias            , fMatrix(SkMatrix44::kUninitialized_Constructor)
885476128f0a88217414f05e6a7ee518cdb411d026raftias            , fInputChannels(fGammas->channels())
89197e311ac9d15696fae929d8f5fcf9d93ec55e18raftias            , fOutputChannels(fGammas->channels()) {
90197e311ac9d15696fae929d8f5fcf9d93ec55e18raftias            for (int i = 0; i < fGammas->channels(); ++i) {
91197e311ac9d15696fae929d8f5fcf9d93ec55e18raftias                if (SkGammas::Type::kTable_Type == fGammas->type(i)) {
92197e311ac9d15696fae929d8f5fcf9d93ec55e18raftias                    SkASSERT(fGammas->data(i).fTable.fSize >= 2);
93197e311ac9d15696fae929d8f5fcf9d93ec55e18raftias                }
94197e311ac9d15696fae929d8f5fcf9d93ec55e18raftias            }
95197e311ac9d15696fae929d8f5fcf9d93ec55e18raftias        }
96026f223d8641beeae19ed0bdbeca738be62256f5raftias
97026f223d8641beeae19ed0bdbeca738be62256f5raftias        explicit Element(sk_sp<SkColorLookUpTable> colorLUT)
98026f223d8641beeae19ed0bdbeca738be62256f5raftias            : fType(Type::kCLUT)
99026f223d8641beeae19ed0bdbeca738be62256f5raftias            , fCLUT(std::move(colorLUT))
100026f223d8641beeae19ed0bdbeca738be62256f5raftias            , fMatrix(SkMatrix44::kUninitialized_Constructor)
1015476128f0a88217414f05e6a7ee518cdb411d026raftias            , fInputChannels(fCLUT->inputChannels())
1025476128f0a88217414f05e6a7ee518cdb411d026raftias            , fOutputChannels(fCLUT->outputChannels())
103026f223d8641beeae19ed0bdbeca738be62256f5raftias        {}
104026f223d8641beeae19ed0bdbeca738be62256f5raftias
105026f223d8641beeae19ed0bdbeca738be62256f5raftias        explicit Element(const SkMatrix44& matrix)
106026f223d8641beeae19ed0bdbeca738be62256f5raftias            : fType(Type::kMatrix)
107026f223d8641beeae19ed0bdbeca738be62256f5raftias            , fMatrix(matrix)
1085476128f0a88217414f05e6a7ee518cdb411d026raftias            , fInputChannels(3)
1095476128f0a88217414f05e6a7ee518cdb411d026raftias            , fOutputChannels(3)
110026f223d8641beeae19ed0bdbeca738be62256f5raftias        {}
1115476128f0a88217414f05e6a7ee518cdb411d026raftias
112026f223d8641beeae19ed0bdbeca738be62256f5raftias        enum class Type {
113026f223d8641beeae19ed0bdbeca738be62256f5raftias            kGammaNamed,
114026f223d8641beeae19ed0bdbeca738be62256f5raftias            kGammas,
115026f223d8641beeae19ed0bdbeca738be62256f5raftias            kCLUT,
116026f223d8641beeae19ed0bdbeca738be62256f5raftias            kMatrix
117026f223d8641beeae19ed0bdbeca738be62256f5raftias        };
118026f223d8641beeae19ed0bdbeca738be62256f5raftias
119026f223d8641beeae19ed0bdbeca738be62256f5raftias        Type type() const { return fType; }
120026f223d8641beeae19ed0bdbeca738be62256f5raftias
121026f223d8641beeae19ed0bdbeca738be62256f5raftias        SkGammaNamed gammaNamed() const {
122026f223d8641beeae19ed0bdbeca738be62256f5raftias            SkASSERT(Type::kGammaNamed == fType);
123026f223d8641beeae19ed0bdbeca738be62256f5raftias            return fGammaNamed;
124026f223d8641beeae19ed0bdbeca738be62256f5raftias        }
125026f223d8641beeae19ed0bdbeca738be62256f5raftias
126026f223d8641beeae19ed0bdbeca738be62256f5raftias        const SkGammas& gammas() const {
127026f223d8641beeae19ed0bdbeca738be62256f5raftias            SkASSERT(Type::kGammas == fType);
128026f223d8641beeae19ed0bdbeca738be62256f5raftias            return *fGammas;
129026f223d8641beeae19ed0bdbeca738be62256f5raftias        }
130026f223d8641beeae19ed0bdbeca738be62256f5raftias
131026f223d8641beeae19ed0bdbeca738be62256f5raftias        const SkColorLookUpTable& colorLUT() const {
132026f223d8641beeae19ed0bdbeca738be62256f5raftias            SkASSERT(Type::kCLUT == fType);
133026f223d8641beeae19ed0bdbeca738be62256f5raftias            return *fCLUT;
134026f223d8641beeae19ed0bdbeca738be62256f5raftias        }
135026f223d8641beeae19ed0bdbeca738be62256f5raftias
136026f223d8641beeae19ed0bdbeca738be62256f5raftias        const SkMatrix44& matrix() const {
137026f223d8641beeae19ed0bdbeca738be62256f5raftias            SkASSERT(Type::kMatrix == fType);
138026f223d8641beeae19ed0bdbeca738be62256f5raftias            return fMatrix;
139026f223d8641beeae19ed0bdbeca738be62256f5raftias        }
140026f223d8641beeae19ed0bdbeca738be62256f5raftias
1415476128f0a88217414f05e6a7ee518cdb411d026raftias        int inputChannels() const { return fInputChannels; }
1425476128f0a88217414f05e6a7ee518cdb411d026raftias
1435476128f0a88217414f05e6a7ee518cdb411d026raftias        int outputChannels() const { return fOutputChannels; }
1445476128f0a88217414f05e6a7ee518cdb411d026raftias
145026f223d8641beeae19ed0bdbeca738be62256f5raftias    private:
146026f223d8641beeae19ed0bdbeca738be62256f5raftias        Type                      fType;
147026f223d8641beeae19ed0bdbeca738be62256f5raftias        SkGammaNamed              fGammaNamed;
148026f223d8641beeae19ed0bdbeca738be62256f5raftias        sk_sp<SkGammas>           fGammas;
149026f223d8641beeae19ed0bdbeca738be62256f5raftias        sk_sp<SkColorLookUpTable> fCLUT;
150026f223d8641beeae19ed0bdbeca738be62256f5raftias        SkMatrix44                fMatrix;
1515476128f0a88217414f05e6a7ee518cdb411d026raftias        int                       fInputChannels;
1525476128f0a88217414f05e6a7ee518cdb411d026raftias        int                       fOutputChannels;
153026f223d8641beeae19ed0bdbeca738be62256f5raftias    };
1545476128f0a88217414f05e6a7ee518cdb411d026raftias    const Element& element(int i) const { return fElements[i]; }
1555476128f0a88217414f05e6a7ee518cdb411d026raftias
1562563601fc2b0505619f905f86bd249ae630197ccraftias    int count() const { return (int)fElements.size(); }
1579488833428e83c93a7e6002f4d056084fb57112fraftias
1589488833428e83c93a7e6002f4d056084fb57112fraftias    // the intermediate profile connection space that this color space
1599488833428e83c93a7e6002f4d056084fb57112fraftias    // represents the transformation to
1609488833428e83c93a7e6002f4d056084fb57112fraftias    enum class PCS : uint8_t {
1619488833428e83c93a7e6002f4d056084fb57112fraftias        kLAB, // CIELAB
1629488833428e83c93a7e6002f4d056084fb57112fraftias        kXYZ  // CIEXYZ
1639488833428e83c93a7e6002f4d056084fb57112fraftias    };
1645476128f0a88217414f05e6a7ee518cdb411d026raftias
1659488833428e83c93a7e6002f4d056084fb57112fraftias    PCS pcs() const { return fPCS; }
1669488833428e83c93a7e6002f4d056084fb57112fraftias
167f78b55cb94f4ac89b76a26d5a56d6380aa8fea6bLeon Scroggins III    SkColorSpace::Type iccType() const { return fICCType; }
1685476128f0a88217414f05e6a7ee518cdb411d026raftias
169f78b55cb94f4ac89b76a26d5a56d6380aa8fea6bLeon Scroggins III    SkColorSpace_A2B(SkColorSpace::Type iccType, std::vector<Element> elements, PCS pcs,
1705476128f0a88217414f05e6a7ee518cdb411d026raftias                     sk_sp<SkData> profileData);
171026f223d8641beeae19ed0bdbeca738be62256f5raftias
172595599f46261225dfc67ab4d91d326e099558239Matt Sarettprivate:
173e9edf8cc50e50998f7074023f974ec034cfcec4cBrian Osman    sk_sp<SkData>        fProfileData;
174e9edf8cc50e50998f7074023f974ec034cfcec4cBrian Osman
175f78b55cb94f4ac89b76a26d5a56d6380aa8fea6bLeon Scroggins III    SkColorSpace::Type   fICCType;
17662458a6778bc39eea5360301a67d192b3a263df1Mike Klein    std::vector<Element> fElements;
1775476128f0a88217414f05e6a7ee518cdb411d026raftias    PCS                  fPCS;
178026f223d8641beeae19ed0bdbeca738be62256f5raftias
1795476128f0a88217414f05e6a7ee518cdb411d026raftias    friend class SkColorSpace_Base;
1802563601fc2b0505619f905f86bd249ae630197ccraftias    friend class ColorSpaceXformTest;
1819488833428e83c93a7e6002f4d056084fb57112fraftias    typedef SkColorSpace_Base INHERITED;
1829488833428e83c93a7e6002f4d056084fb57112fraftias};
1839488833428e83c93a7e6002f4d056084fb57112fraftias
1849488833428e83c93a7e6002f4d056084fb57112fraftias#endif
185