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
17struct SkEncodedInfo {
18public:
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
24 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
98 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
103 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 */
161 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
176 int width() const { return fWidth; }
177 int height() const { return fHeight; }
178 Color color() const { return fColor; }
179 Alpha alpha() const { return fAlpha; }
180 bool opaque() const { return fAlpha == kOpaque_Alpha; }
181 const skcms_ICCProfile* profile() const {
182 if (!fProfile) return nullptr;
183 return fProfile->profile();
184 }
185
186 uint8_t bitsPerComponent() const { return fBitsPerComponent; }
187
188 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.
222 SkEncodedInfo copy() const {
223 auto copy = SkEncodedInfo::Make(fWidth, fHeight, fColor, fAlpha, fBitsPerComponent);
224 if (fProfile) {
225 copy.fProfile = std::make_unique<ICCProfile>(*fProfile.get());
226 }
227 return copy;
228 }
229
230private:
231 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