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 "SkImageDecoder.h"
     13 #include "SkScaledBitmapSampler.h"
     14 #include "SkStream.h"
     15 #include "SkStreamHelpers.h"
     16 #include "SkTDArray.h"
     17 
     18 class SkBMPImageDecoder : public SkImageDecoder {
     19 public:
     20     SkBMPImageDecoder() {}
     21 
     22     virtual Format getFormat() const SK_OVERRIDE {
     23         return kBMP_Format;
     24     }
     25 
     26 protected:
     27     virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode mode) SK_OVERRIDE;
     28 
     29 private:
     30     typedef SkImageDecoder INHERITED;
     31 };
     32 
     33 ///////////////////////////////////////////////////////////////////////////////
     34 DEFINE_DECODER_CREATOR(BMPImageDecoder);
     35 ///////////////////////////////////////////////////////////////////////////////
     36 
     37 static bool is_bmp(SkStreamRewindable* stream) {
     38     static const char kBmpMagic[] = { 'B', 'M' };
     39 
     40 
     41     char buffer[sizeof(kBmpMagic)];
     42 
     43     return stream->read(buffer, sizeof(kBmpMagic)) == sizeof(kBmpMagic) &&
     44         !memcmp(buffer, kBmpMagic, sizeof(kBmpMagic));
     45 }
     46 
     47 static SkImageDecoder* sk_libbmp_dfactory(SkStreamRewindable* stream) {
     48     if (is_bmp(stream)) {
     49         return SkNEW(SkBMPImageDecoder);
     50     }
     51     return NULL;
     52 }
     53 
     54 static SkImageDecoder_DecodeReg gReg(sk_libbmp_dfactory);
     55 
     56 static SkImageDecoder::Format get_format_bmp(SkStreamRewindable* stream) {
     57     if (is_bmp(stream)) {
     58         return SkImageDecoder::kBMP_Format;
     59     }
     60     return SkImageDecoder::kUnknown_Format;
     61 }
     62 
     63 static SkImageDecoder_FormatReg gFormatReg(get_format_bmp);
     64 
     65 ///////////////////////////////////////////////////////////////////////////////
     66 
     67 class SkBmpDecoderCallback : public image_codec::BmpDecoderCallback {
     68 public:
     69     // we don't copy the bitmap, just remember the pointer
     70     SkBmpDecoderCallback(bool justBounds) : fJustBounds(justBounds) {}
     71 
     72     // override from BmpDecoderCallback
     73     virtual uint8* SetSize(int width, int height) {
     74         fWidth = width;
     75         fHeight = height;
     76         if (fJustBounds) {
     77             return NULL;
     78         }
     79 
     80         fRGB.setCount(width * height * 3);  // 3 == r, g, b
     81         return fRGB.begin();
     82     }
     83 
     84     int width() const { return fWidth; }
     85     int height() const { return fHeight; }
     86     const uint8_t* rgb() const { return fRGB.begin(); }
     87 
     88 private:
     89     SkTDArray<uint8_t> fRGB;
     90     int fWidth;
     91     int fHeight;
     92     bool fJustBounds;
     93 };
     94 
     95 bool SkBMPImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
     96     // First read the entire stream, so that all of the data can be passed to
     97     // the BmpDecoderHelper.
     98 
     99     // Allocated space used to hold the data.
    100     SkAutoMalloc storage;
    101     // Byte length of all of the data.
    102     const size_t length = CopyStreamToStorage(&storage, stream);
    103     if (0 == length) {
    104         return 0;
    105     }
    106 
    107     const bool justBounds = SkImageDecoder::kDecodeBounds_Mode == mode;
    108     SkBmpDecoderCallback callback(justBounds);
    109 
    110     // Now decode the BMP into callback's rgb() array [r,g,b, r,g,b, ...]
    111     {
    112         image_codec::BmpDecoderHelper helper;
    113         const int max_pixels = 16383*16383; // max width*height
    114         if (!helper.DecodeImage((const char*)storage.get(), length,
    115                                 max_pixels, &callback)) {
    116             return false;
    117         }
    118     }
    119 
    120     // we don't need this anymore, so free it now (before we try to allocate
    121     // the bitmap's pixels) rather than waiting for its destructor
    122     storage.free();
    123 
    124     int width = callback.width();
    125     int height = callback.height();
    126     SkBitmap::Config config = this->getPrefConfig(k32Bit_SrcDepth, false);
    127 
    128     // only accept prefConfig if it makes sense for us
    129     if (SkBitmap::kARGB_4444_Config != config &&
    130             SkBitmap::kRGB_565_Config != config) {
    131         config = SkBitmap::kARGB_8888_Config;
    132     }
    133 
    134     SkScaledBitmapSampler sampler(width, height, getSampleSize());
    135 
    136     bm->setConfig(config, sampler.scaledWidth(), sampler.scaledHeight(), 0,
    137                   kOpaque_SkAlphaType);
    138 
    139     if (justBounds) {
    140         return true;
    141     }
    142 
    143     if (!this->allocPixelRef(bm, NULL)) {
    144         return false;
    145     }
    146 
    147     SkAutoLockPixels alp(*bm);
    148 
    149     if (!sampler.begin(bm, SkScaledBitmapSampler::kRGB, *this)) {
    150         return false;
    151     }
    152 
    153     const int srcRowBytes = width * 3;
    154     const int dstHeight = sampler.scaledHeight();
    155     const uint8_t* srcRow = callback.rgb();
    156 
    157     srcRow += sampler.srcY0() * srcRowBytes;
    158     for (int y = 0; y < dstHeight; y++) {
    159         sampler.next(srcRow);
    160         srcRow += sampler.srcDY() * srcRowBytes;
    161     }
    162     return true;
    163 }
    164