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
17SkImageDecoder::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
34SkImageDecoder::~SkImageDecoder() {
35    SkSafeUnref(fPeeker);
36#ifdef SK_SUPPORT_LEGACY_IMAGEDECODER_CHOOSER
37    SkSafeUnref(fChooser);
38#endif
39    SkSafeUnref(fAllocator);
40}
41
42void 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
65SkImageDecoder::Format SkImageDecoder::getFormat() const {
66    return kUnknown_Format;
67}
68
69const char* SkImageDecoder::getFormatName() const {
70    return GetFormatName(this->getFormat());
71}
72
73const 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
101SkImageDecoder::Peeker* SkImageDecoder::setPeeker(Peeker* peeker) {
102    SkRefCnt_SafeAssign(fPeeker, peeker);
103    return peeker;
104}
105
106#ifdef SK_SUPPORT_LEGACY_IMAGEDECODER_CHOOSER
107SkImageDecoder::Chooser* SkImageDecoder::setChooser(Chooser* chooser) {
108    SkRefCnt_SafeAssign(fChooser, chooser);
109    return chooser;
110}
111#endif
112
113SkBitmap::Allocator* SkImageDecoder::setAllocator(SkBitmap::Allocator* alloc) {
114    SkRefCnt_SafeAssign(fAllocator, alloc);
115    return alloc;
116}
117
118void 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//
128bool 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
140bool 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
148void 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//
156SkColorType 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
183SkImageDecoder::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
200bool 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
209bool 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
216bool 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
265bool 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
280bool 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
291bool 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