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/SkData.h"
12#include "include/core/SkImageInfo.h"
13#include "include/third_party/skcms/skcms.h"
14
15struct SkEncodedInfo {
16public:
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
22 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
96 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
101 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(bitsPerComponent >= 8);
133 break;
134 case kBGRA_Color:
135 case kYUVA_Color:
136 SkASSERT(8 == bitsPerComponent);
137 break;
138 case kXAlpha_Color:
139 SkASSERT(kUnpremul_Alpha == alpha);
140 SkASSERT(8 == bitsPerComponent);
141 break;
142 case k565_Color:
143 SkASSERT(kOpaque_Alpha == alpha);
144 SkASSERT(8 == bitsPerComponent);
145 break;
146 default:
147 SkASSERT(false);
148 break;
149 }
150
151 return SkEncodedInfo(width, height, color, alpha, bitsPerComponent, std::move(profile));
152 }
153
154 /*
155 * Returns a recommended SkImageInfo.
156 *
157 * TODO: Leave this up to the client.
158 */
159 SkImageInfo makeImageInfo() const {
160 auto ct = kGray_Color == fColor ? kGray_8_SkColorType :
161 kXAlpha_Color == fColor ? kAlpha_8_SkColorType :
162 k565_Color == fColor ? kRGB_565_SkColorType :
163 kN32_SkColorType ;
164 auto alpha = kOpaque_Alpha == fAlpha ? kOpaque_SkAlphaType
165 : kUnpremul_SkAlphaType;
166 sk_sp<SkColorSpace> cs = fProfile ? SkColorSpace::Make(*fProfile->profile())
167 : nullptr;
168 if (!cs) {
169 cs = SkColorSpace::MakeSRGB();
170 }
171 return SkImageInfo::Make(fWidth, fHeight, ct, alpha, std::move(cs));
172 }
173
174 int width() const { return fWidth; }
175 int height() const { return fHeight; }
176 Color color() const { return fColor; }
177 Alpha alpha() const { return fAlpha; }
178 bool opaque() const { return fAlpha == kOpaque_Alpha; }
179 const skcms_ICCProfile* profile() const {
180 if (!fProfile) return nullptr;
181 return fProfile->profile();
182 }
183
184 uint8_t bitsPerComponent() const { return fBitsPerComponent; }
185
186 uint8_t bitsPerPixel() const {
187 switch (fColor) {
188 case kGray_Color:
189 return fBitsPerComponent;
190 case kXAlpha_Color:
191 case kGrayAlpha_Color:
192 return 2 * fBitsPerComponent;
193 case kPalette_Color:
194 return fBitsPerComponent;
195 case kRGB_Color:
196 case kBGR_Color:
197 case kYUV_Color:
198 case k565_Color:
199 return 3 * fBitsPerComponent;
200 case kRGBA_Color:
201 case kBGRA_Color:
202 case kBGRX_Color:
203 case kYUVA_Color:
204 case kInvertedCMYK_Color:
205 case kYCCK_Color:
206 return 4 * fBitsPerComponent;
207 default:
208 SkASSERT(false);
209 return 0;
210 }
211 }
212
213 SkEncodedInfo(const SkEncodedInfo& orig) = delete;
214 SkEncodedInfo& operator=(const SkEncodedInfo&) = delete;
215
216 SkEncodedInfo(SkEncodedInfo&& orig) = default;
217 SkEncodedInfo& operator=(SkEncodedInfo&&) = default;
218
219 // Explicit copy method, to avoid accidental copying.
220 SkEncodedInfo copy() const {
221 auto copy = SkEncodedInfo::Make(fWidth, fHeight, fColor, fAlpha, fBitsPerComponent);
222 if (fProfile) {
223 copy.fProfile.reset(new ICCProfile(*fProfile.get()));
224 }
225 return copy;
226 }
227
228private:
229 SkEncodedInfo(int width, int height, Color color, Alpha alpha,
230 uint8_t bitsPerComponent, std::unique_ptr<ICCProfile> profile)
231 : fWidth(width)
232 , fHeight(height)
233 , fColor(color)
234 , fAlpha(alpha)
235 , fBitsPerComponent(bitsPerComponent)
236 , fProfile(std::move(profile))
237 {}
238
239 int fWidth;
240 int fHeight;
241 Color fColor;
242 Alpha fAlpha;
243 uint8_t fBitsPerComponent;
244 std::unique_ptr<ICCProfile> fProfile;
245};
246
247#endif
248