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 SkEncodedInfo_DEFINED 9 #define SkEncodedInfo_DEFINED 10 11 #include "SkData.h" 12 #include "SkImageInfo.h" 13 #include "../../third_party/skcms/skcms.h" 14 15 struct SkEncodedInfo { 16 public: 17 class ICCProfile { 18 public: 19 static std::unique_ptr<ICCProfile> Make(sk_sp<SkData>); 20 static std::unique_ptr<ICCProfile> Make(const skcms_ICCProfile&); 21 profileSkEncodedInfo22 const skcms_ICCProfile* profile() const { return &fProfile; } 23 private: 24 ICCProfile(const skcms_ICCProfile&, sk_sp<SkData> = nullptr); 25 26 skcms_ICCProfile fProfile; 27 sk_sp<SkData> fData; 28 }; 29 30 enum Alpha { 31 kOpaque_Alpha, 32 kUnpremul_Alpha, 33 34 // Each pixel is either fully opaque or fully transparent. 35 // There is no difference between requesting kPremul or kUnpremul. 36 kBinary_Alpha, 37 }; 38 39 /* 40 * We strive to make the number of components per pixel obvious through 41 * our naming conventions. 42 * Ex: kRGB has 3 components. kRGBA has 4 components. 43 * 44 * This sometimes results in redundant Alpha and Color information. 45 * Ex: kRGB images must also be kOpaque. 46 */ 47 enum Color { 48 // PNG, WBMP 49 kGray_Color, 50 51 // PNG 52 kGrayAlpha_Color, 53 54 // PNG with Skia-specific sBIT 55 // Like kGrayAlpha, except this expects to be treated as 56 // kAlpha_8_SkColorType, which ignores the gray component. If 57 // decoded to full color (e.g. kN32), the gray component is respected 58 // (so it can share code with kGrayAlpha). 59 kXAlpha_Color, 60 61 // PNG 62 // 565 images may be encoded to PNG by specifying the number of 63 // significant bits for each channel. This is a strange 565 64 // representation because the image is still encoded with 8 bits per 65 // component. 66 k565_Color, 67 68 // PNG, GIF, BMP 69 kPalette_Color, 70 71 // PNG, RAW 72 kRGB_Color, 73 kRGBA_Color, 74 75 // BMP 76 kBGR_Color, 77 kBGRX_Color, 78 kBGRA_Color, 79 80 // JPEG, WEBP 81 kYUV_Color, 82 83 // WEBP 84 kYUVA_Color, 85 86 // JPEG 87 // Photoshop actually writes inverted CMYK data into JPEGs, where zero 88 // represents 100% ink coverage. For this reason, we treat CMYK JPEGs 89 // as having inverted CMYK. libjpeg-turbo warns that this may break 90 // other applications, but the CMYK JPEGs we see on the web expect to 91 // be treated as inverted CMYK. 92 kInvertedCMYK_Color, 93 kYCCK_Color, 94 }; 95 MakeSkEncodedInfo96 static SkEncodedInfo Make(int width, int height, Color color, Alpha alpha, 97 int bitsPerComponent) { 98 return Make(width, height, color, alpha, bitsPerComponent, nullptr); 99 } 100 MakeSkEncodedInfo101 static SkEncodedInfo Make(int width, int height, Color color, Alpha alpha, 102 int bitsPerComponent, std::unique_ptr<ICCProfile> profile) { 103 SkASSERT(1 == bitsPerComponent || 104 2 == bitsPerComponent || 105 4 == bitsPerComponent || 106 8 == bitsPerComponent || 107 16 == bitsPerComponent); 108 109 switch (color) { 110 case kGray_Color: 111 SkASSERT(kOpaque_Alpha == alpha); 112 break; 113 case kGrayAlpha_Color: 114 SkASSERT(kOpaque_Alpha != alpha); 115 break; 116 case kPalette_Color: 117 SkASSERT(16 != bitsPerComponent); 118 break; 119 case kRGB_Color: 120 case kBGR_Color: 121 case kBGRX_Color: 122 SkASSERT(kOpaque_Alpha == alpha); 123 SkASSERT(bitsPerComponent >= 8); 124 break; 125 case kYUV_Color: 126 case kInvertedCMYK_Color: 127 case kYCCK_Color: 128 SkASSERT(kOpaque_Alpha == alpha); 129 SkASSERT(8 == bitsPerComponent); 130 break; 131 case kRGBA_Color: 132 SkASSERT(bitsPerComponent >= 8); 133 break; 134 case kBGRA_Color: 135 case kYUVA_Color: 136 SkASSERT(8 == bitsPerComponent); 137 break; 138 case kXAlpha_Color: 139 SkASSERT(kUnpremul_Alpha == alpha); 140 SkASSERT(8 == bitsPerComponent); 141 break; 142 case k565_Color: 143 SkASSERT(kOpaque_Alpha == alpha); 144 SkASSERT(8 == bitsPerComponent); 145 break; 146 default: 147 SkASSERT(false); 148 break; 149 } 150 151 return SkEncodedInfo(width, height, color, alpha, bitsPerComponent, std::move(profile)); 152 } 153 154 /* 155 * Returns a recommended SkImageInfo. 156 * 157 * TODO: Leave this up to the client. 158 */ makeImageInfoSkEncodedInfo159 SkImageInfo makeImageInfo() const { 160 auto ct = kGray_Color == fColor ? kGray_8_SkColorType : 161 kXAlpha_Color == fColor ? kAlpha_8_SkColorType : 162 k565_Color == fColor ? kRGB_565_SkColorType : 163 kN32_SkColorType ; 164 auto alpha = kOpaque_Alpha == fAlpha ? kOpaque_SkAlphaType 165 : kUnpremul_SkAlphaType; 166 sk_sp<SkColorSpace> cs = fProfile ? SkColorSpace::Make(*fProfile->profile()) 167 : nullptr; 168 if (!cs) { 169 cs = SkColorSpace::MakeSRGB(); 170 } 171 return SkImageInfo::Make(fWidth, fHeight, ct, alpha, std::move(cs)); 172 } 173 widthSkEncodedInfo174 int width() const { return fWidth; } heightSkEncodedInfo175 int height() const { return fHeight; } colorSkEncodedInfo176 Color color() const { return fColor; } alphaSkEncodedInfo177 Alpha alpha() const { return fAlpha; } opaqueSkEncodedInfo178 bool opaque() const { return fAlpha == kOpaque_Alpha; } profileSkEncodedInfo179 const skcms_ICCProfile* profile() const { 180 if (!fProfile) return nullptr; 181 return fProfile->profile(); 182 } 183 bitsPerComponentSkEncodedInfo184 uint8_t bitsPerComponent() const { return fBitsPerComponent; } 185 bitsPerPixelSkEncodedInfo186 uint8_t bitsPerPixel() const { 187 switch (fColor) { 188 case kGray_Color: 189 return fBitsPerComponent; 190 case kXAlpha_Color: 191 case kGrayAlpha_Color: 192 return 2 * fBitsPerComponent; 193 case kPalette_Color: 194 return fBitsPerComponent; 195 case kRGB_Color: 196 case kBGR_Color: 197 case kYUV_Color: 198 case k565_Color: 199 return 3 * fBitsPerComponent; 200 case kRGBA_Color: 201 case kBGRA_Color: 202 case kBGRX_Color: 203 case kYUVA_Color: 204 case kInvertedCMYK_Color: 205 case kYCCK_Color: 206 return 4 * fBitsPerComponent; 207 default: 208 SkASSERT(false); 209 return 0; 210 } 211 } 212 213 SkEncodedInfo(const SkEncodedInfo& orig) = delete; 214 SkEncodedInfo& operator=(const SkEncodedInfo&) = delete; 215 216 SkEncodedInfo(SkEncodedInfo&& orig) = default; 217 SkEncodedInfo& operator=(SkEncodedInfo&&) = default; 218 219 // Explicit copy method, to avoid accidental copying. copySkEncodedInfo220 SkEncodedInfo copy() const { 221 auto copy = SkEncodedInfo::Make(fWidth, fHeight, fColor, fAlpha, fBitsPerComponent); 222 if (fProfile) { 223 copy.fProfile.reset(new ICCProfile(*fProfile.get())); 224 } 225 return copy; 226 } 227 228 private: SkEncodedInfoSkEncodedInfo229 SkEncodedInfo(int width, int height, Color color, Alpha alpha, 230 uint8_t bitsPerComponent, std::unique_ptr<ICCProfile> profile) 231 : fWidth(width) 232 , fHeight(height) 233 , fColor(color) 234 , fAlpha(alpha) 235 , fBitsPerComponent(bitsPerComponent) 236 , fProfile(std::move(profile)) 237 {} 238 239 int fWidth; 240 int fHeight; 241 Color fColor; 242 Alpha fAlpha; 243 uint8_t fBitsPerComponent; 244 std::unique_ptr<ICCProfile> fProfile; 245 }; 246 247 #endif 248