Home | History | Annotate | Download | only in images
      1 
      2 /*
      3  * Copyright 2007 The Android Open Source Project
      4  *
      5  * Use of this source code is governed by a BSD-style license that can be
      6  * found in the LICENSE file.
      7  */
      8 
      9 
     10 #include "bmpdecoderhelper.h"
     11 #include "SkColorPriv.h"
     12 #include "SkData.h"
     13 #include "SkImageDecoder.h"
     14 #include "SkScaledBitmapSampler.h"
     15 #include "SkStream.h"
     16 #include "SkStreamPriv.h"
     17 #include "SkTDArray.h"
     18 
     19 class SkBMPImageDecoder : public SkImageDecoder {
     20 public:
     21     SkBMPImageDecoder() {}
     22 
     23     Format getFormat() const override {
     24         return kBMP_Format;
     25     }
     26 
     27 protected:
     28     Result onDecode(SkStream* stream, SkBitmap* bm, Mode mode) override;
     29 
     30 private:
     31     typedef SkImageDecoder INHERITED;
     32 };
     33 
     34 ///////////////////////////////////////////////////////////////////////////////
     35 DEFINE_DECODER_CREATOR(BMPImageDecoder);
     36 ///////////////////////////////////////////////////////////////////////////////
     37 
     38 static bool is_bmp(SkStreamRewindable* stream) {
     39     static const char kBmpMagic[] = { 'B', 'M' };
     40 
     41 
     42     char buffer[sizeof(kBmpMagic)];
     43 
     44     return stream->read(buffer, sizeof(kBmpMagic)) == sizeof(kBmpMagic) &&
     45         !memcmp(buffer, kBmpMagic, sizeof(kBmpMagic));
     46 }
     47 
     48 static SkImageDecoder* sk_libbmp_dfactory(SkStreamRewindable* stream) {
     49     if (is_bmp(stream)) {
     50         return new SkBMPImageDecoder;
     51     }
     52     return nullptr;
     53 }
     54 
     55 static SkImageDecoder_DecodeReg gReg(sk_libbmp_dfactory);
     56 
     57 static SkImageDecoder::Format get_format_bmp(SkStreamRewindable* stream) {
     58     if (is_bmp(stream)) {
     59         return SkImageDecoder::kBMP_Format;
     60     }
     61     return SkImageDecoder::kUnknown_Format;
     62 }
     63 
     64 static SkImageDecoder_FormatReg gFormatReg(get_format_bmp);
     65 
     66 ///////////////////////////////////////////////////////////////////////////////
     67 
     68 class SkBmpDecoderCallback : public image_codec::BmpDecoderCallback {
     69 public:
     70     // we don't copy the bitmap, just remember the pointer
     71     SkBmpDecoderCallback(bool justBounds) : fJustBounds(justBounds) {}
     72 
     73     // override from BmpDecoderCallback
     74     virtual uint8* SetSize(int width, int height) {
     75         fWidth = width;
     76         fHeight = height;
     77         if (fJustBounds) {
     78             return nullptr;
     79         }
     80 
     81         fRGB.setCount(width * height * 3);  // 3 == r, g, b
     82         return fRGB.begin();
     83     }
     84 
     85     int width() const { return fWidth; }
     86     int height() const { return fHeight; }
     87     const uint8_t* rgb() const { return fRGB.begin(); }
     88 
     89 private:
     90     SkTDArray<uint8_t> fRGB;
     91     int fWidth;
     92     int fHeight;
     93     bool fJustBounds;
     94 };
     95 
     96 SkImageDecoder::Result SkBMPImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
     97     // First read the entire stream, so that all of the data can be passed to
     98     // the BmpDecoderHelper.
     99 
    100     SkAutoTUnref<SkData> data(SkCopyStreamToData(stream));
    101     if (!data) {
    102         return kFailure;
    103     }
    104 
    105     // Byte length of all of the data.
    106     const size_t length = data->size();
    107     if (0 == length) {
    108         return kFailure;
    109     }
    110 
    111     const bool justBounds = SkImageDecoder::kDecodeBounds_Mode == mode;
    112     SkBmpDecoderCallback callback(justBounds);
    113 
    114     // Now decode the BMP into callback's rgb() array [r,g,b, r,g,b, ...]
    115     {
    116         image_codec::BmpDecoderHelper helper;
    117         const int max_pixels = 16383*16383; // max width*height
    118         if (!helper.DecodeImage((const char*) data->data(), length,
    119                                 max_pixels, &callback)) {
    120             return kFailure;
    121         }
    122     }
    123 
    124     // we don't need this anymore, so free it now (before we try to allocate
    125     // the bitmap's pixels) rather than waiting for its destructor
    126     data.reset(nullptr);
    127 
    128     int width = callback.width();
    129     int height = callback.height();
    130     SkColorType colorType = this->getPrefColorType(k32Bit_SrcDepth, false);
    131 
    132     // only accept prefConfig if it makes sense for us
    133     if (kARGB_4444_SkColorType != colorType && kRGB_565_SkColorType != colorType) {
    134         colorType = kN32_SkColorType;
    135     }
    136 
    137     SkScaledBitmapSampler sampler(width, height, getSampleSize());
    138 
    139     bm->setInfo(SkImageInfo::Make(sampler.scaledWidth(), sampler.scaledHeight(),
    140                                   colorType, kOpaque_SkAlphaType));
    141 
    142     if (justBounds) {
    143         return kSuccess;
    144     }
    145 
    146     if (!this->allocPixelRef(bm, nullptr)) {
    147         return kFailure;
    148     }
    149 
    150     SkAutoLockPixels alp(*bm);
    151 
    152     if (!sampler.begin(bm, SkScaledBitmapSampler::kRGB, *this)) {
    153         return kFailure;
    154     }
    155 
    156     const int srcRowBytes = width * 3;
    157     const int dstHeight = sampler.scaledHeight();
    158     const uint8_t* srcRow = callback.rgb();
    159 
    160     srcRow += sampler.srcY0() * srcRowBytes;
    161     for (int y = 0; y < dstHeight; y++) {
    162         sampler.next(srcRow);
    163         srcRow += sampler.srcDY() * srcRowBytes;
    164     }
    165     return kSuccess;
    166 }
    167