• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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