Home | History | Annotate | Download | only in core
      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.
     28 class SkColorSpace_A2B : public SkColorSpace_Base {
     29 public:
     30     const SkMatrix44* toXYZD50() 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 toXYZD50Hash() const override {
     40         // See toXYZD50()'s comment.
     41         return 0;
     42     }
     43 
     44     const SkMatrix44* fromXYZD50() const override {
     45         // See toXYZD50()'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     bool onGammaCloseToSRGB() const override { return false; }
     52     bool onGammaIsLinear() const override { return false; }
     53     bool onIsNumericalTransferFn(SkColorSpaceTransferFn* coeffs) const override { return false; }
     54 
     55     bool onIsCMYK() const override { return kCMYK_ICCTypeFlag == fICCType; }
     56 
     57     sk_sp<SkColorSpace> makeLinearGamma() override {
     58         // TODO: Analyze the extrema of our projection into XYZ and use suitable primaries?
     59         // For now, just fall back to a default, because we don't have a good answer.
     60         return SkColorSpace::MakeSRGBLinear();
     61     }
     62 
     63     sk_sp<SkColorSpace> makeSRGBGamma() override {
     64         // See comment in makeLinearGamma
     65         return SkColorSpace::MakeSRGB();
     66     }
     67 
     68     Type type() const override { return Type::kA2B; }
     69 
     70     class Element {
     71     public:
     72         Element(SkGammaNamed gammaNamed, int channelCount)
     73             : fType(Type::kGammaNamed)
     74             , fGammaNamed(gammaNamed)
     75             , fMatrix(SkMatrix44::kUninitialized_Constructor)
     76             , fInputChannels(channelCount)
     77             , fOutputChannels(channelCount) {
     78             SkASSERT(gammaNamed != kNonStandard_SkGammaNamed);
     79         }
     80 
     81         explicit Element(sk_sp<SkGammas> gammas)
     82             : fType(Type::kGammas)
     83             , fGammas(std::move(gammas))
     84             , fMatrix(SkMatrix44::kUninitialized_Constructor)
     85             , fInputChannels(fGammas->channels())
     86             , fOutputChannels(fGammas->channels()) {
     87             for (int i = 0; i < fGammas->channels(); ++i) {
     88                 if (SkGammas::Type::kTable_Type == fGammas->type(i)) {
     89                     SkASSERT(fGammas->data(i).fTable.fSize >= 2);
     90                 }
     91             }
     92         }
     93 
     94         explicit Element(sk_sp<SkColorLookUpTable> colorLUT)
     95             : fType(Type::kCLUT)
     96             , fCLUT(std::move(colorLUT))
     97             , fMatrix(SkMatrix44::kUninitialized_Constructor)
     98             , fInputChannels(fCLUT->inputChannels())
     99             , fOutputChannels(fCLUT->outputChannels())
    100         {}
    101 
    102         explicit Element(const SkMatrix44& matrix)
    103             : fType(Type::kMatrix)
    104             , fMatrix(matrix)
    105             , fInputChannels(3)
    106             , fOutputChannels(3)
    107         {}
    108 
    109         enum class Type {
    110             kGammaNamed,
    111             kGammas,
    112             kCLUT,
    113             kMatrix
    114         };
    115 
    116         Type type() const { return fType; }
    117 
    118         SkGammaNamed gammaNamed() const {
    119             SkASSERT(Type::kGammaNamed == fType);
    120             return fGammaNamed;
    121         }
    122 
    123         const SkGammas& gammas() const {
    124             SkASSERT(Type::kGammas == fType);
    125             return *fGammas;
    126         }
    127 
    128         const SkColorLookUpTable& colorLUT() const {
    129             SkASSERT(Type::kCLUT == fType);
    130             return *fCLUT;
    131         }
    132 
    133         const SkMatrix44& matrix() const {
    134             SkASSERT(Type::kMatrix == fType);
    135             return fMatrix;
    136         }
    137 
    138         int inputChannels() const { return fInputChannels; }
    139 
    140         int outputChannels() const { return fOutputChannels; }
    141 
    142     private:
    143         Type                      fType;
    144         SkGammaNamed              fGammaNamed;
    145         sk_sp<SkGammas>           fGammas;
    146         sk_sp<SkColorLookUpTable> fCLUT;
    147         SkMatrix44                fMatrix;
    148         int                       fInputChannels;
    149         int                       fOutputChannels;
    150     };
    151     const Element& element(int i) const { return fElements[i]; }
    152 
    153     int count() const { return (int)fElements.size(); }
    154 
    155     // the intermediate profile connection space that this color space
    156     // represents the transformation to
    157     enum class PCS : uint8_t {
    158         kLAB, // CIELAB
    159         kXYZ  // CIEXYZ
    160     };
    161 
    162     PCS pcs() const { return fPCS; }
    163 
    164     ICCTypeFlag iccType() const { return fICCType; }
    165 
    166     SkColorSpace_A2B(ICCTypeFlag iccType, std::vector<Element> elements, PCS pcs,
    167                      sk_sp<SkData> profileData);
    168 
    169 private:
    170     ICCTypeFlag          fICCType;
    171     std::vector<Element> fElements;
    172     PCS                  fPCS;
    173 
    174     friend class SkColorSpace_Base;
    175     friend class ColorSpaceXformTest;
    176     typedef SkColorSpace_Base INHERITED;
    177 };
    178 
    179 #endif
    180