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