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    , fAllocator(NULL)
20    , fSampleSize(1)
21    , fDefaultPref(kUnknown_SkColorType)
22    , fPreserveSrcDepth(false)
23    , fDitherImage(true)
24    , fSkipWritingZeroes(false)
25    , fPreferQualityOverSpeed(false)
26    , fRequireUnpremultipliedColors(false) {
27}
28
29SkImageDecoder::~SkImageDecoder() {
30    SkSafeUnref(fPeeker);
31    SkSafeUnref(fAllocator);
32}
33
34void SkImageDecoder::copyFieldsToOther(SkImageDecoder* other) {
35    if (NULL == other) {
36        return;
37    }
38    other->setPeeker(fPeeker);
39    other->setAllocator(fAllocator);
40    other->setSampleSize(fSampleSize);
41    other->setPreserveSrcDepth(fPreserveSrcDepth);
42    other->setDitherImage(fDitherImage);
43    other->setSkipWritingZeroes(fSkipWritingZeroes);
44    other->setPreferQualityOverSpeed(fPreferQualityOverSpeed);
45    other->setRequireUnpremultipliedColors(fRequireUnpremultipliedColors);
46}
47
48SkImageDecoder::Format SkImageDecoder::getFormat() const {
49    return kUnknown_Format;
50}
51
52const char* SkImageDecoder::getFormatName() const {
53    return GetFormatName(this->getFormat());
54}
55
56const char* SkImageDecoder::GetFormatName(Format format) {
57    switch (format) {
58        case kUnknown_Format:
59            return "Unknown Format";
60        case kBMP_Format:
61            return "BMP";
62        case kGIF_Format:
63            return "GIF";
64        case kICO_Format:
65            return "ICO";
66        case kPKM_Format:
67            return "PKM";
68        case kKTX_Format:
69            return "KTX";
70        case kASTC_Format:
71            return "ASTC";
72        case kJPEG_Format:
73            return "JPEG";
74        case kPNG_Format:
75            return "PNG";
76        case kWBMP_Format:
77            return "WBMP";
78        case kWEBP_Format:
79            return "WEBP";
80        default:
81            SkDEBUGFAIL("Invalid format type!");
82    }
83    return "Unknown Format";
84}
85
86SkImageDecoder::Peeker* SkImageDecoder::setPeeker(Peeker* peeker) {
87    SkRefCnt_SafeAssign(fPeeker, peeker);
88    return peeker;
89}
90
91SkBitmap::Allocator* SkImageDecoder::setAllocator(SkBitmap::Allocator* alloc) {
92    SkRefCnt_SafeAssign(fAllocator, alloc);
93    return alloc;
94}
95
96void SkImageDecoder::setSampleSize(int size) {
97    if (size < 1) {
98        size = 1;
99    }
100    fSampleSize = size;
101}
102
103bool SkImageDecoder::allocPixelRef(SkBitmap* bitmap,
104                                   SkColorTable* ctable) const {
105    return bitmap->tryAllocPixels(fAllocator, ctable);
106}
107
108///////////////////////////////////////////////////////////////////////////////
109
110SkColorType SkImageDecoder::getPrefColorType(SrcDepth srcDepth, bool srcHasAlpha) const {
111    SkColorType ct = fDefaultPref;
112    if (fPreserveSrcDepth) {
113        switch (srcDepth) {
114            case kIndex_SrcDepth:
115                ct = kIndex_8_SkColorType;
116                break;
117            case k8BitGray_SrcDepth:
118                ct = kN32_SkColorType;
119                break;
120            case k32Bit_SrcDepth:
121                ct = kN32_SkColorType;
122                break;
123        }
124    }
125    return ct;
126}
127
128SkImageDecoder::Result SkImageDecoder::decode(SkStream* stream, SkBitmap* bm, SkColorType pref,
129                                              Mode mode) {
130    // we reset this to false before calling onDecode
131    fShouldCancelDecode = false;
132    // assign this, for use by getPrefColorType(), in case fUsePrefTable is false
133    fDefaultPref = pref;
134
135    // pass a temporary bitmap, so that if we return false, we are assured of
136    // leaving the caller's bitmap untouched.
137    SkBitmap tmp;
138    const Result result = this->onDecode(stream, &tmp, mode);
139    if (kFailure != result) {
140        bm->swap(tmp);
141    }
142    return result;
143}
144
145bool SkImageDecoder::decodeSubset(SkBitmap* bm, const SkIRect& rect, SkColorType pref) {
146    // we reset this to false before calling onDecodeSubset
147    fShouldCancelDecode = false;
148    // assign this, for use by getPrefColorType(), in case fUsePrefTable is false
149    fDefaultPref = pref;
150
151    return this->onDecodeSubset(bm, rect);
152}
153
154bool SkImageDecoder::buildTileIndex(SkStreamRewindable* stream, int *width, int *height) {
155    // we reset this to false before calling onBuildTileIndex
156    fShouldCancelDecode = false;
157
158    return this->onBuildTileIndex(stream, width, height);
159}
160
161bool SkImageDecoder::onBuildTileIndex(SkStreamRewindable* stream, int* /*width*/,
162                                      int* /*height*/) {
163    SkDELETE(stream);
164    return false;
165}
166
167
168bool SkImageDecoder::cropBitmap(SkBitmap *dst, SkBitmap *src, int sampleSize,
169                                int dstX, int dstY, int width, int height,
170                                int srcX, int srcY) {
171    int w = width / sampleSize;
172    int h = height / sampleSize;
173    if (src->colorType() == kIndex_8_SkColorType) {
174        // kIndex8 does not allow drawing via an SkCanvas, as is done below.
175        // Instead, use extractSubset. Note that this shares the SkPixelRef and
176        // SkColorTable.
177        // FIXME: Since src is discarded in practice, this holds on to more
178        // pixels than is strictly necessary. Switch to a copy if memory
179        // savings are more important than speed here. This also means
180        // that the pixels in dst can not be reused (though there is no
181        // allocation, which was already done on src).
182        int x = (dstX - srcX) / sampleSize;
183        int y = (dstY - srcY) / sampleSize;
184        SkIRect subset = SkIRect::MakeXYWH(x, y, w, h);
185        return src->extractSubset(dst, subset);
186    }
187    // if the destination has no pixels then we must allocate them.
188    if (dst->isNull()) {
189        dst->setInfo(src->info().makeWH(w, h));
190
191        if (!this->allocPixelRef(dst, NULL)) {
192            SkDEBUGF(("failed to allocate pixels needed to crop the bitmap"));
193            return false;
194        }
195    }
196    // check to see if the destination is large enough to decode the desired
197    // region. If this assert fails we will just draw as much of the source
198    // into the destination that we can.
199    if (dst->width() < w || dst->height() < h) {
200        SkDEBUGF(("SkImageDecoder::cropBitmap does not have a large enough bitmap.\n"));
201    }
202
203    // Set the Src_Mode for the paint to prevent transparency issue in the
204    // dest in the event that the dest was being re-used.
205    SkPaint paint;
206    paint.setXfermodeMode(SkXfermode::kSrc_Mode);
207
208    SkCanvas canvas(*dst);
209    canvas.drawSprite(*src, (srcX - dstX) / sampleSize,
210                            (srcY - dstY) / sampleSize,
211                            &paint);
212    return true;
213}
214
215///////////////////////////////////////////////////////////////////////////////
216
217bool SkImageDecoder::DecodeFile(const char file[], SkBitmap* bm, SkColorType pref,  Mode mode,
218                                Format* format) {
219    SkASSERT(file);
220    SkASSERT(bm);
221
222    SkAutoTDelete<SkStreamRewindable> stream(SkStream::NewFromFile(file));
223    if (stream.get()) {
224        if (SkImageDecoder::DecodeStream(stream, bm, pref, mode, format)) {
225            if (SkPixelRef* pr = bm->pixelRef()) {
226                pr->setURI(file);
227            }
228            return true;
229        }
230    }
231    return false;
232}
233
234bool SkImageDecoder::DecodeMemory(const void* buffer, size_t size, SkBitmap* bm, SkColorType pref,
235                                  Mode mode, Format* format) {
236    if (0 == size) {
237        return false;
238    }
239    SkASSERT(buffer);
240
241    SkMemoryStream  stream(buffer, size);
242    return SkImageDecoder::DecodeStream(&stream, bm, pref, mode, format);
243}
244
245bool SkImageDecoder::DecodeStream(SkStreamRewindable* stream, SkBitmap* bm, SkColorType pref,
246                                  Mode mode, Format* format) {
247    SkASSERT(stream);
248    SkASSERT(bm);
249
250    bool success = false;
251    SkImageDecoder* codec = SkImageDecoder::Factory(stream);
252
253    if (codec) {
254        success = codec->decode(stream, bm, pref, mode) != kFailure;
255        if (success && format) {
256            *format = codec->getFormat();
257            if (kUnknown_Format == *format) {
258                if (stream->rewind()) {
259                    *format = GetStreamFormat(stream);
260                }
261            }
262        }
263        delete codec;
264    }
265    return success;
266}
267
268bool SkImageDecoder::decodeYUV8Planes(SkStream* stream, SkISize componentSizes[3], void* planes[3],
269                                      size_t rowBytes[3], SkYUVColorSpace* colorSpace) {
270    // we reset this to false before calling onDecodeYUV8Planes
271    fShouldCancelDecode = false;
272
273    return this->onDecodeYUV8Planes(stream, componentSizes, planes, rowBytes, colorSpace);
274}
275