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