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