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 +}