1
2/*
3 * Copyright 2006 The Android Open Source Project
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9
10#include "SkImageDecoder.h"
11#include "SkBitmap.h"
12#include "SkPixelRef.h"
13#include "SkStream.h"
14#include "SkTemplates.h"
15#include "SkCanvas.h"
16
17SkVMMemoryReporter::~SkVMMemoryReporter() {
18}
19
20const char *SkImageDecoder::kFormatName[] = {
21    "Unknown Format",
22    "BMP",
23    "GIF",
24    "ICO",
25    "JPEG",
26    "PNG",
27    "WBMP",
28    "WEBP",
29};
30
31static SkBitmap::Config gDeviceConfig = SkBitmap::kNo_Config;
32
33SkBitmap::Config SkImageDecoder::GetDeviceConfig()
34{
35    return gDeviceConfig;
36}
37
38void SkImageDecoder::SetDeviceConfig(SkBitmap::Config config)
39{
40    gDeviceConfig = config;
41}
42
43///////////////////////////////////////////////////////////////////////////////
44
45SkImageDecoder::SkImageDecoder()
46    : fReporter(NULL), fPeeker(NULL), fChooser(NULL), fAllocator(NULL),
47      fSampleSize(1), fDefaultPref(SkBitmap::kNo_Config), fDitherImage(true),
48      fUsePrefTable(false),fPreferQualityOverSpeed(false) {
49}
50
51SkImageDecoder::~SkImageDecoder() {
52    SkSafeUnref(fPeeker);
53    SkSafeUnref(fChooser);
54    SkSafeUnref(fAllocator);
55    SkSafeUnref(fReporter);
56}
57
58SkImageDecoder::Format SkImageDecoder::getFormat() const {
59    return kUnknown_Format;
60}
61
62SkImageDecoder::Peeker* SkImageDecoder::setPeeker(Peeker* peeker) {
63    SkRefCnt_SafeAssign(fPeeker, peeker);
64    return peeker;
65}
66
67SkImageDecoder::Chooser* SkImageDecoder::setChooser(Chooser* chooser) {
68    SkRefCnt_SafeAssign(fChooser, chooser);
69    return chooser;
70}
71
72SkBitmap::Allocator* SkImageDecoder::setAllocator(SkBitmap::Allocator* alloc) {
73    SkRefCnt_SafeAssign(fAllocator, alloc);
74    return alloc;
75}
76
77SkVMMemoryReporter* SkImageDecoder::setReporter(SkVMMemoryReporter* reporter) {
78    SkRefCnt_SafeAssign(fReporter, reporter);
79    return reporter;
80}
81
82void SkImageDecoder::setSampleSize(int size) {
83    if (size < 1) {
84        size = 1;
85    }
86    fSampleSize = size;
87}
88
89bool SkImageDecoder::chooseFromOneChoice(SkBitmap::Config config, int width,
90                                         int height) const {
91    Chooser* chooser = fChooser;
92
93    if (NULL == chooser) {    // no chooser, we just say YES to decoding :)
94        return true;
95    }
96    chooser->begin(1);
97    chooser->inspect(0, config, width, height);
98    return chooser->choose() == 0;
99}
100
101bool SkImageDecoder::allocPixelRef(SkBitmap* bitmap,
102                                   SkColorTable* ctable) const {
103    return bitmap->allocPixels(fAllocator, ctable);
104}
105
106///////////////////////////////////////////////////////////////////////////////
107
108void SkImageDecoder::setPrefConfigTable(const SkBitmap::Config pref[6]) {
109    if (NULL == pref) {
110        fUsePrefTable = false;
111    } else {
112        fUsePrefTable = true;
113        memcpy(fPrefTable, pref, sizeof(fPrefTable));
114    }
115}
116
117SkBitmap::Config SkImageDecoder::getPrefConfig(SrcDepth srcDepth,
118                                               bool srcHasAlpha) const {
119    SkBitmap::Config config;
120
121    if (fUsePrefTable) {
122        int index = 0;
123        switch (srcDepth) {
124            case kIndex_SrcDepth:
125                index = 0;
126                break;
127            case k16Bit_SrcDepth:
128                index = 2;
129                break;
130            case k32Bit_SrcDepth:
131                index = 4;
132                break;
133        }
134        if (srcHasAlpha) {
135            index += 1;
136        }
137        config = fPrefTable[index];
138    } else {
139        config = fDefaultPref;
140    }
141
142    if (SkBitmap::kNo_Config == config) {
143        config = SkImageDecoder::GetDeviceConfig();
144    }
145    return config;
146}
147
148bool SkImageDecoder::decode(SkStream* stream, SkBitmap* bm,
149                            SkBitmap::Config pref, Mode mode, bool reuseBitmap) {
150    // pass a temporary bitmap, so that if we return false, we are assured of
151    // leaving the caller's bitmap untouched.
152    SkBitmap    tmp;
153
154    // we reset this to false before calling onDecode
155    fShouldCancelDecode = false;
156    // assign this, for use by getPrefConfig(), in case fUsePrefTable is false
157    fDefaultPref = pref;
158
159    if (reuseBitmap) {
160        SkAutoLockPixels alp(*bm);
161        if (bm->getPixels() != NULL) {
162            return this->onDecode(stream, bm, mode);
163        }
164    }
165    if (!this->onDecode(stream, &tmp, mode)) {
166        return false;
167    }
168    bm->swap(tmp);
169    return true;
170}
171
172bool SkImageDecoder::decodeRegion(SkBitmap* bm, SkIRect rect,
173                                  SkBitmap::Config pref) {
174    // we reset this to false before calling onDecodeRegion
175    fShouldCancelDecode = false;
176    // assign this, for use by getPrefConfig(), in case fUsePrefTable is false
177    fDefaultPref = pref;
178
179    if (!this->onDecodeRegion(bm, rect)) {
180        return false;
181    }
182    return true;
183}
184
185bool SkImageDecoder::buildTileIndex(SkStream* stream,
186                                int *width, int *height) {
187    // we reset this to false before calling onBuildTileIndex
188    fShouldCancelDecode = false;
189
190    return this->onBuildTileIndex(stream, width, height);
191}
192
193void SkImageDecoder::cropBitmap(SkBitmap *dest, SkBitmap *src,
194                                    int sampleSize, int destX, int destY,
195                                    int width, int height, int srcX, int srcY) {
196    int w = width / sampleSize;
197    int h = height / sampleSize;
198    // if the destination has no pixels then we must allocate them.
199    if (dest->isNull()) {
200        dest->setConfig(src->getConfig(), w, h);
201        dest->setIsOpaque(src->isOpaque());
202
203        if (!this->allocPixelRef(dest, NULL)) {
204            SkDEBUGF(("failed to allocate pixels needed to crop the bitmap"));
205            return;
206        }
207    }
208    // check to see if the destination is large enough to decode the desired
209    // region. If this assert fails we will just draw as much of the source
210    // into the destination that we can.
211    SkASSERT(dest->width() >= w && dest->height() >= h);
212
213    // Set the Src_Mode for the paint to prevent transparency issue in the
214    // dest in the event that the dest was being re-used.
215    SkPaint paint;
216    paint.setXfermodeMode(SkXfermode::kSrc_Mode);
217
218    SkCanvas canvas(*dest);
219    canvas.drawSprite(*src, (srcX - destX) / sampleSize,
220                            (srcY - destY) / sampleSize,
221                            &paint);
222}
223
224///////////////////////////////////////////////////////////////////////////////
225
226bool SkImageDecoder::DecodeFile(const char file[], SkBitmap* bm,
227                            SkBitmap::Config pref,  Mode mode, Format* format) {
228    SkASSERT(file);
229    SkASSERT(bm);
230
231    SkFILEStream    stream(file);
232    if (stream.isValid()) {
233        if (SkImageDecoder::DecodeStream(&stream, bm, pref, mode, format)) {
234            bm->pixelRef()->setURI(file);
235            return true;
236        }
237    }
238    return false;
239}
240
241bool SkImageDecoder::DecodeMemory(const void* buffer, size_t size, SkBitmap* bm,
242                          SkBitmap::Config pref, Mode mode, Format* format) {
243    if (0 == size) {
244        return false;
245    }
246    SkASSERT(buffer);
247
248    SkMemoryStream  stream(buffer, size);
249    return SkImageDecoder::DecodeStream(&stream, bm, pref, mode, format);
250}
251
252bool SkImageDecoder::DecodeStream(SkStream* stream, SkBitmap* bm,
253                          SkBitmap::Config pref, Mode mode, Format* format) {
254    SkASSERT(stream);
255    SkASSERT(bm);
256
257    bool success = false;
258    SkImageDecoder* codec = SkImageDecoder::Factory(stream);
259
260    if (NULL != codec) {
261        success = codec->decode(stream, bm, pref, mode);
262        if (success && format) {
263            *format = codec->getFormat();
264        }
265        delete codec;
266    }
267    return success;
268}
269