/* * Copyright 2006 The Android Open Source Project * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "SkImageDecoder.h" #include "SkBitmap.h" #include "SkPixelRef.h" #include "SkStream.h" #include "SkTemplates.h" #include "SkCanvas.h" SK_DEFINE_INST_COUNT(SkImageDecoder::Peeker) SK_DEFINE_INST_COUNT(SkImageDecoder::Chooser) SK_DEFINE_INST_COUNT(SkImageDecoderFactory) SkVMMemoryReporter::~SkVMMemoryReporter() { } const char *SkImageDecoder::kFormatName[] = { "Unknown Format", "BMP", "GIF", "ICO", "JPEG", "PNG", "WBMP", "WEBP", }; static SkBitmap::Config gDeviceConfig = SkBitmap::kNo_Config; SkBitmap::Config SkImageDecoder::GetDeviceConfig() { return gDeviceConfig; } void SkImageDecoder::SetDeviceConfig(SkBitmap::Config config) { gDeviceConfig = config; } /////////////////////////////////////////////////////////////////////////////// SkImageDecoder::SkImageDecoder() : fReporter(NULL), fPeeker(NULL), fChooser(NULL), fAllocator(NULL), fSampleSize(1), fDefaultPref(SkBitmap::kNo_Config), fDitherImage(true), fUsePrefTable(false),fPreferQualityOverSpeed(false) { } SkImageDecoder::~SkImageDecoder() { SkSafeUnref(fPeeker); SkSafeUnref(fChooser); SkSafeUnref(fAllocator); SkSafeUnref(fReporter); } SkImageDecoder::Format SkImageDecoder::getFormat() const { return kUnknown_Format; } SkImageDecoder::Peeker* SkImageDecoder::setPeeker(Peeker* peeker) { SkRefCnt_SafeAssign(fPeeker, peeker); return peeker; } SkImageDecoder::Chooser* SkImageDecoder::setChooser(Chooser* chooser) { SkRefCnt_SafeAssign(fChooser, chooser); return chooser; } SkBitmap::Allocator* SkImageDecoder::setAllocator(SkBitmap::Allocator* alloc) { SkRefCnt_SafeAssign(fAllocator, alloc); return alloc; } SkVMMemoryReporter* SkImageDecoder::setReporter(SkVMMemoryReporter* reporter) { SkRefCnt_SafeAssign(fReporter, reporter); return reporter; } void SkImageDecoder::setSampleSize(int size) { if (size < 1) { size = 1; } fSampleSize = size; } bool SkImageDecoder::chooseFromOneChoice(SkBitmap::Config config, int width, int height) const { Chooser* chooser = fChooser; if (NULL == chooser) { // no chooser, we just say YES to decoding :) return true; } chooser->begin(1); chooser->inspect(0, config, width, height); return chooser->choose() == 0; } bool SkImageDecoder::allocPixelRef(SkBitmap* bitmap, SkColorTable* ctable) const { return bitmap->allocPixels(fAllocator, ctable); } /////////////////////////////////////////////////////////////////////////////// void SkImageDecoder::setPrefConfigTable(const SkBitmap::Config pref[6]) { if (NULL == pref) { fUsePrefTable = false; } else { fUsePrefTable = true; memcpy(fPrefTable, pref, sizeof(fPrefTable)); } } SkBitmap::Config SkImageDecoder::getPrefConfig(SrcDepth srcDepth, bool srcHasAlpha) const { SkBitmap::Config config; if (fUsePrefTable) { int index = 0; switch (srcDepth) { case kIndex_SrcDepth: index = 0; break; case k16Bit_SrcDepth: index = 2; break; case k32Bit_SrcDepth: index = 4; break; } if (srcHasAlpha) { index += 1; } config = fPrefTable[index]; } else { config = fDefaultPref; } if (SkBitmap::kNo_Config == config) { config = SkImageDecoder::GetDeviceConfig(); } return config; } bool SkImageDecoder::decode(SkStream* stream, SkBitmap* bm, SkBitmap::Config pref, Mode mode, bool reuseBitmap) { // pass a temporary bitmap, so that if we return false, we are assured of // leaving the caller's bitmap untouched. SkBitmap tmp; // we reset this to false before calling onDecode fShouldCancelDecode = false; // assign this, for use by getPrefConfig(), in case fUsePrefTable is false fDefaultPref = pref; if (reuseBitmap) { SkAutoLockPixels alp(*bm); if (bm->getPixels() != NULL) { return this->onDecode(stream, bm, mode); } } if (!this->onDecode(stream, &tmp, mode)) { return false; } bm->swap(tmp); return true; } bool SkImageDecoder::decodeRegion(SkBitmap* bm, SkIRect rect, SkBitmap::Config pref) { // we reset this to false before calling onDecodeRegion fShouldCancelDecode = false; // assign this, for use by getPrefConfig(), in case fUsePrefTable is false fDefaultPref = pref; if (!this->onDecodeRegion(bm, rect)) { return false; } return true; } bool SkImageDecoder::buildTileIndex(SkStream* stream, int *width, int *height) { // we reset this to false before calling onBuildTileIndex fShouldCancelDecode = false; return this->onBuildTileIndex(stream, width, height); } void SkImageDecoder::cropBitmap(SkBitmap *dest, SkBitmap *src, int sampleSize, int destX, int destY, int width, int height, int srcX, int srcY) { int w = width / sampleSize; int h = height / sampleSize; // if the destination has no pixels then we must allocate them. if (dest->isNull()) { dest->setConfig(src->getConfig(), w, h); dest->setIsOpaque(src->isOpaque()); if (!this->allocPixelRef(dest, NULL)) { SkDEBUGF(("failed to allocate pixels needed to crop the bitmap")); return; } } // check to see if the destination is large enough to decode the desired // region. If this assert fails we will just draw as much of the source // into the destination that we can. SkASSERT(dest->width() >= w && dest->height() >= h); // Set the Src_Mode for the paint to prevent transparency issue in the // dest in the event that the dest was being re-used. SkPaint paint; paint.setXfermodeMode(SkXfermode::kSrc_Mode); SkCanvas canvas(*dest); canvas.drawSprite(*src, (srcX - destX) / sampleSize, (srcY - destY) / sampleSize, &paint); } /////////////////////////////////////////////////////////////////////////////// bool SkImageDecoder::DecodeFile(const char file[], SkBitmap* bm, SkBitmap::Config pref, Mode mode, Format* format) { SkASSERT(file); SkASSERT(bm); SkFILEStream stream(file); if (stream.isValid()) { if (SkImageDecoder::DecodeStream(&stream, bm, pref, mode, format)) { bm->pixelRef()->setURI(file); return true; } } return false; } bool SkImageDecoder::DecodeMemory(const void* buffer, size_t size, SkBitmap* bm, SkBitmap::Config pref, Mode mode, Format* format) { if (0 == size) { return false; } SkASSERT(buffer); SkMemoryStream stream(buffer, size); return SkImageDecoder::DecodeStream(&stream, bm, pref, mode, format); } bool SkImageDecoder::DecodeStream(SkStream* stream, SkBitmap* bm, SkBitmap::Config pref, Mode mode, Format* format) { SkASSERT(stream); SkASSERT(bm); bool success = false; SkImageDecoder* codec = SkImageDecoder::Factory(stream); if (NULL != codec) { success = codec->decode(stream, bm, pref, mode); if (success && format) { *format = codec->getFormat(); } delete codec; } return success; }