gfx/skia/trunk/src/images/SkImageDecoder_libbmp.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/skia/trunk/src/images/SkImageDecoder_libbmp.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,163 @@
     1.4 +
     1.5 +/*
     1.6 + * Copyright 2007 The Android Open Source Project
     1.7 + *
     1.8 + * Use of this source code is governed by a BSD-style license that can be
     1.9 + * found in the LICENSE file.
    1.10 + */
    1.11 +
    1.12 +
    1.13 +#include "bmpdecoderhelper.h"
    1.14 +#include "SkColorPriv.h"
    1.15 +#include "SkImageDecoder.h"
    1.16 +#include "SkScaledBitmapSampler.h"
    1.17 +#include "SkStream.h"
    1.18 +#include "SkStreamHelpers.h"
    1.19 +#include "SkTDArray.h"
    1.20 +
    1.21 +class SkBMPImageDecoder : public SkImageDecoder {
    1.22 +public:
    1.23 +    SkBMPImageDecoder() {}
    1.24 +
    1.25 +    virtual Format getFormat() const SK_OVERRIDE {
    1.26 +        return kBMP_Format;
    1.27 +    }
    1.28 +
    1.29 +protected:
    1.30 +    virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode mode) SK_OVERRIDE;
    1.31 +
    1.32 +private:
    1.33 +    typedef SkImageDecoder INHERITED;
    1.34 +};
    1.35 +
    1.36 +///////////////////////////////////////////////////////////////////////////////
    1.37 +DEFINE_DECODER_CREATOR(BMPImageDecoder);
    1.38 +///////////////////////////////////////////////////////////////////////////////
    1.39 +
    1.40 +static bool is_bmp(SkStreamRewindable* stream) {
    1.41 +    static const char kBmpMagic[] = { 'B', 'M' };
    1.42 +
    1.43 +
    1.44 +    char buffer[sizeof(kBmpMagic)];
    1.45 +
    1.46 +    return stream->read(buffer, sizeof(kBmpMagic)) == sizeof(kBmpMagic) &&
    1.47 +        !memcmp(buffer, kBmpMagic, sizeof(kBmpMagic));
    1.48 +}
    1.49 +
    1.50 +static SkImageDecoder* sk_libbmp_dfactory(SkStreamRewindable* stream) {
    1.51 +    if (is_bmp(stream)) {
    1.52 +        return SkNEW(SkBMPImageDecoder);
    1.53 +    }
    1.54 +    return NULL;
    1.55 +}
    1.56 +
    1.57 +static SkImageDecoder_DecodeReg gReg(sk_libbmp_dfactory);
    1.58 +
    1.59 +static SkImageDecoder::Format get_format_bmp(SkStreamRewindable* stream) {
    1.60 +    if (is_bmp(stream)) {
    1.61 +        return SkImageDecoder::kBMP_Format;
    1.62 +    }
    1.63 +    return SkImageDecoder::kUnknown_Format;
    1.64 +}
    1.65 +
    1.66 +static SkImageDecoder_FormatReg gFormatReg(get_format_bmp);
    1.67 +
    1.68 +///////////////////////////////////////////////////////////////////////////////
    1.69 +
    1.70 +class SkBmpDecoderCallback : public image_codec::BmpDecoderCallback {
    1.71 +public:
    1.72 +    // we don't copy the bitmap, just remember the pointer
    1.73 +    SkBmpDecoderCallback(bool justBounds) : fJustBounds(justBounds) {}
    1.74 +
    1.75 +    // override from BmpDecoderCallback
    1.76 +    virtual uint8* SetSize(int width, int height) {
    1.77 +        fWidth = width;
    1.78 +        fHeight = height;
    1.79 +        if (fJustBounds) {
    1.80 +            return NULL;
    1.81 +        }
    1.82 +
    1.83 +        fRGB.setCount(width * height * 3);  // 3 == r, g, b
    1.84 +        return fRGB.begin();
    1.85 +    }
    1.86 +
    1.87 +    int width() const { return fWidth; }
    1.88 +    int height() const { return fHeight; }
    1.89 +    const uint8_t* rgb() const { return fRGB.begin(); }
    1.90 +
    1.91 +private:
    1.92 +    SkTDArray<uint8_t> fRGB;
    1.93 +    int fWidth;
    1.94 +    int fHeight;
    1.95 +    bool fJustBounds;
    1.96 +};
    1.97 +
    1.98 +bool SkBMPImageDecoder::onDecode(SkStream* stream, SkBitmap* bm, Mode mode) {
    1.99 +    // First read the entire stream, so that all of the data can be passed to
   1.100 +    // the BmpDecoderHelper.
   1.101 +
   1.102 +    // Allocated space used to hold the data.
   1.103 +    SkAutoMalloc storage;
   1.104 +    // Byte length of all of the data.
   1.105 +    const size_t length = CopyStreamToStorage(&storage, stream);
   1.106 +    if (0 == length) {
   1.107 +        return 0;
   1.108 +    }
   1.109 +
   1.110 +    const bool justBounds = SkImageDecoder::kDecodeBounds_Mode == mode;
   1.111 +    SkBmpDecoderCallback callback(justBounds);
   1.112 +
   1.113 +    // Now decode the BMP into callback's rgb() array [r,g,b, r,g,b, ...]
   1.114 +    {
   1.115 +        image_codec::BmpDecoderHelper helper;
   1.116 +        const int max_pixels = 16383*16383; // max width*height
   1.117 +        if (!helper.DecodeImage((const char*)storage.get(), length,
   1.118 +                                max_pixels, &callback)) {
   1.119 +            return false;
   1.120 +        }
   1.121 +    }
   1.122 +
   1.123 +    // we don't need this anymore, so free it now (before we try to allocate
   1.124 +    // the bitmap's pixels) rather than waiting for its destructor
   1.125 +    storage.free();
   1.126 +
   1.127 +    int width = callback.width();
   1.128 +    int height = callback.height();
   1.129 +    SkBitmap::Config config = this->getPrefConfig(k32Bit_SrcDepth, false);
   1.130 +
   1.131 +    // only accept prefConfig if it makes sense for us
   1.132 +    if (SkBitmap::kARGB_4444_Config != config &&
   1.133 +            SkBitmap::kRGB_565_Config != config) {
   1.134 +        config = SkBitmap::kARGB_8888_Config;
   1.135 +    }
   1.136 +
   1.137 +    SkScaledBitmapSampler sampler(width, height, getSampleSize());
   1.138 +
   1.139 +    bm->setConfig(config, sampler.scaledWidth(), sampler.scaledHeight(), 0,
   1.140 +                  kOpaque_SkAlphaType);
   1.141 +
   1.142 +    if (justBounds) {
   1.143 +        return true;
   1.144 +    }
   1.145 +
   1.146 +    if (!this->allocPixelRef(bm, NULL)) {
   1.147 +        return false;
   1.148 +    }
   1.149 +
   1.150 +    SkAutoLockPixels alp(*bm);
   1.151 +
   1.152 +    if (!sampler.begin(bm, SkScaledBitmapSampler::kRGB, *this)) {
   1.153 +        return false;
   1.154 +    }
   1.155 +
   1.156 +    const int srcRowBytes = width * 3;
   1.157 +    const int dstHeight = sampler.scaledHeight();
   1.158 +    const uint8_t* srcRow = callback.rgb();
   1.159 +
   1.160 +    srcRow += sampler.srcY0() * srcRowBytes;
   1.161 +    for (int y = 0; y < dstHeight; y++) {
   1.162 +        sampler.next(srcRow);
   1.163 +        srcRow += sampler.srcDY() * srcRowBytes;
   1.164 +    }
   1.165 +    return true;
   1.166 +}

mercurial