1 | /* |
2 | * Copyright 2015 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 SkAndroidCodec_DEFINED |
9 | #define SkAndroidCodec_DEFINED |
10 | |
11 | #include "include/codec/SkCodec.h" |
12 | #include "include/core/SkEncodedImageFormat.h" |
13 | #include "include/core/SkStream.h" |
14 | #include "include/core/SkTypes.h" |
15 | |
16 | /** |
17 | * Abstract interface defining image codec functionality that is necessary for |
18 | * Android. |
19 | */ |
20 | class SK_API SkAndroidCodec : SkNoncopyable { |
21 | public: |
22 | enum class ExifOrientationBehavior { |
23 | /** |
24 | * Ignore any exif orientation markers in the data. |
25 | * |
26 | * getInfo's width and height will match the header of the image, and |
27 | * no processing will be done to match the marker. |
28 | */ |
29 | kIgnore, |
30 | |
31 | /** |
32 | * Respect the exif orientation marker. |
33 | * |
34 | * getInfo's width and height will represent what they should be after |
35 | * applying the orientation. For example, if the marker specifies a |
36 | * rotation by 90 degrees, they will be swapped relative to the header. |
37 | * getAndroidPixels will apply the orientation as well. |
38 | */ |
39 | kRespect, |
40 | }; |
41 | |
42 | /** |
43 | * Pass ownership of an SkCodec to a newly-created SkAndroidCodec. |
44 | */ |
45 | static std::unique_ptr<SkAndroidCodec> MakeFromCodec(std::unique_ptr<SkCodec>, |
46 | ExifOrientationBehavior = ExifOrientationBehavior::kIgnore); |
47 | |
48 | /** |
49 | * If this stream represents an encoded image that we know how to decode, |
50 | * return an SkAndroidCodec that can decode it. Otherwise return NULL. |
51 | * |
52 | * The SkPngChunkReader handles unknown chunks in PNGs. |
53 | * See SkCodec.h for more details. |
54 | * |
55 | * If NULL is returned, the stream is deleted immediately. Otherwise, the |
56 | * SkCodec takes ownership of it, and will delete it when done with it. |
57 | * |
58 | * ExifOrientationBehavior is set to kIgnore. |
59 | */ |
60 | static std::unique_ptr<SkAndroidCodec> MakeFromStream(std::unique_ptr<SkStream>, |
61 | SkPngChunkReader* = nullptr); |
62 | |
63 | /** |
64 | * If this data represents an encoded image that we know how to decode, |
65 | * return an SkAndroidCodec that can decode it. Otherwise return NULL. |
66 | * |
67 | * The SkPngChunkReader handles unknown chunks in PNGs. |
68 | * See SkCodec.h for more details. |
69 | * |
70 | * ExifOrientationBehavior is set to kIgnore. |
71 | */ |
72 | static std::unique_ptr<SkAndroidCodec> MakeFromData(sk_sp<SkData>, SkPngChunkReader* = nullptr); |
73 | |
74 | virtual ~SkAndroidCodec(); |
75 | |
76 | const SkImageInfo& getInfo() const { return fInfo; } |
77 | |
78 | /** |
79 | * Return the ICC profile of the encoded data. |
80 | */ |
81 | const skcms_ICCProfile* getICCProfile() const { |
82 | return fCodec->getEncodedInfo().profile(); |
83 | } |
84 | |
85 | /** |
86 | * Format of the encoded data. |
87 | */ |
88 | SkEncodedImageFormat getEncodedFormat() const { return fCodec->getEncodedFormat(); } |
89 | |
90 | /** |
91 | * @param requestedColorType Color type requested by the client |
92 | * |
93 | * |requestedColorType| may be overriden. We will default to kF16 |
94 | * for high precision images. |
95 | * |
96 | * In the general case, if it is possible to decode to |
97 | * |requestedColorType|, this returns |requestedColorType|. |
98 | * Otherwise, this returns a color type that is an appropriate |
99 | * match for the the encoded data. |
100 | */ |
101 | SkColorType computeOutputColorType(SkColorType requestedColorType); |
102 | |
103 | /** |
104 | * @param requestedUnpremul Indicates if the client requested |
105 | * unpremultiplied output |
106 | * |
107 | * Returns the appropriate alpha type to decode to. If the image |
108 | * has alpha, the value of requestedUnpremul will be honored. |
109 | */ |
110 | SkAlphaType computeOutputAlphaType(bool requestedUnpremul); |
111 | |
112 | /** |
113 | * @param outputColorType Color type that the client will decode to. |
114 | * @param prefColorSpace Preferred color space to decode to. |
115 | * This may not return |prefColorSpace| for a couple reasons. |
116 | * (1) Android Principles: 565 must be sRGB, F16 must be |
117 | * linear sRGB, transfer function must be parametric. |
118 | * (2) Codec Limitations: F16 requires a linear color space. |
119 | * |
120 | * Returns the appropriate color space to decode to. |
121 | */ |
122 | sk_sp<SkColorSpace> computeOutputColorSpace(SkColorType outputColorType, |
123 | sk_sp<SkColorSpace> prefColorSpace = nullptr); |
124 | |
125 | /** |
126 | * Compute the appropriate sample size to get to |size|. |
127 | * |
128 | * @param size As an input parameter, the desired output size of |
129 | * the decode. As an output parameter, the smallest sampled size |
130 | * larger than the input. |
131 | * @return the sample size to set AndroidOptions::fSampleSize to decode |
132 | * to the output |size|. |
133 | */ |
134 | int computeSampleSize(SkISize* size) const; |
135 | |
136 | /** |
137 | * Returns the dimensions of the scaled output image, for an input |
138 | * sampleSize. |
139 | * |
140 | * When the sample size divides evenly into the original dimensions, the |
141 | * scaled output dimensions will simply be equal to the original |
142 | * dimensions divided by the sample size. |
143 | * |
144 | * When the sample size does not divide even into the original |
145 | * dimensions, the codec may round up or down, depending on what is most |
146 | * efficient to decode. |
147 | * |
148 | * Finally, the codec will always recommend a non-zero output, so the output |
149 | * dimension will always be one if the sampleSize is greater than the |
150 | * original dimension. |
151 | */ |
152 | SkISize getSampledDimensions(int sampleSize) const; |
153 | |
154 | /** |
155 | * Return (via desiredSubset) a subset which can decoded from this codec, |
156 | * or false if the input subset is invalid. |
157 | * |
158 | * @param desiredSubset in/out parameter |
159 | * As input, a desired subset of the original bounds |
160 | * (as specified by getInfo). |
161 | * As output, if true is returned, desiredSubset may |
162 | * have been modified to a subset which is |
163 | * supported. Although a particular change may have |
164 | * been made to desiredSubset to create something |
165 | * supported, it is possible other changes could |
166 | * result in a valid subset. If false is returned, |
167 | * desiredSubset's value is undefined. |
168 | * @return true If the input desiredSubset is valid. |
169 | * desiredSubset may be modified to a subset |
170 | * supported by the codec. |
171 | * false If desiredSubset is invalid (NULL or not fully |
172 | * contained within the image). |
173 | */ |
174 | bool getSupportedSubset(SkIRect* desiredSubset) const; |
175 | // TODO: Rename SkCodec::getValidSubset() to getSupportedSubset() |
176 | |
177 | /** |
178 | * Returns the dimensions of the scaled, partial output image, for an |
179 | * input sampleSize and subset. |
180 | * |
181 | * @param sampleSize Factor to scale down by. |
182 | * @param subset Must be a valid subset of the original image |
183 | * dimensions and a subset supported by SkAndroidCodec. |
184 | * getSubset() can be used to obtain a subset supported |
185 | * by SkAndroidCodec. |
186 | * @return Size of the scaled partial image. Or zero size |
187 | * if either of the inputs is invalid. |
188 | */ |
189 | SkISize getSampledSubsetDimensions(int sampleSize, const SkIRect& subset) const; |
190 | |
191 | /** |
192 | * Additional options to pass to getAndroidPixels(). |
193 | */ |
194 | // FIXME: It's a bit redundant to name these AndroidOptions when this class is already |
195 | // called SkAndroidCodec. On the other hand, it's may be a bit confusing to call |
196 | // these Options when SkCodec has a slightly different set of Options. Maybe these |
197 | // should be DecodeOptions or SamplingOptions? |
198 | struct AndroidOptions { |
199 | AndroidOptions() |
200 | : fZeroInitialized(SkCodec::kNo_ZeroInitialized) |
201 | , fSubset(nullptr) |
202 | , fSampleSize(1) |
203 | {} |
204 | |
205 | /** |
206 | * Indicates is destination pixel memory is zero initialized. |
207 | * |
208 | * The default is SkCodec::kNo_ZeroInitialized. |
209 | */ |
210 | SkCodec::ZeroInitialized fZeroInitialized; |
211 | |
212 | /** |
213 | * If not NULL, represents a subset of the original image to decode. |
214 | * |
215 | * Must be within the bounds returned by getInfo(). |
216 | * |
217 | * If the EncodedFormat is SkEncodedImageFormat::kWEBP, the top and left |
218 | * values must be even. |
219 | * |
220 | * The default is NULL, meaning a decode of the entire image. |
221 | */ |
222 | SkIRect* fSubset; |
223 | |
224 | /** |
225 | * The client may provide an integer downscale factor for the decode. |
226 | * The codec may implement this downscaling by sampling or another |
227 | * method if it is more efficient. |
228 | * |
229 | * The default is 1, representing no downscaling. |
230 | */ |
231 | int fSampleSize; |
232 | }; |
233 | |
234 | /** |
235 | * Decode into the given pixels, a block of memory of size at |
236 | * least (info.fHeight - 1) * rowBytes + (info.fWidth * |
237 | * bytesPerPixel) |
238 | * |
239 | * Repeated calls to this function should give the same results, |
240 | * allowing the PixelRef to be immutable. |
241 | * |
242 | * @param info A description of the format (config, size) |
243 | * expected by the caller. This can simply be identical |
244 | * to the info returned by getInfo(). |
245 | * |
246 | * This contract also allows the caller to specify |
247 | * different output-configs, which the implementation can |
248 | * decide to support or not. |
249 | * |
250 | * A size that does not match getInfo() implies a request |
251 | * to scale or subset. If the codec cannot perform this |
252 | * scaling or subsetting, it will return an error code. |
253 | * |
254 | * The AndroidOptions object is also used to specify any requested scaling or subsetting |
255 | * using options->fSampleSize and options->fSubset. If NULL, the defaults (as specified above |
256 | * for AndroidOptions) are used. |
257 | * |
258 | * @return Result kSuccess, or another value explaining the type of failure. |
259 | */ |
260 | // FIXME: It's a bit redundant to name this getAndroidPixels() when this class is already |
261 | // called SkAndroidCodec. On the other hand, it's may be a bit confusing to call |
262 | // this getPixels() when it is a slightly different API than SkCodec's getPixels(). |
263 | // Maybe this should be decode() or decodeSubset()? |
264 | SkCodec::Result getAndroidPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, |
265 | const AndroidOptions* options); |
266 | |
267 | /** |
268 | * Simplified version of getAndroidPixels() where we supply the default AndroidOptions as |
269 | * specified above for AndroidOptions. It will not perform any scaling or subsetting. |
270 | */ |
271 | SkCodec::Result getAndroidPixels(const SkImageInfo& info, void* pixels, size_t rowBytes); |
272 | |
273 | SkCodec::Result getPixels(const SkImageInfo& info, void* pixels, size_t rowBytes) { |
274 | return this->getAndroidPixels(info, pixels, rowBytes); |
275 | } |
276 | |
277 | SkCodec* codec() const { return fCodec.get(); } |
278 | |
279 | protected: |
280 | SkAndroidCodec(SkCodec*, ExifOrientationBehavior = ExifOrientationBehavior::kIgnore); |
281 | |
282 | virtual SkISize onGetSampledDimensions(int sampleSize) const = 0; |
283 | |
284 | virtual bool onGetSupportedSubset(SkIRect* desiredSubset) const = 0; |
285 | |
286 | virtual SkCodec::Result onGetAndroidPixels(const SkImageInfo& info, void* pixels, |
287 | size_t rowBytes, const AndroidOptions& options) = 0; |
288 | |
289 | private: |
290 | const SkImageInfo fInfo; |
291 | const ExifOrientationBehavior fOrientationBehavior; |
292 | std::unique_ptr<SkCodec> fCodec; |
293 | }; |
294 | #endif // SkAndroidCodec_DEFINED |
295 | |