• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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