blob: f0fff1b9b38f5e6fc13330a95b2054291dc38d49 [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/* libs/graphics/images/SkImageDecoder.cpp
2**
3** Copyright 2006, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9** http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18#include "SkImageDecoder.h"
19#include "SkBitmap.h"
20#include "SkPixelRef.h"
21#include "SkStream.h"
22#include "SkTemplates.h"
23
24static SkBitmap::Config gDeviceConfig = SkBitmap::kNo_Config;
25
26SkBitmap::Config SkImageDecoder::GetDeviceConfig()
27{
28 return gDeviceConfig;
29}
30
31void SkImageDecoder::SetDeviceConfig(SkBitmap::Config config)
32{
33 gDeviceConfig = config;
34}
35
36///////////////////////////////////////////////////////////////////////////////
37
38SkImageDecoder::SkImageDecoder()
39 : fPeeker(NULL), fChooser(NULL), fAllocator(NULL), fSampleSize(1),
40 fDitherImage(true) {
41}
42
43SkImageDecoder::~SkImageDecoder() {
44 fPeeker->safeUnref();
45 fChooser->safeUnref();
46 fAllocator->safeUnref();
47}
48
49SkImageDecoder::Format SkImageDecoder::getFormat() const {
50 return kUnknown_Format;
51}
52
53SkImageDecoder::Peeker* SkImageDecoder::setPeeker(Peeker* peeker) {
54 SkRefCnt_SafeAssign(fPeeker, peeker);
55 return peeker;
56}
57
58SkImageDecoder::Chooser* SkImageDecoder::setChooser(Chooser* chooser) {
59 SkRefCnt_SafeAssign(fChooser, chooser);
60 return chooser;
61}
62
63SkBitmap::Allocator* SkImageDecoder::setAllocator(SkBitmap::Allocator* alloc) {
64 SkRefCnt_SafeAssign(fAllocator, alloc);
65 return alloc;
66}
67
68void SkImageDecoder::setSampleSize(int size) {
69 if (size < 1) {
70 size = 1;
71 }
72 fSampleSize = size;
73}
74
75bool SkImageDecoder::chooseFromOneChoice(SkBitmap::Config config, int width,
76 int height) const {
77 Chooser* chooser = fChooser;
78
79 if (NULL == chooser) { // no chooser, we just say YES to decoding :)
80 return true;
81 }
82 chooser->begin(1);
83 chooser->inspect(0, config, width, height);
84 return chooser->choose() == 0;
85}
86
87bool SkImageDecoder::allocPixelRef(SkBitmap* bitmap,
88 SkColorTable* ctable) const {
89 return bitmap->allocPixels(fAllocator, ctable);
90}
91
92///////////////////////////////////////////////////////////////////////////////
93
reed@android.com62900b42009-02-11 15:07:19 +000094/* Technically, this should be 342, since that is the cutoff point between
95 an index and 32bit bitmap (they take equal ram), but since 32bit is almost
96 always faster, I bump up the value a bit.
97*/
98#define MIN_SIZE_FOR_INDEX (512)
99
100/* Return the "optimal" config for this bitmap. In this case, we just look to
101 promote index bitmaps to full-color, since those are a little faster to
102 draw (fewer memory lookups).
103
104 Seems like we could expose this to the caller through some exising or new
105 proxy object, allowing them to decide (after sniffing some aspect of the
106 original bitmap) what config they really want.
107 */
108static SkBitmap::Config optimal_config(const SkBitmap& bm,
109 SkBitmap::Config pref) {
110 if (bm.config() != pref) {
111 if (bm.config() == SkBitmap::kIndex8_Config) {
112 Sk64 size64 = bm.getSize64();
113 if (size64.is32()) {
114 int32_t size = size64.get32();
115 if (size < MIN_SIZE_FOR_INDEX) {
116 return SkBitmap::kARGB_8888_Config;
117 }
118 }
119 }
120 }
121 return bm.config();
122}
123
reed@android.com8a1c16f2008-12-17 15:59:43 +0000124bool SkImageDecoder::decode(SkStream* stream, SkBitmap* bm,
125 SkBitmap::Config pref, Mode mode) {
reed@android.com62900b42009-02-11 15:07:19 +0000126 // pass a temporary bitmap, so that if we return false, we are assured of
127 // leaving the caller's bitmap untouched.
reed@android.com8a1c16f2008-12-17 15:59:43 +0000128 SkBitmap tmp;
129
130 // we reset this to false before calling onDecode
131 fShouldCancelDecode = false;
132
reed@android.com62900b42009-02-11 15:07:19 +0000133 if (!this->onDecode(stream, &tmp, pref, mode)) {
134 return false;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000135 }
reed@android.com62900b42009-02-11 15:07:19 +0000136
137 SkBitmap::Config c = optimal_config(tmp, pref);
138 if (c != tmp.config()) {
139 if (mode == kDecodeBounds_Mode) {
140 tmp.setConfig(c, tmp.width(), tmp.height());
141 } else {
142 SkBitmap tmp2;
143 if (tmp.copyTo(&tmp2, c, this->getAllocator())) {
144 tmp.swap(tmp2);
145 }
146 }
147 }
148 bm->swap(tmp);
149 return true;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000150}
151
152///////////////////////////////////////////////////////////////////////////////
153
154bool SkImageDecoder::DecodeFile(const char file[], SkBitmap* bm,
155 SkBitmap::Config pref, Mode mode) {
156 SkASSERT(file);
157 SkASSERT(bm);
158
159 SkFILEStream stream(file);
160 if (stream.isValid()) {
161 if (SkImageDecoder::DecodeStream(&stream, bm, pref, mode)) {
162 bm->pixelRef()->setURI(file);
163 }
164 return true;
165 }
166 return false;
167}
168
169bool SkImageDecoder::DecodeMemory(const void* buffer, size_t size, SkBitmap* bm,
170 SkBitmap::Config pref, Mode mode) {
171 if (0 == size) {
172 return false;
173 }
174 SkASSERT(buffer);
175
176 SkMemoryStream stream(buffer, size);
177 return SkImageDecoder::DecodeStream(&stream, bm, pref, mode);
178}
179
180bool SkImageDecoder::DecodeStream(SkStream* stream, SkBitmap* bm,
181 SkBitmap::Config pref, Mode mode) {
182 SkASSERT(stream);
183 SkASSERT(bm);
184
185 bool success = false;
186 SkImageDecoder* codec = SkImageDecoder::Factory(stream);
187
188 if (NULL != codec) {
189 success = codec->decode(stream, bm, pref, mode);
190 delete codec;
191 }
192 return success;
193}
194