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