blob: 7b4267615fc563b5eb0752f7a353c667f4db23a6 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
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
reed@android.com8a1c16f2008-12-17 15:59:43 +00008
9#include "SkImageDecoder.h"
10#include "SkBitmap.h"
scroggo@google.comf8d7d272013-02-22 21:38:35 +000011#include "SkImagePriv.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000012#include "SkPixelRef.h"
13#include "SkStream.h"
14#include "SkTemplates.h"
15
robertphillips@google.com15e9d3e2012-06-21 20:25:03 +000016SK_DEFINE_INST_COUNT(SkImageDecoder::Peeker)
17SK_DEFINE_INST_COUNT(SkImageDecoder::Chooser)
18SK_DEFINE_INST_COUNT(SkImageDecoderFactory)
19
reed@android.com8a1c16f2008-12-17 15:59:43 +000020static SkBitmap::Config gDeviceConfig = SkBitmap::kNo_Config;
21
22SkBitmap::Config SkImageDecoder::GetDeviceConfig()
23{
24 return gDeviceConfig;
25}
26
27void SkImageDecoder::SetDeviceConfig(SkBitmap::Config config)
28{
29 gDeviceConfig = config;
30}
31
32///////////////////////////////////////////////////////////////////////////////
33
34SkImageDecoder::SkImageDecoder()
35 : fPeeker(NULL), fChooser(NULL), fAllocator(NULL), fSampleSize(1),
reed@android.com3f1f06a2010-03-03 21:04:12 +000036 fDefaultPref(SkBitmap::kNo_Config), fDitherImage(true),
37 fUsePrefTable(false) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000038}
39
40SkImageDecoder::~SkImageDecoder() {
reed@google.com82065d62011-02-07 15:30:46 +000041 SkSafeUnref(fPeeker);
42 SkSafeUnref(fChooser);
43 SkSafeUnref(fAllocator);
reed@android.com8a1c16f2008-12-17 15:59:43 +000044}
45
46SkImageDecoder::Format SkImageDecoder::getFormat() const {
47 return kUnknown_Format;
48}
49
50SkImageDecoder::Peeker* SkImageDecoder::setPeeker(Peeker* peeker) {
51 SkRefCnt_SafeAssign(fPeeker, peeker);
52 return peeker;
53}
54
55SkImageDecoder::Chooser* SkImageDecoder::setChooser(Chooser* chooser) {
56 SkRefCnt_SafeAssign(fChooser, chooser);
57 return chooser;
58}
59
60SkBitmap::Allocator* SkImageDecoder::setAllocator(SkBitmap::Allocator* alloc) {
61 SkRefCnt_SafeAssign(fAllocator, alloc);
62 return alloc;
63}
64
65void SkImageDecoder::setSampleSize(int size) {
66 if (size < 1) {
67 size = 1;
68 }
69 fSampleSize = size;
70}
71
72bool SkImageDecoder::chooseFromOneChoice(SkBitmap::Config config, int width,
73 int height) const {
74 Chooser* chooser = fChooser;
75
76 if (NULL == chooser) { // no chooser, we just say YES to decoding :)
77 return true;
78 }
79 chooser->begin(1);
80 chooser->inspect(0, config, width, height);
81 return chooser->choose() == 0;
82}
83
84bool SkImageDecoder::allocPixelRef(SkBitmap* bitmap,
85 SkColorTable* ctable) const {
86 return bitmap->allocPixels(fAllocator, ctable);
87}
88
89///////////////////////////////////////////////////////////////////////////////
reed@android.comb6137c32009-07-29 20:56:52 +000090
reed@android.com3f1f06a2010-03-03 21:04:12 +000091void SkImageDecoder::setPrefConfigTable(const SkBitmap::Config pref[6]) {
92 if (NULL == pref) {
93 fUsePrefTable = false;
94 } else {
95 fUsePrefTable = true;
96 memcpy(fPrefTable, pref, sizeof(fPrefTable));
97 }
98}
99
100SkBitmap::Config SkImageDecoder::getPrefConfig(SrcDepth srcDepth,
101 bool srcHasAlpha) const {
102 SkBitmap::Config config;
103
104 if (fUsePrefTable) {
105 int index = 0;
106 switch (srcDepth) {
107 case kIndex_SrcDepth:
108 index = 0;
109 break;
110 case k16Bit_SrcDepth:
111 index = 2;
112 break;
113 case k32Bit_SrcDepth:
114 index = 4;
115 break;
116 }
117 if (srcHasAlpha) {
118 index += 1;
119 }
120 config = fPrefTable[index];
121 } else {
122 config = fDefaultPref;
123 }
124
125 if (SkBitmap::kNo_Config == config) {
126 config = SkImageDecoder::GetDeviceConfig();
127 }
128 return config;
129}
130
reed@android.com8a1c16f2008-12-17 15:59:43 +0000131bool SkImageDecoder::decode(SkStream* stream, SkBitmap* bm,
132 SkBitmap::Config pref, Mode mode) {
reed@android.com62900b42009-02-11 15:07:19 +0000133 // pass a temporary bitmap, so that if we return false, we are assured of
134 // leaving the caller's bitmap untouched.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000135 SkBitmap tmp;
136
137 // we reset this to false before calling onDecode
138 fShouldCancelDecode = false;
reed@android.com3f1f06a2010-03-03 21:04:12 +0000139 // assign this, for use by getPrefConfig(), in case fUsePrefTable is false
140 fDefaultPref = pref;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000141
reed@android.com3f1f06a2010-03-03 21:04:12 +0000142 if (!this->onDecode(stream, &tmp, mode)) {
reed@android.com62900b42009-02-11 15:07:19 +0000143 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000144 }
reed@android.com62900b42009-02-11 15:07:19 +0000145 bm->swap(tmp);
146 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000147}
148
149///////////////////////////////////////////////////////////////////////////////
150
151bool SkImageDecoder::DecodeFile(const char file[], SkBitmap* bm,
reed@android.comb3ade9d2009-06-15 13:04:45 +0000152 SkBitmap::Config pref, Mode mode, Format* format) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000153 SkASSERT(file);
154 SkASSERT(bm);
155
156 SkFILEStream stream(file);
157 if (stream.isValid()) {
reed@android.comb3ade9d2009-06-15 13:04:45 +0000158 if (SkImageDecoder::DecodeStream(&stream, bm, pref, mode, format)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000159 bm->pixelRef()->setURI(file);
tomhudson@google.com1a366212012-01-03 14:42:08 +0000160 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000161 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000162 }
163 return false;
164}
165
166bool SkImageDecoder::DecodeMemory(const void* buffer, size_t size, SkBitmap* bm,
reed@android.comb3ade9d2009-06-15 13:04:45 +0000167 SkBitmap::Config pref, Mode mode, Format* format) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000168 if (0 == size) {
169 return false;
170 }
171 SkASSERT(buffer);
172
173 SkMemoryStream stream(buffer, size);
reed@android.comb3ade9d2009-06-15 13:04:45 +0000174 return SkImageDecoder::DecodeStream(&stream, bm, pref, mode, format);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000175}
176
scroggo@google.comf8d7d272013-02-22 21:38:35 +0000177class TargetAllocator : public SkBitmap::Allocator {
178
179public:
180 TargetAllocator(void* target)
181 : fTarget(target) {}
182
183 virtual bool allocPixelRef(SkBitmap* bm, SkColorTable* ct) SK_OVERRIDE {
184 // SkColorTable is not supported by Info/Target model.
185 SkASSERT(NULL == ct);
186 bm->setPixels(fTarget);
187 return true;
188 }
189
190private:
191 void* fTarget;
192};
193
194bool SkImageDecoder::DecodeMemoryToTarget(const void* buffer, size_t size,
195 SkImage::Info* info,
196 const SkBitmapFactory::Target* target) {
197 if (NULL == info) {
198 return false;
199 }
200 // FIXME: Just to get this working, implement in terms of existing
201 // ImageDecoder calls.
202 SkBitmap bm;
203 SkMemoryStream stream(buffer, size);
204 SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(&stream));
205 if (decoder.get() != NULL && decoder->decode(&stream, &bm, kDecodeBounds_Mode)) {
206 // Now set info properly
207 if (!SkBitmapToImageInfo(bm, info)) {
208 return false;
209 }
210
211 // SkBitmapToImageInfo will return false if Index8 is used. kIndex8
212 // is not supported by the Info/Target model, since kIndex8 requires
213 // an SkColorTable, which this model does not keep track of.
214 SkASSERT(bm.config() != SkBitmap::kIndex8_Config);
215
216 if (NULL == target) {
217 return true;
218 }
219
220 if (target->fRowBytes != (uint32_t) bm.rowBytes()) {
221 if (target->fRowBytes < SkImageMinRowBytes(*info)) {
222 SkASSERT(!"Desired row bytes is too small");
223 return false;
224 }
225 bm.setConfig(bm.config(), bm.width(), bm.height(), target->fRowBytes);
226 }
227
228 TargetAllocator allocator(target->fAddr);
229 decoder->setAllocator(&allocator);
230 stream.rewind();
231 bool success = decoder->decode(&stream, &bm, kDecodePixels_Mode);
232 // Remove the allocator, since it's on the stack.
233 decoder->setAllocator(NULL);
234 return success;
235 }
236 return false;
237}
238
239
reed@android.com8a1c16f2008-12-17 15:59:43 +0000240bool SkImageDecoder::DecodeStream(SkStream* stream, SkBitmap* bm,
reed@android.comb3ade9d2009-06-15 13:04:45 +0000241 SkBitmap::Config pref, Mode mode, Format* format) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000242 SkASSERT(stream);
243 SkASSERT(bm);
244
245 bool success = false;
246 SkImageDecoder* codec = SkImageDecoder::Factory(stream);
247
248 if (NULL != codec) {
249 success = codec->decode(stream, bm, pref, mode);
reed@android.comb3ade9d2009-06-15 13:04:45 +0000250 if (success && format) {
251 *format = codec->getFormat();
252 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000253 delete codec;
254 }
255 return success;
256}