OLD | NEW |
| (Empty) |
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 SkScanlineDecoder_DEFINED | |
9 #define SkScanlineDecoder_DEFINED | |
10 | |
11 #include "../private/SkTemplates.h" | |
12 #include "SkCodec.h" | |
13 #include "SkImageInfo.h" | |
14 #include "SkTypes.h" | |
15 | |
16 class SkScanlineDecoder : public SkNoncopyable { | |
17 public: | |
18 /** | |
19 * If this stream represents an encoded image that we know how to decode | |
20 * in scanlines, return an SkScanlineDecoder that can decode it. Otherwise | |
21 * return NULL. | |
22 * | |
23 * start() must be called in order to decode any scanlines. | |
24 * | |
25 * If NULL is returned, the stream is deleted immediately. Otherwise, the | |
26 * SkScanlineDecoder takes ownership of it, and will delete it when done | |
27 * with it. | |
28 */ | |
29 static SkScanlineDecoder* NewFromStream(SkStream*); | |
30 | |
31 /** | |
32 * Similar to NewFromStream, but reads from an SkData. | |
33 * | |
34 * Will take a ref if it returns a scanline decoder, else will not affect | |
35 * the data. | |
36 */ | |
37 static SkScanlineDecoder* NewFromData(SkData*); | |
38 | |
39 /** | |
40 * Clean up after reading/skipping scanlines. | |
41 * | |
42 * It is possible that not all scanlines will have been read/skipped. In | |
43 * fact, in the case of subset decodes, it is likely that there will be | |
44 * scanlines at the bottom of the image that have been ignored. | |
45 */ | |
46 virtual ~SkScanlineDecoder() {} | |
47 | |
48 /** | |
49 * Return a size that approximately supports the desired scale factor. | |
50 * The codec may not be able to scale efficiently to the exact scale | |
51 * factor requested, so return a size that approximates that scale. | |
52 * The returned value is the codec's suggestion for the closest valid | |
53 * scale that it can natively support | |
54 * FIXME: share this with SkCodec | |
55 */ | |
56 SkISize getScaledDimensions(float desiredScale) { | |
57 return this->onGetScaledDimensions(desiredScale); | |
58 } | |
59 | |
60 /** | |
61 * Returns the default info, corresponding to the encoded data. | |
62 */ | |
63 const SkImageInfo& getInfo() { return fSrcInfo; } | |
64 | |
65 /** | |
66 * Initialize on the first scanline, with the specified options. | |
67 * | |
68 * This must be called in order to call getScanlnies or skipScanlines. If | |
69 * it has been called before, this will require rewinding the stream. | |
70 * | |
71 * @param dstInfo Info of the destination. If the dimensions do not match | |
72 * those of getInfo, this implies a scale. | |
73 * @param options Contains decoding options, including if memory is zero | |
74 * initialized. | |
75 * @param ctable A pointer to a color table. When dstInfo.colorType() is | |
76 * kIndex8, this should be non-NULL and have enough storage for 256 | |
77 * colors. The color table will be populated after decoding the palett
e. | |
78 * @param ctableCount A pointer to the size of the color table. When | |
79 * dstInfo.colorType() is kIndex8, this should be non-NULL. It will | |
80 * be modified to the true size of the color table (<= 256) after | |
81 * decoding the palette. | |
82 * @return Enum representing success or reason for failure. | |
83 */ | |
84 SkCodec::Result start(const SkImageInfo& dstInfo, const SkCodec::Options* op
tions, | |
85 SkPMColor ctable[], int* ctableCount); | |
86 | |
87 /** | |
88 * Simplified version of start() that asserts that info is NOT | |
89 * kIndex8_SkColorType and uses the default Options. | |
90 */ | |
91 SkCodec::Result start(const SkImageInfo& dstInfo); | |
92 | |
93 /** | |
94 * Write the next countLines scanlines into dst. | |
95 * | |
96 * Not valid to call before calling start(). | |
97 * | |
98 * @param dst Must be non-null, and large enough to hold countLines | |
99 * scanlines of size rowBytes. | |
100 * @param countLines Number of lines to write. | |
101 * @param rowBytes Number of bytes per row. Must be large enough to hold | |
102 * a scanline based on the SkImageInfo used to create this object. | |
103 */ | |
104 SkCodec::Result getScanlines(void* dst, int countLines, size_t rowBytes) { | |
105 SkASSERT(!fDstInfo.isEmpty()); | |
106 if ((rowBytes < fDstInfo.minRowBytes() && countLines > 1 ) || countLines
<= 0 | |
107 || fCurrScanline + countLines > fDstInfo.height()) { | |
108 return SkCodec::kInvalidParameters; | |
109 } | |
110 const SkCodec::Result result = this->onGetScanlines(dst, countLines, row
Bytes); | |
111 fCurrScanline += countLines; | |
112 return result; | |
113 } | |
114 | |
115 /** | |
116 * Skip count scanlines. | |
117 * | |
118 * Not valid to call before calling start(). | |
119 * | |
120 * The default version just calls onGetScanlines and discards the dst. | |
121 * NOTE: If skipped lines are the only lines with alpha, this default | |
122 * will make reallyHasAlpha return true, when it could have returned | |
123 * false. | |
124 */ | |
125 SkCodec::Result skipScanlines(int countLines) { | |
126 SkASSERT(!fDstInfo.isEmpty()); | |
127 if (fCurrScanline + countLines > fDstInfo.height()) { | |
128 // Arguably, we could just skip the scanlines which are remaining, | |
129 // and return kSuccess. We choose to return invalid so the client | |
130 // can catch their bug. | |
131 return SkCodec::kInvalidParameters; | |
132 } | |
133 const SkCodec::Result result = this->onSkipScanlines(countLines); | |
134 fCurrScanline += countLines; | |
135 return result; | |
136 } | |
137 | |
138 /** | |
139 * Some images may initially report that they have alpha due to the format | |
140 * of the encoded data, but then never use any colors which have alpha | |
141 * less than 100%. This function can be called *after* decoding to | |
142 * determine if such an image truly had alpha. Calling it before decoding | |
143 * is undefined. | |
144 * FIXME: see skbug.com/3582. | |
145 */ | |
146 bool reallyHasAlpha() const { | |
147 return this->onReallyHasAlpha(); | |
148 } | |
149 | |
150 /** | |
151 * Format of the encoded data. | |
152 */ | |
153 SkEncodedFormat getEncodedFormat() const { return this->onGetEncodedFormat()
; } | |
154 | |
155 /** | |
156 * The order in which rows are output from the scanline decoder is not the | |
157 * same for all variations of all image types. This explains the possible | |
158 * output row orderings. | |
159 */ | |
160 enum SkScanlineOrder { | |
161 /* | |
162 * By far the most common, this indicates that the image can be decoded | |
163 * reliably using the scanline decoder, and that rows will be output in | |
164 * the logical order. | |
165 */ | |
166 kTopDown_SkScanlineOrder, | |
167 | |
168 /* | |
169 * This indicates that the scanline decoder reliably outputs rows, but | |
170 * they will be returned in reverse order. If the scanline format is | |
171 * kBottomUp, the getY() API can be used to determine the actual | |
172 * y-coordinate of the next output row, but the client is not forced | |
173 * to take advantage of this, given that it's not too tough to keep | |
174 * track independently. | |
175 * | |
176 * For full image decodes, it is safe to get all of the scanlines at | |
177 * once, since the decoder will handle inverting the rows as it | |
178 * decodes. | |
179 * | |
180 * For subset decodes and sampling, it is simplest to get and skip | |
181 * scanlines one at a time, using the getY() API. It is possible to | |
182 * ask for larger chunks at a time, but this should be used with | |
183 * caution. As with full image decodes, the decoder will handle | |
184 * inverting the requested rows, but rows will still be delivered | |
185 * starting from the bottom of the image. | |
186 * | |
187 * Upside down bmps are an example. | |
188 */ | |
189 kBottomUp_SkScanlineOrder, | |
190 | |
191 /* | |
192 * This indicates that the scanline decoder reliably outputs rows, but | |
193 * they will not be in logical order. If the scanline format is | |
194 * kOutOfOrder, the getY() API should be used to determine the actual | |
195 * y-coordinate of the next output row. | |
196 * | |
197 * For this scanline ordering, it is advisable to get and skip | |
198 * scanlines one at a time. | |
199 * | |
200 * Interlaced gifs are an example. | |
201 */ | |
202 kOutOfOrder_SkScanlineOrder, | |
203 | |
204 /* | |
205 * Indicates that the entire image must be decoded in order to output | |
206 * any amount of scanlines. In this case, it is a REALLY BAD IDEA to | |
207 * request scanlines 1-by-1 or in small chunks. The client should | |
208 * determine which scanlines are needed and ask for all of them in | |
209 * a single call to getScanlines(). | |
210 * | |
211 * Interlaced pngs are an example. | |
212 */ | |
213 kNone_SkScanlineOrder, | |
214 }; | |
215 | |
216 /** | |
217 * An enum representing the order in which scanlines will be returned by | |
218 * the scanline decoder. | |
219 */ | |
220 SkScanlineOrder getScanlineOrder() const { return this->onGetScanlineOrder()
; } | |
221 | |
222 /** | |
223 * Returns the y-coordinate of the next row to be returned by the scanline | |
224 * decoder. This will be overridden in the case of | |
225 * kOutOfOrder_SkScanlineOrder and should be unnecessary in the case of | |
226 * kNone_SkScanlineOrder. | |
227 */ | |
228 int getY() const { | |
229 SkASSERT(kNone_SkScanlineOrder != this->getScanlineOrder()); | |
230 return this->onGetY(); | |
231 } | |
232 | |
233 protected: | |
234 SkScanlineDecoder(const SkImageInfo& srcInfo) | |
235 : fSrcInfo(srcInfo) | |
236 , fDstInfo() | |
237 , fOptions() | |
238 , fCurrScanline(0) {} | |
239 | |
240 virtual SkISize onGetScaledDimensions(float /* desiredScale */) { | |
241 // By default, scaling is not supported. | |
242 return this->getInfo().dimensions(); | |
243 } | |
244 | |
245 virtual SkEncodedFormat onGetEncodedFormat() const = 0; | |
246 | |
247 virtual bool onReallyHasAlpha() const { return false; } | |
248 | |
249 /** | |
250 * Most images types will be kTopDown and will not need to override this fu
nction. | |
251 */ | |
252 virtual SkScanlineOrder onGetScanlineOrder() const { return kTopDown_SkScanl
ineOrder; } | |
253 | |
254 /** | |
255 * Most images will be kTopDown and will not need to override this function
. | |
256 */ | |
257 virtual int onGetY() const { return fCurrScanline; } | |
258 | |
259 const SkImageInfo& dstInfo() const { return fDstInfo; } | |
260 | |
261 const SkCodec::Options& options() const { return fOptions; } | |
262 | |
263 private: | |
264 const SkImageInfo fSrcInfo; | |
265 SkImageInfo fDstInfo; | |
266 SkCodec::Options fOptions; | |
267 int fCurrScanline; | |
268 | |
269 virtual SkCodec::Result onStart(const SkImageInfo& dstInfo, | |
270 const SkCodec::Options& options, | |
271 SkPMColor ctable[], int* ctableCount) = 0; | |
272 | |
273 // Naive default version just calls onGetScanlines on temp memory. | |
274 virtual SkCodec::Result onSkipScanlines(int countLines) { | |
275 SkAutoMalloc storage(fDstInfo.minRowBytes()); | |
276 // Note that we pass 0 to rowBytes so we continue to use the same memory
. | |
277 // Also note that while getScanlines checks that rowBytes is big enough, | |
278 // onGetScanlines bypasses that check. | |
279 // Calling the virtual method also means we do not double count | |
280 // countLines. | |
281 return this->onGetScanlines(storage.get(), countLines, 0); | |
282 } | |
283 | |
284 virtual SkCodec::Result onGetScanlines(void* dst, int countLines, | |
285 size_t rowBytes) = 0; | |
286 | |
287 }; | |
288 #endif // SkScanlineDecoder_DEFINED | |
OLD | NEW |