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