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