1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/images/SkDecodingImageGenerator.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,256 @@ 1.4 +/* 1.5 + * Copyright 2013 Google Inc. 1.6 + * 1.7 + * Use of this source code is governed by a BSD-style license that can be 1.8 + * found in the LICENSE file. 1.9 + */ 1.10 + 1.11 +#include "SkData.h" 1.12 +#include "SkDecodingImageGenerator.h" 1.13 +#include "SkImageDecoder.h" 1.14 +#include "SkImageInfo.h" 1.15 +#include "SkImageGenerator.h" 1.16 +#include "SkImagePriv.h" 1.17 +#include "SkStream.h" 1.18 +#include "SkUtils.h" 1.19 + 1.20 +static bool equal_modulo_alpha(const SkImageInfo& a, const SkImageInfo& b) { 1.21 + return a.width() == b.width() && a.height() == b.height() && 1.22 + a.colorType() == b.colorType(); 1.23 +} 1.24 + 1.25 +namespace { 1.26 +/** 1.27 + * Special allocator used by getPixels(). Uses preallocated memory 1.28 + * provided if possible, else fall-back on the default allocator 1.29 + */ 1.30 +class TargetAllocator : public SkBitmap::Allocator { 1.31 +public: 1.32 + TargetAllocator(const SkImageInfo& info, 1.33 + void* target, 1.34 + size_t rowBytes) 1.35 + : fInfo(info) 1.36 + , fTarget(target) 1.37 + , fRowBytes(rowBytes) 1.38 + {} 1.39 + 1.40 + bool isReady() { return (fTarget != NULL); } 1.41 + 1.42 + virtual bool allocPixelRef(SkBitmap* bm, SkColorTable* ct) { 1.43 + if (NULL == fTarget || !equal_modulo_alpha(fInfo, bm->info())) { 1.44 + // Call default allocator. 1.45 + return bm->allocPixels(NULL, ct); 1.46 + } 1.47 + 1.48 + // TODO(halcanary): verify that all callers of this function 1.49 + // will respect new RowBytes. Will be moot once rowbytes belongs 1.50 + // to PixelRef. 1.51 + bm->installPixels(fInfo, fTarget, fRowBytes, NULL, NULL); 1.52 + 1.53 + fTarget = NULL; // never alloc same pixels twice! 1.54 + return true; 1.55 + } 1.56 + 1.57 +private: 1.58 + const SkImageInfo fInfo; 1.59 + void* fTarget; // Block of memory to be supplied as pixel memory 1.60 + // in allocPixelRef. Must be large enough to hold 1.61 + // a bitmap described by fInfo and fRowBytes 1.62 + const size_t fRowBytes; // rowbytes for the destination bitmap 1.63 + 1.64 + typedef SkBitmap::Allocator INHERITED; 1.65 +}; 1.66 + 1.67 +// TODO(halcanary): Give this macro a better name and move it into SkTypes.h 1.68 +#ifdef SK_DEBUG 1.69 + #define SkCheckResult(expr, value) SkASSERT((value) == (expr)) 1.70 +#else 1.71 + #define SkCheckResult(expr, value) (void)(expr) 1.72 +#endif 1.73 + 1.74 +#ifdef SK_DEBUG 1.75 +inline bool check_alpha(SkAlphaType reported, SkAlphaType actual) { 1.76 + return ((reported == actual) 1.77 + || ((reported == kPremul_SkAlphaType) 1.78 + && (actual == kOpaque_SkAlphaType))); 1.79 +} 1.80 +#endif // SK_DEBUG 1.81 + 1.82 +} // namespace 1.83 +//////////////////////////////////////////////////////////////////////////////// 1.84 + 1.85 +SkDecodingImageGenerator::SkDecodingImageGenerator( 1.86 + SkData* data, 1.87 + SkStreamRewindable* stream, 1.88 + const SkImageInfo& info, 1.89 + int sampleSize, 1.90 + bool ditherImage) 1.91 + : fData(data) 1.92 + , fStream(stream) 1.93 + , fInfo(info) 1.94 + , fSampleSize(sampleSize) 1.95 + , fDitherImage(ditherImage) 1.96 +{ 1.97 + SkASSERT(stream != NULL); 1.98 + SkSafeRef(fData); // may be NULL. 1.99 +} 1.100 + 1.101 +SkDecodingImageGenerator::~SkDecodingImageGenerator() { 1.102 + SkSafeUnref(fData); 1.103 + fStream->unref(); 1.104 +} 1.105 + 1.106 +bool SkDecodingImageGenerator::getInfo(SkImageInfo* info) { 1.107 + if (info != NULL) { 1.108 + *info = fInfo; 1.109 + } 1.110 + return true; 1.111 +} 1.112 + 1.113 +SkData* SkDecodingImageGenerator::refEncodedData() { 1.114 + // This functionality is used in `gm --serialize` 1.115 + // Does not encode options. 1.116 + if (fData != NULL) { 1.117 + return SkSafeRef(fData); 1.118 + } 1.119 + // TODO(halcanary): SkStreamRewindable needs a refData() function 1.120 + // which returns a cheap copy of the underlying data. 1.121 + if (!fStream->rewind()) { 1.122 + return NULL; 1.123 + } 1.124 + size_t length = fStream->getLength(); 1.125 + if (0 == length) { 1.126 + return NULL; 1.127 + } 1.128 + void* buffer = sk_malloc_flags(length, 0); 1.129 + SkCheckResult(fStream->read(buffer, length), length); 1.130 + fData = SkData::NewFromMalloc(buffer, length); 1.131 + return SkSafeRef(fData); 1.132 +} 1.133 + 1.134 +bool SkDecodingImageGenerator::getPixels(const SkImageInfo& info, 1.135 + void* pixels, 1.136 + size_t rowBytes) { 1.137 + if (NULL == pixels) { 1.138 + return false; 1.139 + } 1.140 + if (fInfo != info) { 1.141 + // The caller has specified a different info. This is an 1.142 + // error for this kind of SkImageGenerator. Use the Options 1.143 + // to change the settings. 1.144 + return false; 1.145 + } 1.146 + if (info.minRowBytes() > rowBytes) { 1.147 + // The caller has specified a bad rowBytes. 1.148 + return false; 1.149 + } 1.150 + 1.151 + SkAssertResult(fStream->rewind()); 1.152 + SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(fStream)); 1.153 + if (NULL == decoder.get()) { 1.154 + return false; 1.155 + } 1.156 + decoder->setDitherImage(fDitherImage); 1.157 + decoder->setSampleSize(fSampleSize); 1.158 + 1.159 + SkBitmap bitmap; 1.160 + TargetAllocator allocator(fInfo, pixels, rowBytes); 1.161 + decoder->setAllocator(&allocator); 1.162 + // TODO: need to be able to pass colortype directly to decoder 1.163 + SkBitmap::Config legacyConfig = SkColorTypeToBitmapConfig(info.colorType()); 1.164 + bool success = decoder->decode(fStream, &bitmap, legacyConfig, 1.165 + SkImageDecoder::kDecodePixels_Mode); 1.166 + decoder->setAllocator(NULL); 1.167 + if (!success) { 1.168 + return false; 1.169 + } 1.170 + if (allocator.isReady()) { // Did not use pixels! 1.171 + SkBitmap bm; 1.172 + SkASSERT(bitmap.canCopyTo(info.colorType())); 1.173 + bool copySuccess = bitmap.copyTo(&bm, info.colorType(), &allocator); 1.174 + if (!copySuccess || allocator.isReady()) { 1.175 + SkDEBUGFAIL("bitmap.copyTo(requestedConfig) failed."); 1.176 + // Earlier we checked canCopyto(); we expect consistency. 1.177 + return false; 1.178 + } 1.179 + SkASSERT(check_alpha(info.alphaType(), bm.alphaType())); 1.180 + } else { 1.181 + SkASSERT(check_alpha(info.alphaType(), bitmap.alphaType())); 1.182 + } 1.183 + return true; 1.184 +} 1.185 + 1.186 +SkImageGenerator* SkDecodingImageGenerator::Create( 1.187 + SkData* data, 1.188 + const SkDecodingImageGenerator::Options& opts) { 1.189 + SkASSERT(data != NULL); 1.190 + if (NULL == data) { 1.191 + return NULL; 1.192 + } 1.193 + SkStreamRewindable* stream = SkNEW_ARGS(SkMemoryStream, (data)); 1.194 + SkASSERT(stream != NULL); 1.195 + SkASSERT(stream->unique()); 1.196 + return SkDecodingImageGenerator::Create(data, stream, opts); 1.197 +} 1.198 + 1.199 +SkImageGenerator* SkDecodingImageGenerator::Create( 1.200 + SkStreamRewindable* stream, 1.201 + const SkDecodingImageGenerator::Options& opts) { 1.202 + SkASSERT(stream != NULL); 1.203 + SkASSERT(stream->unique()); 1.204 + if ((stream == NULL) || !stream->unique()) { 1.205 + SkSafeUnref(stream); 1.206 + return NULL; 1.207 + } 1.208 + return SkDecodingImageGenerator::Create(NULL, stream, opts); 1.209 +} 1.210 + 1.211 +// A contructor-type function that returns NULL on failure. This 1.212 +// prevents the returned SkImageGenerator from ever being in a bad 1.213 +// state. Called by both Create() functions 1.214 +SkImageGenerator* SkDecodingImageGenerator::Create( 1.215 + SkData* data, 1.216 + SkStreamRewindable* stream, 1.217 + const SkDecodingImageGenerator::Options& opts) { 1.218 + SkASSERT(stream); 1.219 + SkAutoTUnref<SkStreamRewindable> autoStream(stream); // always unref this. 1.220 + if (opts.fUseRequestedColorType && 1.221 + (kIndex_8_SkColorType == opts.fRequestedColorType)) { 1.222 + // We do not support indexed color with SkImageGenerators, 1.223 + return NULL; 1.224 + } 1.225 + SkAssertResult(autoStream->rewind()); 1.226 + SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(autoStream)); 1.227 + if (NULL == decoder.get()) { 1.228 + return NULL; 1.229 + } 1.230 + SkBitmap bitmap; 1.231 + decoder->setSampleSize(opts.fSampleSize); 1.232 + if (!decoder->decode(stream, &bitmap, 1.233 + SkImageDecoder::kDecodeBounds_Mode)) { 1.234 + return NULL; 1.235 + } 1.236 + if (bitmap.config() == SkBitmap::kNo_Config) { 1.237 + return NULL; 1.238 + } 1.239 + 1.240 + SkImageInfo info = bitmap.info(); 1.241 + 1.242 + if (!opts.fUseRequestedColorType) { 1.243 + // Use default 1.244 + if (kIndex_8_SkColorType == bitmap.colorType()) { 1.245 + // We don't support kIndex8 because we don't support 1.246 + // colortables in this workflow. 1.247 + info.fColorType = kPMColor_SkColorType; 1.248 + } 1.249 + } else { 1.250 + if (!bitmap.canCopyTo(opts.fRequestedColorType)) { 1.251 + SkASSERT(bitmap.colorType() != opts.fRequestedColorType); 1.252 + return NULL; // Can not translate to needed config. 1.253 + } 1.254 + info.fColorType = opts.fRequestedColorType; 1.255 + } 1.256 + return SkNEW_ARGS(SkDecodingImageGenerator, 1.257 + (data, autoStream.detach(), info, 1.258 + opts.fSampleSize, opts.fDitherImage)); 1.259 +}