1 /*
2 * Copyright 2013 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 #include "SkData.h"
9 #include "SkDecodingImageGenerator.h"
10 #include "SkImageDecoder.h"
11 #include "SkImageInfo.h"
12 #include "SkImageGenerator.h"
13 #include "SkImagePriv.h"
14 #include "SkStream.h"
15 #include "SkUtils.h"
16
17 namespace {
equal_modulo_alpha(const SkImageInfo & a,const SkImageInfo & b)18 bool equal_modulo_alpha(const SkImageInfo& a, const SkImageInfo& b) {
19 return a.width() == b.width() && a.height() == b.height() &&
20 a.colorType() == b.colorType();
21 }
22
23 class DecodingImageGenerator : public SkImageGenerator {
24 public:
25 virtual ~DecodingImageGenerator();
26
27 SkData* fData;
28 SkAutoTDelete<SkStreamRewindable> fStream;
29 const SkImageInfo fInfo;
30 const int fSampleSize;
31 const bool fDitherImage;
32
33 DecodingImageGenerator(SkData* data,
34 SkStreamRewindable* stream,
35 const SkImageInfo& info,
36 int sampleSize,
37 bool ditherImage);
38
39 protected:
40 SkData* onRefEncodedData() override;
41 Result onGetPixels(const SkImageInfo& info,
42 void* pixels, size_t rowBytes, const Options&,
43 SkPMColor ctable[], int* ctableCount) override;
44 bool onGetYUV8Planes(SkISize sizes[3], void* planes[3], size_t rowBytes[3],
45 SkYUVColorSpace* colorSpace) override;
46
47 private:
48 typedef SkImageGenerator INHERITED;
49 };
50
51 /**
52 * Special allocator used by getPixels(). Uses preallocated memory
53 * provided if possible, else fall-back on the default allocator
54 */
55 class TargetAllocator : public SkBitmap::Allocator {
56 public:
TargetAllocator(const SkImageInfo & info,void * target,size_t rowBytes)57 TargetAllocator(const SkImageInfo& info,
58 void* target,
59 size_t rowBytes)
60 : fInfo(info)
61 , fTarget(target)
62 , fRowBytes(rowBytes)
63 {}
64
isReady()65 bool isReady() { return (fTarget != NULL); }
66
allocPixelRef(SkBitmap * bm,SkColorTable * ct)67 virtual bool allocPixelRef(SkBitmap* bm, SkColorTable* ct) {
68 if (NULL == fTarget || !equal_modulo_alpha(fInfo, bm->info())) {
69 // Call default allocator.
70 return bm->tryAllocPixels(NULL, ct);
71 }
72
73 // TODO(halcanary): verify that all callers of this function
74 // will respect new RowBytes. Will be moot once rowbytes belongs
75 // to PixelRef.
76 bm->installPixels(fInfo, fTarget, fRowBytes, ct, NULL, NULL);
77
78 fTarget = NULL; // never alloc same pixels twice!
79 return true;
80 }
81
82 private:
83 const SkImageInfo fInfo;
84 void* fTarget; // Block of memory to be supplied as pixel memory
85 // in allocPixelRef. Must be large enough to hold
86 // a bitmap described by fInfo and fRowBytes
87 const size_t fRowBytes; // rowbytes for the destination bitmap
88
89 typedef SkBitmap::Allocator INHERITED;
90 };
91
92 // TODO(halcanary): Give this macro a better name and move it into SkTypes.h
93 #ifdef SK_DEBUG
94 #define SkCheckResult(expr, value) SkASSERT((value) == (expr))
95 #else
96 #define SkCheckResult(expr, value) (void)(expr)
97 #endif
98
99 #ifdef SK_DEBUG
check_alpha(SkAlphaType reported,SkAlphaType actual)100 inline bool check_alpha(SkAlphaType reported, SkAlphaType actual) {
101 return ((reported == actual)
102 || ((reported == kPremul_SkAlphaType)
103 && (actual == kOpaque_SkAlphaType)));
104 }
105 #endif // SK_DEBUG
106
107 ////////////////////////////////////////////////////////////////////////////////
108
DecodingImageGenerator(SkData * data,SkStreamRewindable * stream,const SkImageInfo & info,int sampleSize,bool ditherImage)109 DecodingImageGenerator::DecodingImageGenerator(
110 SkData* data,
111 SkStreamRewindable* stream,
112 const SkImageInfo& info,
113 int sampleSize,
114 bool ditherImage)
115 : INHERITED(info)
116 , fData(data)
117 , fStream(stream)
118 , fInfo(info)
119 , fSampleSize(sampleSize)
120 , fDitherImage(ditherImage)
121 {
122 SkASSERT(stream != NULL);
123 SkSafeRef(fData); // may be NULL.
124 }
125
~DecodingImageGenerator()126 DecodingImageGenerator::~DecodingImageGenerator() {
127 SkSafeUnref(fData);
128 }
129
onRefEncodedData()130 SkData* DecodingImageGenerator::onRefEncodedData() {
131 // This functionality is used in `gm --serialize`
132 // Does not encode options.
133 if (NULL == fData) {
134 // TODO(halcanary): SkStreamRewindable needs a refData() function
135 // which returns a cheap copy of the underlying data.
136 if (!fStream->rewind()) {
137 return NULL;
138 }
139 size_t length = fStream->getLength();
140 if (length) {
141 fData = SkData::NewFromStream(fStream, length);
142 }
143 }
144 return SkSafeRef(fData);
145 }
146
onGetPixels(const SkImageInfo & info,void * pixels,size_t rowBytes,const Options & options,SkPMColor ctableEntries[],int * ctableCount)147 SkImageGenerator::Result DecodingImageGenerator::onGetPixels(const SkImageInfo& info,
148 void* pixels, size_t rowBytes, const Options& options, SkPMColor ctableEntries[],
149 int* ctableCount) {
150 if (fInfo != info) {
151 // The caller has specified a different info. This is an
152 // error for this kind of SkImageGenerator. Use the Options
153 // to change the settings.
154 if (info.dimensions() != fInfo.dimensions()) {
155 return kInvalidScale;
156 }
157 return kInvalidConversion;
158 }
159
160 SkAssertResult(fStream->rewind());
161 SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(fStream));
162 if (NULL == decoder.get()) {
163 return kInvalidInput;
164 }
165 decoder->setDitherImage(fDitherImage);
166 decoder->setSampleSize(fSampleSize);
167 decoder->setRequireUnpremultipliedColors(info.alphaType() == kUnpremul_SkAlphaType);
168
169 SkBitmap bitmap;
170 TargetAllocator allocator(fInfo, pixels, rowBytes);
171 decoder->setAllocator(&allocator);
172 const SkImageDecoder::Result decodeResult = decoder->decode(fStream, &bitmap, info.colorType(),
173 SkImageDecoder::kDecodePixels_Mode);
174 decoder->setAllocator(NULL);
175 if (SkImageDecoder::kFailure == decodeResult) {
176 return kInvalidInput;
177 }
178 if (allocator.isReady()) { // Did not use pixels!
179 SkBitmap bm;
180 SkASSERT(bitmap.canCopyTo(info.colorType()));
181 bool copySuccess = bitmap.copyTo(&bm, info.colorType(), &allocator);
182 if (!copySuccess || allocator.isReady()) {
183 SkDEBUGFAIL("bitmap.copyTo(requestedConfig) failed.");
184 // Earlier we checked canCopyto(); we expect consistency.
185 return kInvalidConversion;
186 }
187 SkASSERT(check_alpha(info.alphaType(), bm.alphaType()));
188 } else {
189 SkASSERT(check_alpha(info.alphaType(), bitmap.alphaType()));
190 }
191
192 if (kIndex_8_SkColorType == info.colorType()) {
193 if (kIndex_8_SkColorType != bitmap.colorType()) {
194 // they asked for Index8, but we didn't receive that from decoder
195 return kInvalidConversion;
196 }
197 SkColorTable* ctable = bitmap.getColorTable();
198 if (NULL == ctable) {
199 return kInvalidConversion;
200 }
201 const int count = ctable->count();
202 memcpy(ctableEntries, ctable->readColors(), count * sizeof(SkPMColor));
203 *ctableCount = count;
204 }
205 if (SkImageDecoder::kPartialSuccess == decodeResult) {
206 return kIncompleteInput;
207 }
208 return kSuccess;
209 }
210
onGetYUV8Planes(SkISize sizes[3],void * planes[3],size_t rowBytes[3],SkYUVColorSpace * colorSpace)211 bool DecodingImageGenerator::onGetYUV8Planes(SkISize sizes[3], void* planes[3],
212 size_t rowBytes[3], SkYUVColorSpace* colorSpace) {
213 if (!fStream->rewind()) {
214 return false;
215 }
216
217 SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(fStream));
218 if (NULL == decoder.get()) {
219 return false;
220 }
221
222 return decoder->decodeYUV8Planes(fStream, sizes, planes, rowBytes, colorSpace);
223 }
224
225 // A contructor-type function that returns NULL on failure. This
226 // prevents the returned SkImageGenerator from ever being in a bad
227 // state. Called by both Create() functions
CreateDecodingImageGenerator(SkData * data,SkStreamRewindable * stream,const SkDecodingImageGenerator::Options & opts)228 SkImageGenerator* CreateDecodingImageGenerator(
229 SkData* data,
230 SkStreamRewindable* stream,
231 const SkDecodingImageGenerator::Options& opts) {
232 SkASSERT(stream);
233 SkAutoTDelete<SkStreamRewindable> autoStream(stream); // always delete this
234 SkAssertResult(autoStream->rewind());
235 SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(autoStream));
236 if (NULL == decoder.get()) {
237 return NULL;
238 }
239 SkBitmap bitmap;
240 decoder->setSampleSize(opts.fSampleSize);
241 decoder->setRequireUnpremultipliedColors(opts.fRequireUnpremul);
242 if (!decoder->decode(stream, &bitmap, SkImageDecoder::kDecodeBounds_Mode)) {
243 return NULL;
244 }
245 if (kUnknown_SkColorType == bitmap.colorType()) {
246 return NULL;
247 }
248
249 SkImageInfo info = bitmap.info();
250
251 if (opts.fUseRequestedColorType && (opts.fRequestedColorType != info.colorType())) {
252 if (!bitmap.canCopyTo(opts.fRequestedColorType)) {
253 SkASSERT(bitmap.colorType() != opts.fRequestedColorType);
254 return NULL; // Can not translate to needed config.
255 }
256 info = info.makeColorType(opts.fRequestedColorType);
257 }
258
259 if (opts.fRequireUnpremul && info.alphaType() != kOpaque_SkAlphaType) {
260 info = info.makeAlphaType(kUnpremul_SkAlphaType);
261 }
262
263 SkAlphaType newAlphaType = info.alphaType();
264 if (!SkColorTypeValidateAlphaType(info.colorType(), info.alphaType(), &newAlphaType)) {
265 return NULL;
266 }
267
268 return SkNEW_ARGS(DecodingImageGenerator,
269 (data, autoStream.detach(), info.makeAlphaType(newAlphaType),
270 opts.fSampleSize, opts.fDitherImage));
271 }
272
273 } // namespace
274
275 ////////////////////////////////////////////////////////////////////////////////
276
Create(SkData * data,const SkDecodingImageGenerator::Options & opts)277 SkImageGenerator* SkDecodingImageGenerator::Create(
278 SkData* data,
279 const SkDecodingImageGenerator::Options& opts) {
280 SkASSERT(data != NULL);
281 if (NULL == data) {
282 return NULL;
283 }
284 SkStreamRewindable* stream = SkNEW_ARGS(SkMemoryStream, (data));
285 SkASSERT(stream != NULL);
286 return CreateDecodingImageGenerator(data, stream, opts);
287 }
288
Create(SkStreamRewindable * stream,const SkDecodingImageGenerator::Options & opts)289 SkImageGenerator* SkDecodingImageGenerator::Create(
290 SkStreamRewindable* stream,
291 const SkDecodingImageGenerator::Options& opts) {
292 SkASSERT(stream != NULL);
293 if (stream == NULL) {
294 return NULL;
295 }
296 return CreateDecodingImageGenerator(NULL, stream, opts);
297 }
298