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:
SkBMPImageDecoder()21 SkBMPImageDecoder() {}
22
getFormat() const23 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
is_bmp(SkStreamRewindable * stream)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
sk_libbmp_dfactory(SkStreamRewindable * stream)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
get_format_bmp(SkStreamRewindable * stream)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
SkBmpDecoderCallback(bool justBounds)71 SkBmpDecoderCallback(bool justBounds) : fJustBounds(justBounds) {}
72
73 // override from BmpDecoderCallback
SetSize(int width,int height)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
width() const85 int width() const { return fWidth; }
height() const86 int height() const { return fHeight; }
rgb() const87 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
onDecode(SkStream * stream,SkBitmap * bm,Mode mode)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