Home | History | Annotate | Download | only in images
      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 
     17 namespace {
     18 bool 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 
     23 class DecodingImageGenerator : public SkImageGenerator {
     24 public:
     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 
     39 protected:
     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 
     49 private:
     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  */
     57 class TargetAllocator : public SkBitmap::Allocator {
     58 public:
     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 
     84 private:
     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
    102 inline 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 
    111 DecodingImageGenerator::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 
    127 DecodingImageGenerator::~DecodingImageGenerator() {
    128     SkSafeUnref(fData);
    129     fStream->unref();
    130 }
    131 
    132 SkData* 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 
    149 bool 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
    210 SkImageGenerator* 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 
    259 SkImageGenerator* 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 
    272 SkImageGenerator* 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