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