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(kOpaque_Alpha != alpha); 133 SkASSERT(bitsPerComponent >= 8); 134 break; 135 case kBGRA_Color: 136 case kYUVA_Color: 137 SkASSERT(kOpaque_Alpha != alpha); 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.reset(new ICCProfile(*fProfile.get())); 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