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