• 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,
104             Alpha alpha, int bitsPerComponent, std::unique_ptr<ICCProfile> profile) {
105         return Make(width, height, color, alpha, /*bitsPerComponent*/ bitsPerComponent,
106                 std::move(profile), /*colorDepth*/ bitsPerComponent);
107     }
108 
MakeSkEncodedInfo109     static SkEncodedInfo Make(int width, int height, Color color,
110             Alpha alpha, int bitsPerComponent, std::unique_ptr<ICCProfile> profile,
111             int colorDepth) {
112         SkASSERT(1 == bitsPerComponent ||
113                  2 == bitsPerComponent ||
114                  4 == bitsPerComponent ||
115                  8 == bitsPerComponent ||
116                  16 == bitsPerComponent);
117 
118         switch (color) {
119             case kGray_Color:
120                 SkASSERT(kOpaque_Alpha == alpha);
121                 break;
122             case kGrayAlpha_Color:
123                 SkASSERT(kOpaque_Alpha != alpha);
124                 break;
125             case kPalette_Color:
126                 SkASSERT(16 != bitsPerComponent);
127                 break;
128             case kRGB_Color:
129             case kBGR_Color:
130             case kBGRX_Color:
131                 SkASSERT(kOpaque_Alpha == alpha);
132                 SkASSERT(bitsPerComponent >= 8);
133                 break;
134             case kYUV_Color:
135             case kInvertedCMYK_Color:
136             case kYCCK_Color:
137                 SkASSERT(kOpaque_Alpha == alpha);
138                 SkASSERT(8 == bitsPerComponent);
139                 break;
140             case kRGBA_Color:
141                 SkASSERT(bitsPerComponent >= 8);
142                 break;
143             case kBGRA_Color:
144             case kYUVA_Color:
145                 SkASSERT(8 == bitsPerComponent);
146                 break;
147             case kXAlpha_Color:
148                 SkASSERT(kUnpremul_Alpha == alpha);
149                 SkASSERT(8 == bitsPerComponent);
150                 break;
151             case k565_Color:
152                 SkASSERT(kOpaque_Alpha == alpha);
153                 SkASSERT(8 == bitsPerComponent);
154                 break;
155             default:
156                 SkASSERT(false);
157                 break;
158         }
159 
160         return SkEncodedInfo(width, height, color, alpha,
161                 bitsPerComponent, colorDepth, std::move(profile));
162     }
163 
164     /*
165      * Returns a recommended SkImageInfo.
166      *
167      * TODO: Leave this up to the client.
168      */
makeImageInfoSkEncodedInfo169     SkImageInfo makeImageInfo() const {
170         auto ct =  kGray_Color == fColor ? kGray_8_SkColorType   :
171                  kXAlpha_Color == fColor ? kAlpha_8_SkColorType  :
172                     k565_Color == fColor ? kRGB_565_SkColorType  :
173                                            kN32_SkColorType      ;
174         auto alpha = kOpaque_Alpha == fAlpha ? kOpaque_SkAlphaType
175                                              : kUnpremul_SkAlphaType;
176         sk_sp<SkColorSpace> cs = fProfile ? SkColorSpace::Make(*fProfile->profile())
177                                           : nullptr;
178         if (!cs) {
179             cs = SkColorSpace::MakeSRGB();
180         }
181         return SkImageInfo::Make(fWidth, fHeight, ct, alpha, std::move(cs));
182     }
183 
widthSkEncodedInfo184     int   width() const { return fWidth;  }
heightSkEncodedInfo185     int  height() const { return fHeight; }
colorSkEncodedInfo186     Color color() const { return fColor;  }
alphaSkEncodedInfo187     Alpha alpha() const { return fAlpha;  }
opaqueSkEncodedInfo188     bool opaque() const { return fAlpha == kOpaque_Alpha; }
profileSkEncodedInfo189     const skcms_ICCProfile* profile() const {
190         if (!fProfile) return nullptr;
191         return fProfile->profile();
192     }
193 
bitsPerComponentSkEncodedInfo194     uint8_t bitsPerComponent() const { return fBitsPerComponent; }
195 
bitsPerPixelSkEncodedInfo196     uint8_t bitsPerPixel() const {
197         switch (fColor) {
198             case kGray_Color:
199                 return fBitsPerComponent;
200             case kXAlpha_Color:
201             case kGrayAlpha_Color:
202                 return 2 * fBitsPerComponent;
203             case kPalette_Color:
204                 return fBitsPerComponent;
205             case kRGB_Color:
206             case kBGR_Color:
207             case kYUV_Color:
208             case k565_Color:
209                 return 3 * fBitsPerComponent;
210             case kRGBA_Color:
211             case kBGRA_Color:
212             case kBGRX_Color:
213             case kYUVA_Color:
214             case kInvertedCMYK_Color:
215             case kYCCK_Color:
216                 return 4 * fBitsPerComponent;
217             default:
218                 SkASSERT(false);
219                 return 0;
220         }
221     }
222 
223     SkEncodedInfo(const SkEncodedInfo& orig) = delete;
224     SkEncodedInfo& operator=(const SkEncodedInfo&) = delete;
225 
226     SkEncodedInfo(SkEncodedInfo&& orig) = default;
227     SkEncodedInfo& operator=(SkEncodedInfo&&) = default;
228 
229     // Explicit copy method, to avoid accidental copying.
copySkEncodedInfo230     SkEncodedInfo copy() const {
231         auto copy = SkEncodedInfo::Make(
232                 fWidth, fHeight, fColor, fAlpha, fBitsPerComponent, nullptr, fColorDepth);
233         if (fProfile) {
234             copy.fProfile = std::make_unique<ICCProfile>(*fProfile);
235         }
236         return copy;
237     }
238 
239     // Return number of bits of R/G/B channel
getColorDepthSkEncodedInfo240     uint8_t getColorDepth() const {
241         return fColorDepth;
242     }
243 
244 private:
SkEncodedInfoSkEncodedInfo245     SkEncodedInfo(int width, int height, Color color, Alpha alpha,
246             uint8_t bitsPerComponent, uint8_t colorDepth, std::unique_ptr<ICCProfile> profile)
247         : fWidth(width)
248         , fHeight(height)
249         , fColor(color)
250         , fAlpha(alpha)
251         , fBitsPerComponent(bitsPerComponent)
252         , fColorDepth(colorDepth)
253         , fProfile(std::move(profile))
254     {}
255 
256     int                         fWidth;
257     int                         fHeight;
258     Color                       fColor;
259     Alpha                       fAlpha;
260     uint8_t                     fBitsPerComponent;
261     uint8_t                     fColorDepth;
262     std::unique_ptr<ICCProfile> fProfile;
263 };
264 
265 #endif
266