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
11333848272c4d023199e44ff38f2e6fc6876388e8Mike Klein#include "SkColorLookUpTable.h"
12333848272c4d023199e44ff38f2e6fc6876388e8Mike Klein#include "SkColorSpace.h"
13333848272c4d023199e44ff38f2e6fc6876388e8Mike Klein#include "SkGammas.h"
14026f223d8641beeae19ed0bdbeca738be62256f5raftias#include <vector>
15026f223d8641beeae19ed0bdbeca738be62256f5raftias
169488833428e83c93a7e6002f4d056084fb57112fraftias// An alternative SkColorSpace that represents all the color space data that
179488833428e83c93a7e6002f4d056084fb57112fraftias// is stored in an A2B0 ICC tag. This allows us to use alternative profile
189488833428e83c93a7e6002f4d056084fb57112fraftias// connection spaces (CIELAB instead of just CIEXYZ), use color-lookup-tables
199488833428e83c93a7e6002f4d056084fb57112fraftias// to do color space transformations not representable as TRC functions or
205476128f0a88217414f05e6a7ee518cdb411d026raftias// matrix operations, as well as have multiple TRC functions. The CLUT also
215476128f0a88217414f05e6a7ee518cdb411d026raftias// allows conversion between non-3-channel input color spaces ie CMYK(4) to
225476128f0a88217414f05e6a7ee518cdb411d026raftias// a workable PCS (ie XYZ).
239488833428e83c93a7e6002f4d056084fb57112fraftias//
245476128f0a88217414f05e6a7ee518cdb411d026raftias// AtoBType, lut8Type and lut16Type A2B0 tag types are supported. There are
255476128f0a88217414f05e6a7ee518cdb411d026raftias// also MPET (multi-processing-elements) A2B0 tags in the standard which allow
265476128f0a88217414f05e6a7ee518cdb411d026raftias// you to combine these 3 primitives (TRC, CLUT, matrix) in any order/quantity.
275476128f0a88217414f05e6a7ee518cdb411d026raftias// MPET tags are currently unsupported by the MakeICC parser, could be supported
285476128f0a88217414f05e6a7ee518cdb411d026raftias// here by the nature of the design.
29333848272c4d023199e44ff38f2e6fc6876388e8Mike Kleinclass SkColorSpace_A2B : public SkColorSpace {
309488833428e83c93a7e6002f4d056084fb57112fraftiaspublic:
3136703d9d368050a20764b5336534bd718fd00a6eBrian Osman    const SkMatrix44* onToXYZD50() const override {
329488833428e83c93a7e6002f4d056084fb57112fraftias        // the matrix specified in A2B0 profiles is not necessarily
339488833428e83c93a7e6002f4d056084fb57112fraftias        // a to-XYZ matrix, as to-Lab is supported as well so returning
349488833428e83c93a7e6002f4d056084fb57112fraftias        // that could be misleading. Additionally, B-curves are applied
359488833428e83c93a7e6002f4d056084fb57112fraftias        // after the matrix is, but a toXYZD50 matrix is the last thing
369488833428e83c93a7e6002f4d056084fb57112fraftias        // applied in order to get into the (XYZ) profile connection space.
379488833428e83c93a7e6002f4d056084fb57112fraftias        return nullptr;
389488833428e83c93a7e6002f4d056084fb57112fraftias    }
399488833428e83c93a7e6002f4d056084fb57112fraftias
4036703d9d368050a20764b5336534bd718fd00a6eBrian Osman    uint32_t onToXYZD50Hash() const override {
4136703d9d368050a20764b5336534bd718fd00a6eBrian Osman        // See onToXYZD50()'s comment.
42bbf251bf225489a0939fff6df938035a290f4d16Brian Osman        return 0;
43bbf251bf225489a0939fff6df938035a290f4d16Brian Osman    }
44bbf251bf225489a0939fff6df938035a290f4d16Brian Osman
4536703d9d368050a20764b5336534bd718fd00a6eBrian Osman    const SkMatrix44* onFromXYZD50() const override {
4636703d9d368050a20764b5336534bd718fd00a6eBrian Osman        // See onToXYZD50()'s comment. Also, A2B0 profiles are not supported
479488833428e83c93a7e6002f4d056084fb57112fraftias        // as destination color spaces, so an inverse matrix is never wanted.
489488833428e83c93a7e6002f4d056084fb57112fraftias        return nullptr;
499488833428e83c93a7e6002f4d056084fb57112fraftias    }
505476128f0a88217414f05e6a7ee518cdb411d026raftias
51113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry    // There is no single gamma curve in an A2B0 profile
5236703d9d368050a20764b5336534bd718fd00a6eBrian Osman    SkGammaNamed onGammaNamed() const override { return kNonStandard_SkGammaNamed; }
53113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry    bool onGammaCloseToSRGB() const override { return false; }
54113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry    bool onGammaIsLinear() const override { return false; }
55113d05fa7b26797e3e468f78ea94a214476b63fbRavi Mistry    bool onIsNumericalTransferFn(SkColorSpaceTransferFn* coeffs) const override { return false; }
569488833428e83c93a7e6002f4d056084fb57112fraftias
57f78b55cb94f4ac89b76a26d5a56d6380aa8fea6bLeon Scroggins III    bool onIsCMYK() const override { return SkColorSpace::kCMYK_Type == fICCType; }
587f15b682f4e3e0f61a56d3bbdb8163d3a54b997cMatt Sarett
59e9edf8cc50e50998f7074023f974ec034cfcec4cBrian Osman    const SkData* onProfileData() const override { return fProfileData.get(); }
60e9edf8cc50e50998f7074023f974ec034cfcec4cBrian Osman
61b1e6cfdb28b7a3db9ab64f90a709df725c1a9c43Mike Klein    sk_sp<SkColorSpace> makeLinearGamma() const override {
6212313f072b3563d652a789e28140f70b48e57e03Brian Osman        // TODO: Analyze the extrema of our projection into XYZ and use suitable primaries?
6312313f072b3563d652a789e28140f70b48e57e03Brian Osman        // For now, just fall back to a default, because we don't have a good answer.
6477a7a1b57c16c97f056c1e50c03bdc954947778cMatt Sarett        return SkColorSpace::MakeSRGBLinear();
6512313f072b3563d652a789e28140f70b48e57e03Brian Osman    }
6612313f072b3563d652a789e28140f70b48e57e03Brian Osman
67b1e6cfdb28b7a3db9ab64f90a709df725c1a9c43Mike Klein    sk_sp<SkColorSpace> makeSRGBGamma() const override {
6812313f072b3563d652a789e28140f70b48e57e03Brian Osman        // See comment in makeLinearGamma
6977a7a1b57c16c97f056c1e50c03bdc954947778cMatt Sarett        return SkColorSpace::MakeSRGB();
7012313f072b3563d652a789e28140f70b48e57e03Brian Osman    }
7112313f072b3563d652a789e28140f70b48e57e03Brian Osman
72026f223d8641beeae19ed0bdbeca738be62256f5raftias    class Element {
73026f223d8641beeae19ed0bdbeca738be62256f5raftias    public:
745476128f0a88217414f05e6a7ee518cdb411d026raftias        Element(SkGammaNamed gammaNamed, int channelCount)
75026f223d8641beeae19ed0bdbeca738be62256f5raftias            : fType(Type::kGammaNamed)
76026f223d8641beeae19ed0bdbeca738be62256f5raftias            , fGammaNamed(gammaNamed)
77026f223d8641beeae19ed0bdbeca738be62256f5raftias            , fMatrix(SkMatrix44::kUninitialized_Constructor)
785476128f0a88217414f05e6a7ee518cdb411d026raftias            , fInputChannels(channelCount)
79e8ea07a6127971aea8183303b9abfa9856b7a54craftias            , fOutputChannels(channelCount) {
80e8ea07a6127971aea8183303b9abfa9856b7a54craftias            SkASSERT(gammaNamed != kNonStandard_SkGammaNamed);
81e8ea07a6127971aea8183303b9abfa9856b7a54craftias        }
82026f223d8641beeae19ed0bdbeca738be62256f5raftias
83026f223d8641beeae19ed0bdbeca738be62256f5raftias        explicit Element(sk_sp<SkGammas> gammas)
84026f223d8641beeae19ed0bdbeca738be62256f5raftias            : fType(Type::kGammas)
85026f223d8641beeae19ed0bdbeca738be62256f5raftias            , fGammas(std::move(gammas))
865476128f0a88217414f05e6a7ee518cdb411d026raftias            , fMatrix(SkMatrix44::kUninitialized_Constructor)
875476128f0a88217414f05e6a7ee518cdb411d026raftias            , fInputChannels(fGammas->channels())
88197e311ac9d15696fae929d8f5fcf9d93ec55e18raftias            , fOutputChannels(fGammas->channels()) {
89197e311ac9d15696fae929d8f5fcf9d93ec55e18raftias            for (int i = 0; i < fGammas->channels(); ++i) {
90197e311ac9d15696fae929d8f5fcf9d93ec55e18raftias                if (SkGammas::Type::kTable_Type == fGammas->type(i)) {
91197e311ac9d15696fae929d8f5fcf9d93ec55e18raftias                    SkASSERT(fGammas->data(i).fTable.fSize >= 2);
92197e311ac9d15696fae929d8f5fcf9d93ec55e18raftias                }
93197e311ac9d15696fae929d8f5fcf9d93ec55e18raftias            }
94197e311ac9d15696fae929d8f5fcf9d93ec55e18raftias        }
95026f223d8641beeae19ed0bdbeca738be62256f5raftias
96026f223d8641beeae19ed0bdbeca738be62256f5raftias        explicit Element(sk_sp<SkColorLookUpTable> colorLUT)
97026f223d8641beeae19ed0bdbeca738be62256f5raftias            : fType(Type::kCLUT)
98026f223d8641beeae19ed0bdbeca738be62256f5raftias            , fCLUT(std::move(colorLUT))
99026f223d8641beeae19ed0bdbeca738be62256f5raftias            , fMatrix(SkMatrix44::kUninitialized_Constructor)
1005476128f0a88217414f05e6a7ee518cdb411d026raftias            , fInputChannels(fCLUT->inputChannels())
1015476128f0a88217414f05e6a7ee518cdb411d026raftias            , fOutputChannels(fCLUT->outputChannels())
102026f223d8641beeae19ed0bdbeca738be62256f5raftias        {}
103026f223d8641beeae19ed0bdbeca738be62256f5raftias
104026f223d8641beeae19ed0bdbeca738be62256f5raftias        explicit Element(const SkMatrix44& matrix)
105026f223d8641beeae19ed0bdbeca738be62256f5raftias            : fType(Type::kMatrix)
106026f223d8641beeae19ed0bdbeca738be62256f5raftias            , fMatrix(matrix)
1075476128f0a88217414f05e6a7ee518cdb411d026raftias            , fInputChannels(3)
1085476128f0a88217414f05e6a7ee518cdb411d026raftias            , fOutputChannels(3)
109026f223d8641beeae19ed0bdbeca738be62256f5raftias        {}
1105476128f0a88217414f05e6a7ee518cdb411d026raftias
111026f223d8641beeae19ed0bdbeca738be62256f5raftias        enum class Type {
112026f223d8641beeae19ed0bdbeca738be62256f5raftias            kGammaNamed,
113026f223d8641beeae19ed0bdbeca738be62256f5raftias            kGammas,
114026f223d8641beeae19ed0bdbeca738be62256f5raftias            kCLUT,
115026f223d8641beeae19ed0bdbeca738be62256f5raftias            kMatrix
116026f223d8641beeae19ed0bdbeca738be62256f5raftias        };
117026f223d8641beeae19ed0bdbeca738be62256f5raftias
118026f223d8641beeae19ed0bdbeca738be62256f5raftias        Type type() const { return fType; }
119026f223d8641beeae19ed0bdbeca738be62256f5raftias
120026f223d8641beeae19ed0bdbeca738be62256f5raftias        SkGammaNamed gammaNamed() const {
121026f223d8641beeae19ed0bdbeca738be62256f5raftias            SkASSERT(Type::kGammaNamed == fType);
122026f223d8641beeae19ed0bdbeca738be62256f5raftias            return fGammaNamed;
123026f223d8641beeae19ed0bdbeca738be62256f5raftias        }
124026f223d8641beeae19ed0bdbeca738be62256f5raftias
125026f223d8641beeae19ed0bdbeca738be62256f5raftias        const SkGammas& gammas() const {
126026f223d8641beeae19ed0bdbeca738be62256f5raftias            SkASSERT(Type::kGammas == fType);
127026f223d8641beeae19ed0bdbeca738be62256f5raftias            return *fGammas;
128026f223d8641beeae19ed0bdbeca738be62256f5raftias        }
129026f223d8641beeae19ed0bdbeca738be62256f5raftias
130026f223d8641beeae19ed0bdbeca738be62256f5raftias        const SkColorLookUpTable& colorLUT() const {
131026f223d8641beeae19ed0bdbeca738be62256f5raftias            SkASSERT(Type::kCLUT == fType);
132026f223d8641beeae19ed0bdbeca738be62256f5raftias            return *fCLUT;
133026f223d8641beeae19ed0bdbeca738be62256f5raftias        }
134026f223d8641beeae19ed0bdbeca738be62256f5raftias
135026f223d8641beeae19ed0bdbeca738be62256f5raftias        const SkMatrix44& matrix() const {
136026f223d8641beeae19ed0bdbeca738be62256f5raftias            SkASSERT(Type::kMatrix == fType);
137026f223d8641beeae19ed0bdbeca738be62256f5raftias            return fMatrix;
138026f223d8641beeae19ed0bdbeca738be62256f5raftias        }
139026f223d8641beeae19ed0bdbeca738be62256f5raftias
1405476128f0a88217414f05e6a7ee518cdb411d026raftias        int inputChannels() const { return fInputChannels; }
1415476128f0a88217414f05e6a7ee518cdb411d026raftias
1425476128f0a88217414f05e6a7ee518cdb411d026raftias        int outputChannels() const { return fOutputChannels; }
1435476128f0a88217414f05e6a7ee518cdb411d026raftias
144026f223d8641beeae19ed0bdbeca738be62256f5raftias    private:
145026f223d8641beeae19ed0bdbeca738be62256f5raftias        Type                      fType;
146026f223d8641beeae19ed0bdbeca738be62256f5raftias        SkGammaNamed              fGammaNamed;
147026f223d8641beeae19ed0bdbeca738be62256f5raftias        sk_sp<SkGammas>           fGammas;
148026f223d8641beeae19ed0bdbeca738be62256f5raftias        sk_sp<SkColorLookUpTable> fCLUT;
149026f223d8641beeae19ed0bdbeca738be62256f5raftias        SkMatrix44                fMatrix;
1505476128f0a88217414f05e6a7ee518cdb411d026raftias        int                       fInputChannels;
1515476128f0a88217414f05e6a7ee518cdb411d026raftias        int                       fOutputChannels;
152026f223d8641beeae19ed0bdbeca738be62256f5raftias    };
1535476128f0a88217414f05e6a7ee518cdb411d026raftias    const Element& element(int i) const { return fElements[i]; }
1545476128f0a88217414f05e6a7ee518cdb411d026raftias
1552563601fc2b0505619f905f86bd249ae630197ccraftias    int count() const { return (int)fElements.size(); }
1569488833428e83c93a7e6002f4d056084fb57112fraftias
1579488833428e83c93a7e6002f4d056084fb57112fraftias    // the intermediate profile connection space that this color space
1589488833428e83c93a7e6002f4d056084fb57112fraftias    // represents the transformation to
1599488833428e83c93a7e6002f4d056084fb57112fraftias    enum class PCS : uint8_t {
1609488833428e83c93a7e6002f4d056084fb57112fraftias        kLAB, // CIELAB
1619488833428e83c93a7e6002f4d056084fb57112fraftias        kXYZ  // CIEXYZ
1629488833428e83c93a7e6002f4d056084fb57112fraftias    };
1635476128f0a88217414f05e6a7ee518cdb411d026raftias
1649488833428e83c93a7e6002f4d056084fb57112fraftias    PCS pcs() const { return fPCS; }
1659488833428e83c93a7e6002f4d056084fb57112fraftias
166f78b55cb94f4ac89b76a26d5a56d6380aa8fea6bLeon Scroggins III    SkColorSpace::Type iccType() const { return fICCType; }
1675476128f0a88217414f05e6a7ee518cdb411d026raftias
168f78b55cb94f4ac89b76a26d5a56d6380aa8fea6bLeon Scroggins III    SkColorSpace_A2B(SkColorSpace::Type iccType, std::vector<Element> elements, PCS pcs,
1695476128f0a88217414f05e6a7ee518cdb411d026raftias                     sk_sp<SkData> profileData);
170026f223d8641beeae19ed0bdbeca738be62256f5raftias
171595599f46261225dfc67ab4d91d326e099558239Matt Sarettprivate:
172e9edf8cc50e50998f7074023f974ec034cfcec4cBrian Osman    sk_sp<SkData>        fProfileData;
173e9edf8cc50e50998f7074023f974ec034cfcec4cBrian Osman
174f78b55cb94f4ac89b76a26d5a56d6380aa8fea6bLeon Scroggins III    SkColorSpace::Type   fICCType;
17562458a6778bc39eea5360301a67d192b3a263df1Mike Klein    std::vector<Element> fElements;
1765476128f0a88217414f05e6a7ee518cdb411d026raftias    PCS                  fPCS;
177026f223d8641beeae19ed0bdbeca738be62256f5raftias
1782563601fc2b0505619f905f86bd249ae630197ccraftias    friend class ColorSpaceXformTest;
1799488833428e83c93a7e6002f4d056084fb57112fraftias};
1809488833428e83c93a7e6002f4d056084fb57112fraftias
1819488833428e83c93a7e6002f4d056084fb57112fraftias#endif
182