1 /*
2 * Copyright 2006 The Android Open Source Project
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
9 #include "SkImageDecoder.h"
10 #include "SkBitmap.h"
11 #include "SkImagePriv.h"
12 #include "SkPixelRef.h"
13 #include "SkStream.h"
14 #include "SkTemplates.h"
15 #include "SkCanvas.h"
16
17 static SkBitmap::Config gDeviceConfig = SkBitmap::kNo_Config;
18
GetDeviceConfig()19 SkBitmap::Config SkImageDecoder::GetDeviceConfig()
20 {
21 return gDeviceConfig;
22 }
23
SetDeviceConfig(SkBitmap::Config config)24 void SkImageDecoder::SetDeviceConfig(SkBitmap::Config config)
25 {
26 gDeviceConfig = config;
27 }
28
29 ///////////////////////////////////////////////////////////////////////////////
30
SkImageDecoder()31 SkImageDecoder::SkImageDecoder()
32 : fPeeker(NULL)
33 , fChooser(NULL)
34 , fAllocator(NULL)
35 , fSampleSize(1)
36 , fDefaultPref(SkBitmap::kNo_Config)
37 , fDitherImage(true)
38 , fUsePrefTable(false)
39 , fSkipWritingZeroes(false)
40 , fPreferQualityOverSpeed(false)
41 , fRequireUnpremultipliedColors(false) {
42 }
43
~SkImageDecoder()44 SkImageDecoder::~SkImageDecoder() {
45 SkSafeUnref(fPeeker);
46 SkSafeUnref(fChooser);
47 SkSafeUnref(fAllocator);
48 }
49
copyFieldsToOther(SkImageDecoder * other)50 void SkImageDecoder::copyFieldsToOther(SkImageDecoder* other) {
51 if (NULL == other) {
52 return;
53 }
54 other->setPeeker(fPeeker);
55 other->setChooser(fChooser);
56 other->setAllocator(fAllocator);
57 other->setSampleSize(fSampleSize);
58 if (fUsePrefTable) {
59 other->setPrefConfigTable(fPrefTable);
60 } else {
61 other->fDefaultPref = fDefaultPref;
62 }
63 other->setDitherImage(fDitherImage);
64 other->setSkipWritingZeroes(fSkipWritingZeroes);
65 other->setPreferQualityOverSpeed(fPreferQualityOverSpeed);
66 other->setRequireUnpremultipliedColors(fRequireUnpremultipliedColors);
67 }
68
getFormat() const69 SkImageDecoder::Format SkImageDecoder::getFormat() const {
70 return kUnknown_Format;
71 }
72
getFormatName() const73 const char* SkImageDecoder::getFormatName() const {
74 return GetFormatName(this->getFormat());
75 }
76
GetFormatName(Format format)77 const char* SkImageDecoder::GetFormatName(Format format) {
78 switch (format) {
79 case kUnknown_Format:
80 return "Unknown Format";
81 case kBMP_Format:
82 return "BMP";
83 case kGIF_Format:
84 return "GIF";
85 case kICO_Format:
86 return "ICO";
87 case kJPEG_Format:
88 return "JPEG";
89 case kPNG_Format:
90 return "PNG";
91 case kWBMP_Format:
92 return "WBMP";
93 case kWEBP_Format:
94 return "WEBP";
95 default:
96 SkDEBUGFAIL("Invalid format type!");
97 }
98 return "Unknown Format";
99 }
100
setPeeker(Peeker * peeker)101 SkImageDecoder::Peeker* SkImageDecoder::setPeeker(Peeker* peeker) {
102 SkRefCnt_SafeAssign(fPeeker, peeker);
103 return peeker;
104 }
105
setChooser(Chooser * chooser)106 SkImageDecoder::Chooser* SkImageDecoder::setChooser(Chooser* chooser) {
107 SkRefCnt_SafeAssign(fChooser, chooser);
108 return chooser;
109 }
110
setAllocator(SkBitmap::Allocator * alloc)111 SkBitmap::Allocator* SkImageDecoder::setAllocator(SkBitmap::Allocator* alloc) {
112 SkRefCnt_SafeAssign(fAllocator, alloc);
113 return alloc;
114 }
115
setSampleSize(int size)116 void SkImageDecoder::setSampleSize(int size) {
117 if (size < 1) {
118 size = 1;
119 }
120 fSampleSize = size;
121 }
122
chooseFromOneChoice(SkBitmap::Config config,int width,int height) const123 bool SkImageDecoder::chooseFromOneChoice(SkBitmap::Config config, int width,
124 int height) const {
125 Chooser* chooser = fChooser;
126
127 if (NULL == chooser) { // no chooser, we just say YES to decoding :)
128 return true;
129 }
130 chooser->begin(1);
131 chooser->inspect(0, config, width, height);
132 return chooser->choose() == 0;
133 }
134
allocPixelRef(SkBitmap * bitmap,SkColorTable * ctable) const135 bool SkImageDecoder::allocPixelRef(SkBitmap* bitmap,
136 SkColorTable* ctable) const {
137 return bitmap->allocPixels(fAllocator, ctable);
138 }
139
140 ///////////////////////////////////////////////////////////////////////////////
141
setPrefConfigTable(const PrefConfigTable & prefTable)142 void SkImageDecoder::setPrefConfigTable(const PrefConfigTable& prefTable) {
143 fUsePrefTable = true;
144 fPrefTable = prefTable;
145 }
146
getPrefConfig(SrcDepth srcDepth,bool srcHasAlpha) const147 SkBitmap::Config SkImageDecoder::getPrefConfig(SrcDepth srcDepth,
148 bool srcHasAlpha) const {
149 SkBitmap::Config config = SkBitmap::kNo_Config;
150
151 if (fUsePrefTable) {
152 switch (srcDepth) {
153 case kIndex_SrcDepth:
154 config = srcHasAlpha ? fPrefTable.fPrefFor_8Index_YesAlpha_src
155 : fPrefTable.fPrefFor_8Index_NoAlpha_src;
156 break;
157 case k8BitGray_SrcDepth:
158 config = fPrefTable.fPrefFor_8Gray_src;
159 break;
160 case k32Bit_SrcDepth:
161 config = srcHasAlpha ? fPrefTable.fPrefFor_8bpc_YesAlpha_src
162 : fPrefTable.fPrefFor_8bpc_NoAlpha_src;
163 break;
164 }
165 } else {
166 config = fDefaultPref;
167 }
168
169 if (SkBitmap::kNo_Config == config) {
170 config = SkImageDecoder::GetDeviceConfig();
171 }
172 return config;
173 }
174
decode(SkStream * stream,SkBitmap * bm,SkBitmap::Config pref,Mode mode)175 bool SkImageDecoder::decode(SkStream* stream, SkBitmap* bm,
176 SkBitmap::Config pref, Mode mode) {
177 // we reset this to false before calling onDecode
178 fShouldCancelDecode = false;
179 // assign this, for use by getPrefConfig(), in case fUsePrefTable is false
180 fDefaultPref = pref;
181
182 // pass a temporary bitmap, so that if we return false, we are assured of
183 // leaving the caller's bitmap untouched.
184 SkBitmap tmp;
185 if (!this->onDecode(stream, &tmp, mode)) {
186 return false;
187 }
188 bm->swap(tmp);
189 return true;
190 }
191
decodeSubset(SkBitmap * bm,const SkIRect & rect,SkBitmap::Config pref)192 bool SkImageDecoder::decodeSubset(SkBitmap* bm, const SkIRect& rect,
193 SkBitmap::Config pref) {
194 // we reset this to false before calling onDecodeSubset
195 fShouldCancelDecode = false;
196 // assign this, for use by getPrefConfig(), in case fUsePrefTable is false
197 fDefaultPref = pref;
198
199 return this->onDecodeSubset(bm, rect);
200 }
201
buildTileIndex(SkStreamRewindable * stream,int * width,int * height)202 bool SkImageDecoder::buildTileIndex(SkStreamRewindable* stream,
203 int *width, int *height) {
204 // we reset this to false before calling onBuildTileIndex
205 fShouldCancelDecode = false;
206
207 return this->onBuildTileIndex(stream, width, height);
208 }
209
cropBitmap(SkBitmap * dst,SkBitmap * src,int sampleSize,int dstX,int dstY,int width,int height,int srcX,int srcY)210 bool SkImageDecoder::cropBitmap(SkBitmap *dst, SkBitmap *src, int sampleSize,
211 int dstX, int dstY, int width, int height,
212 int srcX, int srcY) {
213 int w = width / sampleSize;
214 int h = height / sampleSize;
215 if (src->config() == SkBitmap::kIndex8_Config) {
216 // kIndex8 does not allow drawing via an SkCanvas, as is done below.
217 // Instead, use extractSubset. Note that this shares the SkPixelRef and
218 // SkColorTable.
219 // FIXME: Since src is discarded in practice, this holds on to more
220 // pixels than is strictly necessary. Switch to a copy if memory
221 // savings are more important than speed here. This also means
222 // that the pixels in dst can not be reused (though there is no
223 // allocation, which was already done on src).
224 int x = (dstX - srcX) / sampleSize;
225 int y = (dstY - srcY) / sampleSize;
226 SkIRect subset = SkIRect::MakeXYWH(x, y, w, h);
227 return src->extractSubset(dst, subset);
228 }
229 // if the destination has no pixels then we must allocate them.
230 if (dst->isNull()) {
231 dst->setConfig(src->config(), w, h, 0, src->alphaType());
232
233 if (!this->allocPixelRef(dst, NULL)) {
234 SkDEBUGF(("failed to allocate pixels needed to crop the bitmap"));
235 return false;
236 }
237 }
238 // check to see if the destination is large enough to decode the desired
239 // region. If this assert fails we will just draw as much of the source
240 // into the destination that we can.
241 if (dst->width() < w || dst->height() < h) {
242 SkDEBUGF(("SkImageDecoder::cropBitmap does not have a large enough bitmap.\n"));
243 }
244
245 // Set the Src_Mode for the paint to prevent transparency issue in the
246 // dest in the event that the dest was being re-used.
247 SkPaint paint;
248 paint.setXfermodeMode(SkXfermode::kSrc_Mode);
249
250 SkCanvas canvas(*dst);
251 canvas.drawSprite(*src, (srcX - dstX) / sampleSize,
252 (srcY - dstY) / sampleSize,
253 &paint);
254 return true;
255 }
256
257 ///////////////////////////////////////////////////////////////////////////////
258
DecodeFile(const char file[],SkBitmap * bm,SkBitmap::Config pref,Mode mode,Format * format)259 bool SkImageDecoder::DecodeFile(const char file[], SkBitmap* bm,
260 SkBitmap::Config pref, Mode mode, Format* format) {
261 SkASSERT(file);
262 SkASSERT(bm);
263
264 SkAutoTUnref<SkStreamRewindable> stream(SkStream::NewFromFile(file));
265 if (stream.get()) {
266 if (SkImageDecoder::DecodeStream(stream, bm, pref, mode, format)) {
267 bm->pixelRef()->setURI(file);
268 return true;
269 }
270 }
271 return false;
272 }
273
DecodeMemory(const void * buffer,size_t size,SkBitmap * bm,SkBitmap::Config pref,Mode mode,Format * format)274 bool SkImageDecoder::DecodeMemory(const void* buffer, size_t size, SkBitmap* bm,
275 SkBitmap::Config pref, Mode mode, Format* format) {
276 if (0 == size) {
277 return false;
278 }
279 SkASSERT(buffer);
280
281 SkMemoryStream stream(buffer, size);
282 return SkImageDecoder::DecodeStream(&stream, bm, pref, mode, format);
283 }
284
DecodeStream(SkStreamRewindable * stream,SkBitmap * bm,SkBitmap::Config pref,Mode mode,Format * format)285 bool SkImageDecoder::DecodeStream(SkStreamRewindable* stream, SkBitmap* bm,
286 SkBitmap::Config pref, Mode mode,
287 Format* format) {
288 SkASSERT(stream);
289 SkASSERT(bm);
290
291 bool success = false;
292 SkImageDecoder* codec = SkImageDecoder::Factory(stream);
293
294 if (NULL != codec) {
295 success = codec->decode(stream, bm, pref, mode);
296 if (success && format) {
297 *format = codec->getFormat();
298 if (kUnknown_Format == *format) {
299 if (stream->rewind()) {
300 *format = GetStreamFormat(stream);
301 }
302 }
303 }
304 delete codec;
305 }
306 return success;
307 }
308