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, Alpha alpha, 104 int bitsPerComponent, std::unique_ptr<ICCProfile> profile) { 105 SkASSERT(1 == bitsPerComponent || 106 2 == bitsPerComponent || 107 4 == bitsPerComponent || 108 8 == bitsPerComponent || 109 16 == bitsPerComponent); 110 111 switch (color) { 112 case kGray_Color: 113 SkASSERT(kOpaque_Alpha == alpha); 114 break; 115 case kGrayAlpha_Color: 116 SkASSERT(kOpaque_Alpha != alpha); 117 break; 118 case kPalette_Color: 119 SkASSERT(16 != bitsPerComponent); 120 break; 121 case kRGB_Color: 122 case kBGR_Color: 123 case kBGRX_Color: 124 SkASSERT(kOpaque_Alpha == alpha); 125 SkASSERT(bitsPerComponent >= 8); 126 break; 127 case kYUV_Color: 128 case kInvertedCMYK_Color: 129 case kYCCK_Color: 130 SkASSERT(kOpaque_Alpha == alpha); 131 SkASSERT(8 == bitsPerComponent); 132 break; 133 case kRGBA_Color: 134 SkASSERT(bitsPerComponent >= 8); 135 break; 136 case kBGRA_Color: 137 case kYUVA_Color: 138 SkASSERT(8 == bitsPerComponent); 139 break; 140 case kXAlpha_Color: 141 SkASSERT(kUnpremul_Alpha == alpha); 142 SkASSERT(8 == bitsPerComponent); 143 break; 144 case k565_Color: 145 SkASSERT(kOpaque_Alpha == alpha); 146 SkASSERT(8 == bitsPerComponent); 147 break; 148 default: 149 SkASSERT(false); 150 break; 151 } 152 153 return SkEncodedInfo(width, height, color, alpha, bitsPerComponent, std::move(profile)); 154 } 155 156 /* 157 * Returns a recommended SkImageInfo. 158 * 159 * TODO: Leave this up to the client. 160 */ makeImageInfoSkEncodedInfo161 SkImageInfo makeImageInfo() const { 162 auto ct = kGray_Color == fColor ? kGray_8_SkColorType : 163 kXAlpha_Color == fColor ? kAlpha_8_SkColorType : 164 k565_Color == fColor ? kRGB_565_SkColorType : 165 kN32_SkColorType ; 166 auto alpha = kOpaque_Alpha == fAlpha ? kOpaque_SkAlphaType 167 : kUnpremul_SkAlphaType; 168 sk_sp<SkColorSpace> cs = fProfile ? SkColorSpace::Make(*fProfile->profile()) 169 : nullptr; 170 if (!cs) { 171 cs = SkColorSpace::MakeSRGB(); 172 } 173 return SkImageInfo::Make(fWidth, fHeight, ct, alpha, std::move(cs)); 174 } 175 widthSkEncodedInfo176 int width() const { return fWidth; } heightSkEncodedInfo177 int height() const { return fHeight; } colorSkEncodedInfo178 Color color() const { return fColor; } alphaSkEncodedInfo179 Alpha alpha() const { return fAlpha; } opaqueSkEncodedInfo180 bool opaque() const { return fAlpha == kOpaque_Alpha; } profileSkEncodedInfo181 const skcms_ICCProfile* profile() const { 182 if (!fProfile) return nullptr; 183 return fProfile->profile(); 184 } 185 bitsPerComponentSkEncodedInfo186 uint8_t bitsPerComponent() const { return fBitsPerComponent; } 187 bitsPerPixelSkEncodedInfo188 uint8_t bitsPerPixel() const { 189 switch (fColor) { 190 case kGray_Color: 191 return fBitsPerComponent; 192 case kXAlpha_Color: 193 case kGrayAlpha_Color: 194 return 2 * fBitsPerComponent; 195 case kPalette_Color: 196 return fBitsPerComponent; 197 case kRGB_Color: 198 case kBGR_Color: 199 case kYUV_Color: 200 case k565_Color: 201 return 3 * fBitsPerComponent; 202 case kRGBA_Color: 203 case kBGRA_Color: 204 case kBGRX_Color: 205 case kYUVA_Color: 206 case kInvertedCMYK_Color: 207 case kYCCK_Color: 208 return 4 * fBitsPerComponent; 209 default: 210 SkASSERT(false); 211 return 0; 212 } 213 } 214 215 SkEncodedInfo(const SkEncodedInfo& orig) = delete; 216 SkEncodedInfo& operator=(const SkEncodedInfo&) = delete; 217 218 SkEncodedInfo(SkEncodedInfo&& orig) = default; 219 SkEncodedInfo& operator=(SkEncodedInfo&&) = default; 220 221 // Explicit copy method, to avoid accidental copying. copySkEncodedInfo222 SkEncodedInfo copy() const { 223 auto copy = SkEncodedInfo::Make(fWidth, fHeight, fColor, fAlpha, fBitsPerComponent); 224 if (fProfile) { 225 copy.fProfile = std::make_unique<ICCProfile>(*fProfile); 226 } 227 return copy; 228 } 229 230 private: SkEncodedInfoSkEncodedInfo231 SkEncodedInfo(int width, int height, Color color, Alpha alpha, 232 uint8_t bitsPerComponent, std::unique_ptr<ICCProfile> profile) 233 : fWidth(width) 234 , fHeight(height) 235 , fColor(color) 236 , fAlpha(alpha) 237 , fBitsPerComponent(bitsPerComponent) 238 , fProfile(std::move(profile)) 239 {} 240 241 int fWidth; 242 int fHeight; 243 Color fColor; 244 Alpha fAlpha; 245 uint8_t fBitsPerComponent; 246 std::unique_ptr<ICCProfile> fProfile; 247 }; 248 249 #endif 250