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