1
2 /*
3 * Copyright 2006 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 "SkImageDecoder.h"
11 #include "SkColor.h"
12 #include "SkColorPriv.h"
13 #include "SkMath.h"
14 #include "SkStream.h"
15 #include "SkTemplates.h"
16 #include "SkUtils.h"
17
18 class SkWBMPImageDecoder : public SkImageDecoder {
19 public:
getFormat() const20 virtual Format getFormat() const {
21 return kWBMP_Format;
22 }
23
24 protected:
25 virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode);
26 };
27
read_byte(SkStream * stream,uint8_t * data)28 static bool read_byte(SkStream* stream, uint8_t* data)
29 {
30 return stream->read(data, 1) == 1;
31 }
32
read_mbf(SkStream * stream,int * value)33 static bool read_mbf(SkStream* stream, int* value)
34 {
35 int n = 0;
36 uint8_t data;
37 do {
38 if (!read_byte(stream, &data)) {
39 return false;
40 }
41 n = (n << 7) | (data & 0x7F);
42 } while (data & 0x80);
43
44 *value = n;
45 return true;
46 }
47
48 struct wbmp_head {
49 int fWidth;
50 int fHeight;
51
initwbmp_head52 bool init(SkStream* stream)
53 {
54 uint8_t data;
55
56 if (!read_byte(stream, &data) || data != 0) { // unknown type
57 return false;
58 }
59 if (!read_byte(stream, &data) || (data & 0x9F)) { // skip fixed header
60 return false;
61 }
62 if (!read_mbf(stream, &fWidth) || (unsigned)fWidth > 0xFFFF) {
63 return false;
64 }
65 if (!read_mbf(stream, &fHeight) || (unsigned)fHeight > 0xFFFF) {
66 return false;
67 }
68 return fWidth != 0 && fHeight != 0;
69 }
70 };
71
expand_bits_to_bytes(uint8_t dst[],const uint8_t src[],int bits)72 static void expand_bits_to_bytes(uint8_t dst[], const uint8_t src[], int bits)
73 {
74 int bytes = bits >> 3;
75
76 for (int i = 0; i < bytes; i++) {
77 unsigned mask = *src++;
78 dst[0] = (mask >> 7) & 1;
79 dst[1] = (mask >> 6) & 1;
80 dst[2] = (mask >> 5) & 1;
81 dst[3] = (mask >> 4) & 1;
82 dst[4] = (mask >> 3) & 1;
83 dst[5] = (mask >> 2) & 1;
84 dst[6] = (mask >> 1) & 1;
85 dst[7] = (mask >> 0) & 1;
86 dst += 8;
87 }
88
89 bits &= 7;
90 if (bits > 0) {
91 unsigned mask = *src;
92 do {
93 *dst++ = (mask >> 7) & 1;;
94 mask <<= 1;
95 } while (--bits != 0);
96 }
97 }
98
99 #define SkAlign8(x) (((x) + 7) & ~7)
100
onDecode(SkStream * stream,SkBitmap * decodedBitmap,Mode mode)101 bool SkWBMPImageDecoder::onDecode(SkStream* stream, SkBitmap* decodedBitmap,
102 Mode mode)
103 {
104 wbmp_head head;
105
106 if (!head.init(stream)) {
107 return false;
108 }
109
110 int width = head.fWidth;
111 int height = head.fHeight;
112
113 if (SkImageDecoder::kDecodeBounds_Mode == mode) {
114 // assign these directly, in case we return kDimensions_Result
115 decodedBitmap->setConfig(SkBitmap::kIndex8_Config, width, height);
116 decodedBitmap->setIsOpaque(true);
117 return true;
118 }
119 #ifdef SK_BUILD_FOR_ANDROID
120 // No Bitmap reuse supported for this format
121 if (!decodedBitmap->isNull()) {
122 return false;
123 }
124 #endif
125 // assign these directly, in case we return kDimensions_Result
126 decodedBitmap->setConfig(SkBitmap::kIndex8_Config, width, height);
127 decodedBitmap->setIsOpaque(true);
128
129 const SkPMColor colors[] = { SK_ColorBLACK, SK_ColorWHITE };
130 SkColorTable* ct = SkNEW_ARGS(SkColorTable, (colors, 2));
131 SkAutoUnref aur(ct);
132
133 if (!this->allocPixelRef(decodedBitmap, ct)) {
134 return false;
135 }
136
137 SkAutoLockPixels alp(*decodedBitmap);
138
139 uint8_t* dst = decodedBitmap->getAddr8(0, 0);
140 // store the 1-bit valuess at the end of our pixels, so we won't stomp
141 // on them before we're read them. Just trying to avoid a temp allocation
142 size_t srcRB = SkAlign8(width) >> 3;
143 size_t srcSize = height * srcRB;
144 uint8_t* src = dst + decodedBitmap->getSize() - srcSize;
145 if (stream->read(src, srcSize) != srcSize) {
146 return false;
147 }
148
149 for (int y = 0; y < height; y++)
150 {
151 expand_bits_to_bytes(dst, src, width);
152 dst += decodedBitmap->rowBytes();
153 src += srcRB;
154 }
155
156 return true;
157 }
158
159 ///////////////////////////////////////////////////////////////////////////////
160
161 #include "SkTRegistry.h"
162
Factory(SkStream * stream)163 static SkImageDecoder* Factory(SkStream* stream) {
164 wbmp_head head;
165
166 if (head.init(stream)) {
167 return SkNEW(SkWBMPImageDecoder);
168 }
169 return NULL;
170 }
171
172 static SkTRegistry<SkImageDecoder*, SkStream*> gReg(Factory);
173
174