• 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 <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