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
SkImageDecoder()17 SkImageDecoder::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
~SkImageDecoder()29 SkImageDecoder::~SkImageDecoder() {
30 SkSafeUnref(fPeeker);
31 SkSafeUnref(fAllocator);
32 }
33
copyFieldsToOther(SkImageDecoder * other)34 void 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
getFormat() const48 SkImageDecoder::Format SkImageDecoder::getFormat() const {
49 return kUnknown_Format;
50 }
51
getFormatName() const52 const char* SkImageDecoder::getFormatName() const {
53 return GetFormatName(this->getFormat());
54 }
55
GetFormatName(Format format)56 const 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
setPeeker(Peeker * peeker)86 SkImageDecoder::Peeker* SkImageDecoder::setPeeker(Peeker* peeker) {
87 SkRefCnt_SafeAssign(fPeeker, peeker);
88 return peeker;
89 }
90
setAllocator(SkBitmap::Allocator * alloc)91 SkBitmap::Allocator* SkImageDecoder::setAllocator(SkBitmap::Allocator* alloc) {
92 SkRefCnt_SafeAssign(fAllocator, alloc);
93 return alloc;
94 }
95
setSampleSize(int size)96 void SkImageDecoder::setSampleSize(int size) {
97 if (size < 1) {
98 size = 1;
99 }
100 fSampleSize = size;
101 }
102
allocPixelRef(SkBitmap * bitmap,SkColorTable * ctable) const103 bool SkImageDecoder::allocPixelRef(SkBitmap* bitmap,
104 SkColorTable* ctable) const {
105 return bitmap->tryAllocPixels(fAllocator, ctable);
106 }
107
108 ///////////////////////////////////////////////////////////////////////////////
109
getPrefColorType(SrcDepth srcDepth,bool srcHasAlpha) const110 SkColorType 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
decode(SkStream * stream,SkBitmap * bm,SkColorType pref,Mode mode)128 SkImageDecoder::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
decodeSubset(SkBitmap * bm,const SkIRect & rect,SkColorType pref)145 bool 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
buildTileIndex(SkStreamRewindable * stream,int * width,int * height)154 bool 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
onBuildTileIndex(SkStreamRewindable * stream,int *,int *)161 bool SkImageDecoder::onBuildTileIndex(SkStreamRewindable* stream, int* /*width*/,
162 int* /*height*/) {
163 SkDELETE(stream);
164 return false;
165 }
166
167
cropBitmap(SkBitmap * dst,SkBitmap * src,int sampleSize,int dstX,int dstY,int width,int height,int srcX,int srcY)168 bool 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
DecodeFile(const char file[],SkBitmap * bm,SkColorType pref,Mode mode,Format * format)217 bool 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
DecodeMemory(const void * buffer,size_t size,SkBitmap * bm,SkColorType pref,Mode mode,Format * format)234 bool 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
DecodeStream(SkStreamRewindable * stream,SkBitmap * bm,SkColorType pref,Mode mode,Format * format)245 bool 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
decodeYUV8Planes(SkStream * stream,SkISize componentSizes[3],void * planes[3],size_t rowBytes[3],SkYUVColorSpace * colorSpace)268 bool 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