• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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