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 SkAutoTDelete<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 SkData* onRefEncodedData() override;
41 #ifdef SK_SUPPORT_LEGACY_BOOL_ONGETINFO
42 bool onGetInfo(SkImageInfo* info) override {
47 virtual Result onGetPixels(const SkImageInfo& info,
48 void* pixels, size_t rowBytes, const Options&,
49 SkPMColor ctable[], int* ctableCount) override;
50 virtual bool onGetYUV8Planes(SkISize sizes[3], void* planes[3], size_t rowBytes[3],
51 SkYUVColorSpace* colorSpace) override;
54 typedef SkImageGenerator INHERITED;
58 * Special allocator used by getPixels(). Uses preallocated memory
59 * provided if possible, else fall-back on the default allocator
61 class TargetAllocator : public SkBitmap::Allocator {
63 TargetAllocator(const SkImageInfo& info,
71 bool isReady() { return (fTarget != NULL); }
73 virtual bool allocPixelRef(SkBitmap* bm, SkColorTable* ct) {
74 if (NULL == fTarget || !equal_modulo_alpha(fInfo, bm->info())) {
75 // Call default allocator.
76 return bm->tryAllocPixels(NULL, ct);
79 // TODO(halcanary): verify that all callers of this function
80 // will respect new RowBytes. Will be moot once rowbytes belongs
82 bm->installPixels(fInfo, fTarget, fRowBytes, ct, NULL, NULL);
84 fTarget = NULL; // never alloc same pixels twice!
89 const SkImageInfo fInfo;
90 void* fTarget; // Block of memory to be supplied as pixel memory
91 // in allocPixelRef. Must be large enough to hold
92 // a bitmap described by fInfo and fRowBytes
93 const size_t fRowBytes; // rowbytes for the destination bitmap
95 typedef SkBitmap::Allocator INHERITED;
98 // TODO(halcanary): Give this macro a better name and move it into SkTypes.h
100 #define SkCheckResult(expr, value) SkASSERT((value) == (expr))
102 #define SkCheckResult(expr, value) (void)(expr)
106 inline bool check_alpha(SkAlphaType reported, SkAlphaType actual) {
107 return ((reported == actual)
108 || ((reported == kPremul_SkAlphaType)
109 && (actual == kOpaque_SkAlphaType)));
113 ////////////////////////////////////////////////////////////////////////////////
115 DecodingImageGenerator::DecodingImageGenerator(
117 SkStreamRewindable* stream,
118 const SkImageInfo& info,
125 , fSampleSize(sampleSize)
126 , fDitherImage(ditherImage)
128 SkASSERT(stream != NULL);
129 SkSafeRef(fData); // may be NULL.
132 DecodingImageGenerator::~DecodingImageGenerator() {
136 SkData* DecodingImageGenerator::onRefEncodedData() {
137 // This functionality is used in `gm --serialize`
138 // Does not encode options.
140 // TODO(halcanary): SkStreamRewindable needs a refData() function
141 // which returns a cheap copy of the underlying data.
142 if (!fStream->rewind()) {
145 size_t length = fStream->getLength();
147 fData = SkData::NewFromStream(fStream, length);
150 return SkSafeRef(fData);
153 SkImageGenerator::Result DecodingImageGenerator::onGetPixels(const SkImageInfo& info,
154 void* pixels, size_t rowBytes, const Options& options, SkPMColor ctableEntries[],
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.
160 if (info.dimensions() != fInfo.dimensions()) {
161 return kInvalidScale;
163 return kInvalidConversion;
166 SkAssertResult(fStream->rewind());
167 SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(fStream));
168 if (NULL == decoder.get()) {
169 return kInvalidInput;
171 decoder->setDitherImage(fDitherImage);
172 decoder->setSampleSize(fSampleSize);
173 decoder->setRequireUnpremultipliedColors(info.alphaType() == kUnpremul_SkAlphaType);
176 TargetAllocator allocator(fInfo, pixels, rowBytes);
177 decoder->setAllocator(&allocator);
178 const SkImageDecoder::Result decodeResult = decoder->decode(fStream, &bitmap, info.colorType(),
179 SkImageDecoder::kDecodePixels_Mode);
180 decoder->setAllocator(NULL);
181 if (SkImageDecoder::kFailure == decodeResult) {
182 return kInvalidInput;
184 if (allocator.isReady()) { // Did not use pixels!
186 SkASSERT(bitmap.canCopyTo(info.colorType()));
187 bool copySuccess = bitmap.copyTo(&bm, info.colorType(), &allocator);
188 if (!copySuccess || allocator.isReady()) {
189 SkDEBUGFAIL("bitmap.copyTo(requestedConfig) failed.");
190 // Earlier we checked canCopyto(); we expect consistency.
191 return kInvalidConversion;
193 SkASSERT(check_alpha(info.alphaType(), bm.alphaType()));
195 SkASSERT(check_alpha(info.alphaType(), bitmap.alphaType()));
198 if (kIndex_8_SkColorType == info.colorType()) {
199 if (kIndex_8_SkColorType != bitmap.colorType()) {
200 // they asked for Index8, but we didn't receive that from decoder
201 return kInvalidConversion;
203 SkColorTable* ctable = bitmap.getColorTable();
204 if (NULL == ctable) {
205 return kInvalidConversion;
207 const int count = ctable->count();
208 memcpy(ctableEntries, ctable->readColors(), count * sizeof(SkPMColor));
209 *ctableCount = count;
211 if (SkImageDecoder::kPartialSuccess == decodeResult) {
212 return kIncompleteInput;
217 bool DecodingImageGenerator::onGetYUV8Planes(SkISize sizes[3], void* planes[3],
218 size_t rowBytes[3], SkYUVColorSpace* colorSpace) {
219 if (!fStream->rewind()) {
223 SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(fStream));
224 if (NULL == decoder.get()) {
228 return decoder->decodeYUV8Planes(fStream, sizes, planes, rowBytes, colorSpace);
231 // A contructor-type function that returns NULL on failure. This
232 // prevents the returned SkImageGenerator from ever being in a bad
233 // state. Called by both Create() functions
234 SkImageGenerator* CreateDecodingImageGenerator(
236 SkStreamRewindable* stream,
237 const SkDecodingImageGenerator::Options& opts) {
239 SkAutoTDelete<SkStreamRewindable> autoStream(stream); // always delete this
240 SkAssertResult(autoStream->rewind());
241 SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(autoStream));
242 if (NULL == decoder.get()) {
246 decoder->setSampleSize(opts.fSampleSize);
247 decoder->setRequireUnpremultipliedColors(opts.fRequireUnpremul);
248 if (!decoder->decode(stream, &bitmap, SkImageDecoder::kDecodeBounds_Mode)) {
251 if (kUnknown_SkColorType == bitmap.colorType()) {
255 SkImageInfo info = bitmap.info();
257 if (opts.fUseRequestedColorType && (opts.fRequestedColorType != info.colorType())) {
258 if (!bitmap.canCopyTo(opts.fRequestedColorType)) {
259 SkASSERT(bitmap.colorType() != opts.fRequestedColorType);
260 return NULL; // Can not translate to needed config.
262 info = info.makeColorType(opts.fRequestedColorType);
265 if (opts.fRequireUnpremul && info.alphaType() != kOpaque_SkAlphaType) {
266 info = info.makeAlphaType(kUnpremul_SkAlphaType);
269 SkAlphaType newAlphaType = info.alphaType();
270 if (!SkColorTypeValidateAlphaType(info.colorType(), info.alphaType(), &newAlphaType)) {
274 return SkNEW_ARGS(DecodingImageGenerator,
275 (data, autoStream.detach(), info.makeAlphaType(newAlphaType),
276 opts.fSampleSize, opts.fDitherImage));
281 ////////////////////////////////////////////////////////////////////////////////
283 SkImageGenerator* SkDecodingImageGenerator::Create(
285 const SkDecodingImageGenerator::Options& opts) {
286 SkASSERT(data != NULL);
290 SkStreamRewindable* stream = SkNEW_ARGS(SkMemoryStream, (data));
291 SkASSERT(stream != NULL);
292 return CreateDecodingImageGenerator(data, stream, opts);
295 SkImageGenerator* SkDecodingImageGenerator::Create(
296 SkStreamRewindable* stream,
297 const SkDecodingImageGenerator::Options& opts) {
298 SkASSERT(stream != NULL);
299 if (stream == NULL) {
302 return CreateDecodingImageGenerator(NULL, stream, opts);