• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
onDecode(SkStream * stream,SkBitmap * decodedBitmap,Mode mode)99 bool SkWBMPImageDecoder::onDecode(SkStream* stream, SkBitmap* decodedBitmap,
100                                   Mode mode)
101 {
102     wbmp_head   head;
103 
104     if (!head.init(stream)) {
105         return false;
106     }
107 
108     int width = head.fWidth;
109     int height = head.fHeight;
110 
111     if (SkImageDecoder::kDecodeBounds_Mode == mode) {
112         // assign these directly, in case we return kDimensions_Result
113         decodedBitmap->setConfig(SkBitmap::kIndex8_Config, width, height);
114         decodedBitmap->setIsOpaque(true);
115         return true;
116     }
117 #ifdef SK_BUILD_FOR_ANDROID
118     // No Bitmap reuse supported for this format
119     if (!decodedBitmap->isNull()) {
120         return false;
121     }
122 #endif
123     // assign these directly, in case we return kDimensions_Result
124     decodedBitmap->setConfig(SkBitmap::kIndex8_Config, width, height);
125     decodedBitmap->setIsOpaque(true);
126 
127     const SkPMColor colors[] = { SK_ColorBLACK, SK_ColorWHITE };
128     SkColorTable* ct = SkNEW_ARGS(SkColorTable, (colors, 2));
129     SkAutoUnref   aur(ct);
130 
131     if (!this->allocPixelRef(decodedBitmap, ct)) {
132         return false;
133     }
134 
135     SkAutoLockPixels alp(*decodedBitmap);
136 
137     uint8_t* dst = decodedBitmap->getAddr8(0, 0);
138     // store the 1-bit valuess at the end of our pixels, so we won't stomp
139     // on them before we're read them. Just trying to avoid a temp allocation
140     size_t srcRB = SkAlign8(width) >> 3;
141     size_t srcSize = height * srcRB;
142     uint8_t* src = dst + decodedBitmap->getSize() - srcSize;
143     if (stream->read(src, srcSize) != srcSize) {
144         return false;
145     }
146 
147     for (int y = 0; y < height; y++)
148     {
149         expand_bits_to_bytes(dst, src, width);
150         dst += decodedBitmap->rowBytes();
151         src += srcRB;
152     }
153 
154     return true;
155 }
156 
157 ///////////////////////////////////////////////////////////////////////////////
158 DEFINE_DECODER_CREATOR(WBMPImageDecoder);
159 ///////////////////////////////////////////////////////////////////////////////
160 
161 #include "SkTRegistry.h"
162 
sk_wbmp_dfactory(SkStream * stream)163 static SkImageDecoder* sk_wbmp_dfactory(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(sk_wbmp_dfactory);
173