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 "SkDecodingImageGenerator.h"
9 #include "SkData.h"
10 #include "SkImageDecoder.h"
11 #include "SkImageGenerator.h"
12 #include "SkImagePriv.h"
13 #include "SkStream.h"
14
15
16 namespace {
17 /**
18 * Special allocator used by getPixels(). Uses preallocated memory
19 * provided.
20 */
21 class TargetAllocator : public SkBitmap::Allocator {
22 public:
TargetAllocator(void * target,size_t rowBytes,const SkImageInfo & info)23 TargetAllocator(void* target, size_t rowBytes, const SkImageInfo& info)
24 : fTarget(target)
25 , fRowBytes(rowBytes)
26 , fInfo(info) { }
27
allocPixelRef(SkBitmap * bm,SkColorTable * ct)28 virtual bool allocPixelRef(SkBitmap* bm, SkColorTable* ct) SK_OVERRIDE {
29 if ((SkImageInfoToBitmapConfig(fInfo) != bm->config())
30 || (bm->width() != fInfo.fWidth)
31 || (bm->height() != fInfo.fHeight)) {
32 return false;
33 }
34 bm->setConfig(bm->config(), bm->width(), bm->height(),
35 fRowBytes, bm->alphaType());
36 bm->setPixels(fTarget, ct);
37 return true;
38 }
39
40 private:
41 void* fTarget;
42 size_t fRowBytes;
43 SkImageInfo fInfo;
44 typedef SkBitmap::Allocator INHERITED;
45 };
46 } // namespace
47 ////////////////////////////////////////////////////////////////////////////////
48
SkDecodingImageGenerator(SkData * data)49 SkDecodingImageGenerator::SkDecodingImageGenerator(SkData* data)
50 : fData(data)
51 , fHasInfo(false)
52 , fDoCopyTo(false) {
53 SkASSERT(fData != NULL);
54 fStream = SkNEW_ARGS(SkMemoryStream, (fData));
55 SkASSERT(fStream != NULL);
56 SkASSERT(fStream->unique());
57 fData->ref();
58 }
59
SkDecodingImageGenerator(SkStreamRewindable * stream)60 SkDecodingImageGenerator::SkDecodingImageGenerator(SkStreamRewindable* stream)
61 : fData(NULL)
62 , fStream(stream)
63 , fHasInfo(false)
64 , fDoCopyTo(false) {
65 SkASSERT(fStream != NULL);
66 SkASSERT(fStream->unique());
67 }
68
~SkDecodingImageGenerator()69 SkDecodingImageGenerator::~SkDecodingImageGenerator() {
70 SkSafeUnref(fData);
71 fStream->unref();
72 }
73
74 // TODO(halcanary): Give this macro a better name and move it into SkTypes.h
75 #ifdef SK_DEBUG
76 #define SkCheckResult(expr, value) SkASSERT((value) == (expr))
77 #else
78 #define SkCheckResult(expr, value) (void)(expr)
79 #endif
80
refEncodedData()81 SkData* SkDecodingImageGenerator::refEncodedData() {
82 // This functionality is used in `gm --serialize`
83 if (fData != NULL) {
84 return SkSafeRef(fData);
85 }
86 // TODO(halcanary): SkStreamRewindable needs a refData() function
87 // which returns a cheap copy of the underlying data.
88 if (!fStream->rewind()) {
89 return NULL;
90 }
91 size_t length = fStream->getLength();
92 if (0 == length) {
93 return NULL;
94 }
95 void* buffer = sk_malloc_flags(length, 0);
96 SkCheckResult(fStream->read(buffer, length), length);
97 fData = SkData::NewFromMalloc(buffer, length);
98 return SkSafeRef(fData);
99 }
100
getInfo(SkImageInfo * info)101 bool SkDecodingImageGenerator::getInfo(SkImageInfo* info) {
102 // info can be NULL. If so, will update fInfo, fDoCopyTo, and fHasInfo.
103 if (fHasInfo) {
104 if (info != NULL) {
105 *info = fInfo;
106 }
107 return true;
108 }
109 SkAssertResult(fStream->rewind());
110 SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(fStream));
111 if (NULL == decoder.get()) {
112 return false;
113 }
114 SkBitmap bitmap;
115 if (!decoder->decode(fStream, &bitmap,
116 SkImageDecoder::kDecodeBounds_Mode)) {
117 return false;
118 }
119 if (bitmap.config() == SkBitmap::kNo_Config) {
120 return false;
121 }
122 if (!bitmap.asImageInfo(&fInfo)) {
123 // We can't use bitmap.config() as is.
124 if (!bitmap.canCopyTo(SkBitmap::kARGB_8888_Config)) {
125 SkDEBUGFAIL("!bitmap->canCopyTo(SkBitmap::kARGB_8888_Config)");
126 return false;
127 }
128 fDoCopyTo = true;
129 fInfo.fWidth = bitmap.width();
130 fInfo.fHeight = bitmap.height();
131 fInfo.fColorType = kPMColor_SkColorType;
132 fInfo.fAlphaType = bitmap.alphaType();
133 }
134 if (info != NULL) {
135 *info = fInfo;
136 }
137 fHasInfo = true;
138 return true;
139 }
140
getPixels(const SkImageInfo & info,void * pixels,size_t rowBytes)141 bool SkDecodingImageGenerator::getPixels(const SkImageInfo& info,
142 void* pixels,
143 size_t rowBytes) {
144 if (NULL == pixels) {
145 return false;
146 }
147 if (!this->getInfo(NULL)) {
148 return false;
149 }
150 if (SkImageInfoToBitmapConfig(info) == SkBitmap::kNo_Config) {
151 return false; // Unsupported SkColorType.
152 }
153 SkAssertResult(fStream->rewind());
154 SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(fStream));
155 if (NULL == decoder.get()) {
156 return false;
157 }
158 if (fInfo != info) {
159 // The caller has specified a different info. For now, this
160 // is an error. In the future, we will check to see if we can
161 // convert.
162 return false;
163 }
164 int bpp = SkBitmap::ComputeBytesPerPixel(SkImageInfoToBitmapConfig(info));
165 if (static_cast<size_t>(bpp * info.fWidth) > rowBytes) {
166 return false;
167 }
168 SkBitmap bitmap;
169 if (!bitmap.setConfig(info, rowBytes)) {
170 return false;
171 }
172
173 TargetAllocator allocator(pixels, rowBytes, info);
174 if (!fDoCopyTo) {
175 decoder->setAllocator(&allocator);
176 }
177 bool success = decoder->decode(fStream, &bitmap,
178 SkImageDecoder::kDecodePixels_Mode);
179 decoder->setAllocator(NULL);
180 if (!success) {
181 return false;
182 }
183 if (fDoCopyTo) {
184 SkBitmap bm8888;
185 bitmap.copyTo(&bm8888, SkBitmap::kARGB_8888_Config, &allocator);
186 }
187 return true;
188 }
Install(SkData * data,SkBitmap * dst,SkDiscardableMemory::Factory * factory)189 bool SkDecodingImageGenerator::Install(SkData* data, SkBitmap* dst,
190 SkDiscardableMemory::Factory* factory) {
191 SkASSERT(data != NULL);
192 SkASSERT(dst != NULL);
193 SkImageGenerator* gen(SkNEW_ARGS(SkDecodingImageGenerator, (data)));
194 return SkInstallDiscardablePixelRef(gen, dst, factory);
195 }
196
Install(SkStreamRewindable * stream,SkBitmap * dst,SkDiscardableMemory::Factory * factory)197 bool SkDecodingImageGenerator::Install(SkStreamRewindable* stream,
198 SkBitmap* dst,
199 SkDiscardableMemory::Factory* factory) {
200 SkASSERT(stream != NULL);
201 SkASSERT(dst != NULL);
202 if ((stream == NULL) || !stream->unique()) {
203 SkSafeUnref(stream);
204 return false;
205 }
206 SkImageGenerator* gen(SkNEW_ARGS(SkDecodingImageGenerator, (stream)));
207 return SkInstallDiscardablePixelRef(gen, dst, factory);
208 }
209