2 * Copyright 2013 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
9 #include "SkDecodingImageGenerator.h"
10 #include "SkImageDecoder.h"
11 #include "SkImageInfo.h"
12 #include "SkImageGenerator.h"
13 #include "SkImagePriv.h"
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();
23 class DecodingImageGenerator : public SkImageGenerator {
25 virtual ~DecodingImageGenerator();
28 SkStreamRewindable* fStream;
29 const SkImageInfo fInfo;
30 const int fSampleSize;
31 const bool fDitherImage;
33 DecodingImageGenerator(SkData* data,
34 SkStreamRewindable* stream,
35 const SkImageInfo& info,
40 virtual SkData* onRefEncodedData() SK_OVERRIDE;
41 virtual bool onGetInfo(SkImageInfo* info) SK_OVERRIDE {
45 virtual bool onGetPixels(const SkImageInfo& info,
46 void* pixels, size_t rowBytes,
47 SkPMColor ctable[], int* ctableCount) SK_OVERRIDE;
50 typedef SkImageGenerator INHERITED;
54 * Special allocator used by getPixels(). Uses preallocated memory
55 * provided if possible, else fall-back on the default allocator
57 class TargetAllocator : public SkBitmap::Allocator {
59 TargetAllocator(const SkImageInfo& info,
67 bool isReady() { return (fTarget != NULL); }
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->allocPixels(NULL, ct);
75 // TODO(halcanary): verify that all callers of this function
76 // will respect new RowBytes. Will be moot once rowbytes belongs
78 bm->installPixels(fInfo, fTarget, fRowBytes, ct, NULL, NULL);
80 fTarget = NULL; // never alloc same pixels twice!
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
91 typedef SkBitmap::Allocator INHERITED;
94 // TODO(halcanary): Give this macro a better name and move it into SkTypes.h
96 #define SkCheckResult(expr, value) SkASSERT((value) == (expr))
98 #define SkCheckResult(expr, value) (void)(expr)
102 inline bool check_alpha(SkAlphaType reported, SkAlphaType actual) {
103 return ((reported == actual)
104 || ((reported == kPremul_SkAlphaType)
105 && (actual == kOpaque_SkAlphaType)));
109 ////////////////////////////////////////////////////////////////////////////////
111 DecodingImageGenerator::DecodingImageGenerator(
113 SkStreamRewindable* stream,
114 const SkImageInfo& info,
120 , fSampleSize(sampleSize)
121 , fDitherImage(ditherImage)
123 SkASSERT(stream != NULL);
124 SkSafeRef(fData); // may be NULL.
127 DecodingImageGenerator::~DecodingImageGenerator() {
132 SkData* DecodingImageGenerator::onRefEncodedData() {
133 // This functionality is used in `gm --serialize`
134 // Does not encode options.
136 return SkSafeRef(fData);
138 // TODO(halcanary): SkStreamRewindable needs a refData() function
139 // which returns a cheap copy of the underlying data.
140 if (!fStream->rewind()) {
143 size_t length = fStream->getLength();
147 void* buffer = sk_malloc_flags(length, 0);
148 SkCheckResult(fStream->read(buffer, length), length);
149 fData = SkData::NewFromMalloc(buffer, length);
150 return SkSafeRef(fData);
153 bool DecodingImageGenerator::onGetPixels(const SkImageInfo& info,
154 void* pixels, size_t rowBytes,
155 SkPMColor ctableEntries[], int* ctableCount) {
157 // The caller has specified a different info. This is an
158 // error for this kind of SkImageGenerator. Use the Options
159 // to change the settings.
163 SkAssertResult(fStream->rewind());
164 SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(fStream));
165 if (NULL == decoder.get()) {
168 decoder->setDitherImage(fDitherImage);
169 decoder->setSampleSize(fSampleSize);
170 decoder->setRequireUnpremultipliedColors(
171 info.fAlphaType == kUnpremul_SkAlphaType);
174 TargetAllocator allocator(fInfo, pixels, rowBytes);
175 decoder->setAllocator(&allocator);
176 bool success = decoder->decode(fStream, &bitmap, info.colorType(),
177 SkImageDecoder::kDecodePixels_Mode);
178 decoder->setAllocator(NULL);
182 if (allocator.isReady()) { // Did not use pixels!
184 SkASSERT(bitmap.canCopyTo(info.colorType()));
185 bool copySuccess = bitmap.copyTo(&bm, info.colorType(), &allocator);
186 if (!copySuccess || allocator.isReady()) {
187 SkDEBUGFAIL("bitmap.copyTo(requestedConfig) failed.");
188 // Earlier we checked canCopyto(); we expect consistency.
191 SkASSERT(check_alpha(info.alphaType(), bm.alphaType()));
193 SkASSERT(check_alpha(info.alphaType(), bitmap.alphaType()));
196 if (kIndex_8_SkColorType == info.colorType()) {
197 if (kIndex_8_SkColorType != bitmap.colorType()) {
198 return false; // they asked for Index8, but we didn't receive that from decoder
200 SkColorTable* ctable = bitmap.getColorTable();
201 if (NULL == ctable) {
204 const int count = ctable->count();
205 memcpy(ctableEntries, ctable->lockColors(), count * sizeof(SkPMColor));
206 ctable->unlockColors();
207 *ctableCount = count;
212 // A contructor-type function that returns NULL on failure. This
213 // prevents the returned SkImageGenerator from ever being in a bad
214 // state. Called by both Create() functions
215 SkImageGenerator* CreateDecodingImageGenerator(
217 SkStreamRewindable* stream,
218 const SkDecodingImageGenerator::Options& opts) {
220 SkAutoTUnref<SkStreamRewindable> autoStream(stream); // always unref this.
221 SkAssertResult(autoStream->rewind());
222 SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(autoStream));
223 if (NULL == decoder.get()) {
227 decoder->setSampleSize(opts.fSampleSize);
228 decoder->setRequireUnpremultipliedColors(opts.fRequireUnpremul);
229 if (!decoder->decode(stream, &bitmap, SkImageDecoder::kDecodeBounds_Mode)) {
232 if (kUnknown_SkColorType == bitmap.colorType()) {
236 SkImageInfo info = bitmap.info();
238 if (opts.fUseRequestedColorType && (opts.fRequestedColorType != info.colorType())) {
239 if (!bitmap.canCopyTo(opts.fRequestedColorType)) {
240 SkASSERT(bitmap.colorType() != opts.fRequestedColorType);
241 return NULL; // Can not translate to needed config.
243 info.fColorType = opts.fRequestedColorType;
246 if (opts.fRequireUnpremul && info.fAlphaType != kOpaque_SkAlphaType) {
247 info.fAlphaType = kUnpremul_SkAlphaType;
249 return SkNEW_ARGS(DecodingImageGenerator,
250 (data, autoStream.detach(), info,
251 opts.fSampleSize, opts.fDitherImage));
256 ////////////////////////////////////////////////////////////////////////////////
258 SkImageGenerator* SkDecodingImageGenerator::Create(
260 const SkDecodingImageGenerator::Options& opts) {
261 SkASSERT(data != NULL);
265 SkStreamRewindable* stream = SkNEW_ARGS(SkMemoryStream, (data));
266 SkASSERT(stream != NULL);
267 SkASSERT(stream->unique());
268 return CreateDecodingImageGenerator(data, stream, opts);
271 SkImageGenerator* SkDecodingImageGenerator::Create(
272 SkStreamRewindable* stream,
273 const SkDecodingImageGenerator::Options& opts) {
274 SkASSERT(stream != NULL);
275 SkASSERT(stream->unique());
276 if ((stream == NULL) || !stream->unique()) {
280 return CreateDecodingImageGenerator(NULL, stream, opts);