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