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