1/* 2 * Copyright 2013 Google Inc. 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#include "SkData.h" 9#include "SkDecodingImageGenerator.h" 10#include "SkImageDecoder.h" 11#include "SkImageInfo.h" 12#include "SkImageGenerator.h" 13#include "SkImagePriv.h" 14#include "SkStream.h" 15#include "SkUtils.h" 16 17namespace { 18bool equal_modulo_alpha(const SkImageInfo& a, const SkImageInfo& b) { 19 return a.width() == b.width() && a.height() == b.height() && 20 a.colorType() == b.colorType(); 21} 22 23class DecodingImageGenerator : public SkImageGenerator { 24public: 25 virtual ~DecodingImageGenerator(); 26 27 SkData* fData; 28 SkStreamRewindable* fStream; 29 const SkImageInfo fInfo; 30 const int fSampleSize; 31 const bool fDitherImage; 32 33 DecodingImageGenerator(SkData* data, 34 SkStreamRewindable* stream, 35 const SkImageInfo& info, 36 int sampleSize, 37 bool ditherImage); 38 39protected: 40 virtual SkData* onRefEncodedData() SK_OVERRIDE; 41 virtual bool onGetInfo(SkImageInfo* info) SK_OVERRIDE { 42 *info = fInfo; 43 return true; 44 } 45 virtual bool onGetPixels(const SkImageInfo& info, 46 void* pixels, size_t rowBytes, 47 SkPMColor ctable[], int* ctableCount) SK_OVERRIDE; 48 49private: 50 typedef SkImageGenerator INHERITED; 51}; 52 53/** 54 * Special allocator used by getPixels(). Uses preallocated memory 55 * provided if possible, else fall-back on the default allocator 56 */ 57class TargetAllocator : public SkBitmap::Allocator { 58public: 59 TargetAllocator(const SkImageInfo& info, 60 void* target, 61 size_t rowBytes) 62 : fInfo(info) 63 , fTarget(target) 64 , fRowBytes(rowBytes) 65 {} 66 67 bool isReady() { return (fTarget != NULL); } 68 69 virtual bool allocPixelRef(SkBitmap* bm, SkColorTable* ct) { 70 if (NULL == fTarget || !equal_modulo_alpha(fInfo, bm->info())) { 71 // Call default allocator. 72 return bm->tryAllocPixels(NULL, ct); 73 } 74 75 // TODO(halcanary): verify that all callers of this function 76 // will respect new RowBytes. Will be moot once rowbytes belongs 77 // to PixelRef. 78 bm->installPixels(fInfo, fTarget, fRowBytes, ct, NULL, NULL); 79 80 fTarget = NULL; // never alloc same pixels twice! 81 return true; 82 } 83 84private: 85 const SkImageInfo fInfo; 86 void* fTarget; // Block of memory to be supplied as pixel memory 87 // in allocPixelRef. Must be large enough to hold 88 // a bitmap described by fInfo and fRowBytes 89 const size_t fRowBytes; // rowbytes for the destination bitmap 90 91 typedef SkBitmap::Allocator INHERITED; 92}; 93 94// TODO(halcanary): Give this macro a better name and move it into SkTypes.h 95#ifdef SK_DEBUG 96 #define SkCheckResult(expr, value) SkASSERT((value) == (expr)) 97#else 98 #define SkCheckResult(expr, value) (void)(expr) 99#endif 100 101#ifdef SK_DEBUG 102inline bool check_alpha(SkAlphaType reported, SkAlphaType actual) { 103 return ((reported == actual) 104 || ((reported == kPremul_SkAlphaType) 105 && (actual == kOpaque_SkAlphaType))); 106} 107#endif // SK_DEBUG 108 109//////////////////////////////////////////////////////////////////////////////// 110 111DecodingImageGenerator::DecodingImageGenerator( 112 SkData* data, 113 SkStreamRewindable* stream, 114 const SkImageInfo& info, 115 int sampleSize, 116 bool ditherImage) 117 : fData(data) 118 , fStream(stream) 119 , fInfo(info) 120 , fSampleSize(sampleSize) 121 , fDitherImage(ditherImage) 122{ 123 SkASSERT(stream != NULL); 124 SkSafeRef(fData); // may be NULL. 125} 126 127DecodingImageGenerator::~DecodingImageGenerator() { 128 SkSafeUnref(fData); 129 fStream->unref(); 130} 131 132SkData* DecodingImageGenerator::onRefEncodedData() { 133 // This functionality is used in `gm --serialize` 134 // Does not encode options. 135 if (NULL == fData) { 136 // TODO(halcanary): SkStreamRewindable needs a refData() function 137 // which returns a cheap copy of the underlying data. 138 if (!fStream->rewind()) { 139 return NULL; 140 } 141 size_t length = fStream->getLength(); 142 if (length) { 143 fData = SkData::NewFromStream(fStream, length); 144 } 145 } 146 return SkSafeRef(fData); 147} 148 149bool DecodingImageGenerator::onGetPixels(const SkImageInfo& info, 150 void* pixels, size_t rowBytes, 151 SkPMColor ctableEntries[], int* ctableCount) { 152 if (fInfo != info) { 153 // The caller has specified a different info. This is an 154 // error for this kind of SkImageGenerator. Use the Options 155 // to change the settings. 156 return false; 157 } 158 159 SkAssertResult(fStream->rewind()); 160 SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(fStream)); 161 if (NULL == decoder.get()) { 162 return false; 163 } 164 decoder->setDitherImage(fDitherImage); 165 decoder->setSampleSize(fSampleSize); 166 decoder->setRequireUnpremultipliedColors(info.alphaType() == kUnpremul_SkAlphaType); 167 168 SkBitmap bitmap; 169 TargetAllocator allocator(fInfo, pixels, rowBytes); 170 decoder->setAllocator(&allocator); 171 bool success = decoder->decode(fStream, &bitmap, info.colorType(), 172 SkImageDecoder::kDecodePixels_Mode); 173 decoder->setAllocator(NULL); 174 if (!success) { 175 return false; 176 } 177 if (allocator.isReady()) { // Did not use pixels! 178 SkBitmap bm; 179 SkASSERT(bitmap.canCopyTo(info.colorType())); 180 bool copySuccess = bitmap.copyTo(&bm, info.colorType(), &allocator); 181 if (!copySuccess || allocator.isReady()) { 182 SkDEBUGFAIL("bitmap.copyTo(requestedConfig) failed."); 183 // Earlier we checked canCopyto(); we expect consistency. 184 return false; 185 } 186 SkASSERT(check_alpha(info.alphaType(), bm.alphaType())); 187 } else { 188 SkASSERT(check_alpha(info.alphaType(), bitmap.alphaType())); 189 } 190 191 if (kIndex_8_SkColorType == info.colorType()) { 192 if (kIndex_8_SkColorType != bitmap.colorType()) { 193 return false; // they asked for Index8, but we didn't receive that from decoder 194 } 195 SkColorTable* ctable = bitmap.getColorTable(); 196 if (NULL == ctable) { 197 return false; 198 } 199 const int count = ctable->count(); 200 memcpy(ctableEntries, ctable->lockColors(), count * sizeof(SkPMColor)); 201 ctable->unlockColors(); 202 *ctableCount = count; 203 } 204 return true; 205} 206 207// A contructor-type function that returns NULL on failure. This 208// prevents the returned SkImageGenerator from ever being in a bad 209// state. Called by both Create() functions 210SkImageGenerator* CreateDecodingImageGenerator( 211 SkData* data, 212 SkStreamRewindable* stream, 213 const SkDecodingImageGenerator::Options& opts) { 214 SkASSERT(stream); 215 SkAutoTUnref<SkStreamRewindable> autoStream(stream); // always unref this. 216 SkAssertResult(autoStream->rewind()); 217 SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(autoStream)); 218 if (NULL == decoder.get()) { 219 return NULL; 220 } 221 SkBitmap bitmap; 222 decoder->setSampleSize(opts.fSampleSize); 223 decoder->setRequireUnpremultipliedColors(opts.fRequireUnpremul); 224 if (!decoder->decode(stream, &bitmap, SkImageDecoder::kDecodeBounds_Mode)) { 225 return NULL; 226 } 227 if (kUnknown_SkColorType == bitmap.colorType()) { 228 return NULL; 229 } 230 231 SkImageInfo info = bitmap.info(); 232 233 if (opts.fUseRequestedColorType && (opts.fRequestedColorType != info.colorType())) { 234 if (!bitmap.canCopyTo(opts.fRequestedColorType)) { 235 SkASSERT(bitmap.colorType() != opts.fRequestedColorType); 236 return NULL; // Can not translate to needed config. 237 } 238 info = info.makeColorType(opts.fRequestedColorType); 239 } 240 241 if (opts.fRequireUnpremul && info.alphaType() != kOpaque_SkAlphaType) { 242 info = info.makeAlphaType(kUnpremul_SkAlphaType); 243 } 244 245 SkAlphaType newAlphaType = info.alphaType(); 246 if (!SkColorTypeValidateAlphaType(info.colorType(), info.alphaType(), &newAlphaType)) { 247 return NULL; 248 } 249 250 return SkNEW_ARGS(DecodingImageGenerator, 251 (data, autoStream.detach(), info.makeAlphaType(newAlphaType), 252 opts.fSampleSize, opts.fDitherImage)); 253} 254 255} // namespace 256 257//////////////////////////////////////////////////////////////////////////////// 258 259SkImageGenerator* SkDecodingImageGenerator::Create( 260 SkData* data, 261 const SkDecodingImageGenerator::Options& opts) { 262 SkASSERT(data != NULL); 263 if (NULL == data) { 264 return NULL; 265 } 266 SkStreamRewindable* stream = SkNEW_ARGS(SkMemoryStream, (data)); 267 SkASSERT(stream != NULL); 268 SkASSERT(stream->unique()); 269 return CreateDecodingImageGenerator(data, stream, opts); 270} 271 272SkImageGenerator* SkDecodingImageGenerator::Create( 273 SkStreamRewindable* stream, 274 const SkDecodingImageGenerator::Options& opts) { 275 SkASSERT(stream != NULL); 276 SkASSERT(stream->unique()); 277 if ((stream == NULL) || !stream->unique()) { 278 SkSafeUnref(stream); 279 return NULL; 280 } 281 return CreateDecodingImageGenerator(NULL, stream, opts); 282} 283