Line | Count | Source |
1 | | /* WBMP |
2 | | * ---- |
3 | | * WBMP Level 0: B/W, Uncompressed |
4 | | * This implements the WBMP format as specified in WAPSpec 1.1 and 1.2. |
5 | | * It does not support ExtHeaders as defined in the spec. The spec states |
6 | | * that a WAP client does not need to implement ExtHeaders. |
7 | | * |
8 | | * (c) 2000 Johan Van den Brande <johan@vandenbrande.com> |
9 | | */ |
10 | | |
11 | | #ifdef HAVE_CONFIG_H |
12 | | #include "config.h" |
13 | | #endif |
14 | | |
15 | | #include <stddef.h> |
16 | | #include <stdio.h> |
17 | | #include <stdlib.h> |
18 | | #include <string.h> |
19 | | |
20 | | #include "gd.h" |
21 | | #include "gdhelpers.h" |
22 | | #include "wbmp.h" |
23 | | |
24 | | #ifdef NOTDEF |
25 | | #define __TEST /* Compile with main function */ |
26 | | #define __DEBUG /* Extra verbose when with __TEST */ |
27 | | #define __WRITE /* readwbmp and writewbmp(stdout) */ |
28 | | #define __VIEW /* view the wbmp on stdout */ |
29 | | #endif |
30 | | |
31 | | /* getmbi |
32 | | * ------ |
33 | | * Get a multibyte integer from a generic getin function |
34 | | * 'getin' can be getc, with in = NULL |
35 | | * you can find getin as a function just above the main function |
36 | | * This way you gain a lot of flexibility about how this package |
37 | | * reads a wbmp file. |
38 | | */ |
39 | | int getmbi(int (*getin)(void *in), void *in) |
40 | 509 | { |
41 | 509 | unsigned int mbi = 0; |
42 | 509 | int i; |
43 | | |
44 | 4.13M | do { |
45 | 4.13M | i = getin(in); |
46 | 4.13M | if (i < 0) { |
47 | 104 | return (-1); |
48 | 104 | } |
49 | 4.13M | mbi = (mbi << 7) | (i & 0x7f); |
50 | 4.13M | } while (i & 0x80); |
51 | | |
52 | 405 | return mbi; |
53 | 509 | } |
54 | | |
55 | | /* putmbi |
56 | | * ------ |
57 | | * Put a multibyte intgerer in some kind of output stream |
58 | | * I work here with a function pointer, to make it as generic |
59 | | * as possible. Look at this function as an iterator on the |
60 | | * mbi integers it spits out. |
61 | | * |
62 | | */ |
63 | | void putmbi(int i, void (*putout)(int c, void *out), void *out) |
64 | 0 | { |
65 | 0 | int cnt, l, accu; |
66 | | |
67 | | /* Get number of septets */ |
68 | 0 | accu = cnt = 0; |
69 | 0 | while (accu != i) { |
70 | 0 | accu += i & 0x7f << 7 * cnt++; |
71 | 0 | } |
72 | | |
73 | | /* Produce the multibyte output */ |
74 | 0 | for (l = cnt - 1; l > 0; l--) { |
75 | 0 | putout(0x80 | (i & 0x7f << 7 * l) >> 7 * l, out); |
76 | 0 | } |
77 | |
|
78 | 0 | putout(i & 0x7f, out); |
79 | 0 | } |
80 | | |
81 | | /* skipheader |
82 | | * ---------- |
83 | | * Skips the ExtHeader. Not needed for the moment |
84 | | */ |
85 | | int skipheader(int (*getin)(void *in), void *in) |
86 | 278 | { |
87 | 278 | int i; |
88 | | |
89 | 45.7k | do { |
90 | 45.7k | i = getin(in); |
91 | 45.7k | if (i < 0) { |
92 | 15 | return (-1); |
93 | 15 | } |
94 | 45.7k | } while (i & 0x80); |
95 | | |
96 | 263 | return 0; |
97 | 278 | } |
98 | | |
99 | | /* create wbmp |
100 | | * ----------- |
101 | | * create an empty wbmp |
102 | | */ |
103 | | Wbmp *createwbmp(int width, int height, int color) |
104 | 0 | { |
105 | 0 | int i; |
106 | 0 | Wbmp *wbmp; |
107 | |
|
108 | 0 | if ((wbmp = (Wbmp *)gdMalloc(sizeof(Wbmp))) == NULL) { |
109 | 0 | return (NULL); |
110 | 0 | } |
111 | | |
112 | 0 | if (overflow2(sizeof(int), width)) { |
113 | 0 | gdFree(wbmp); |
114 | 0 | return NULL; |
115 | 0 | } |
116 | | |
117 | 0 | if (overflow2(sizeof(int) * width, height)) { |
118 | 0 | gdFree(wbmp); |
119 | 0 | return NULL; |
120 | 0 | } |
121 | | |
122 | 0 | if ((wbmp->bitmap = (int *)gdMalloc(sizeof(int) * width * height)) == NULL) { |
123 | 0 | gdFree(wbmp); |
124 | 0 | return NULL; |
125 | 0 | } |
126 | | |
127 | 0 | wbmp->width = width; |
128 | 0 | wbmp->height = height; |
129 | |
|
130 | 0 | for (i = 0; i < width * height; wbmp->bitmap[i++] = color) |
131 | 0 | ; |
132 | |
|
133 | 0 | return wbmp; |
134 | 0 | } |
135 | | |
136 | | /* readwbmp |
137 | | * ------- |
138 | | * Actually reads the WBMP format from an open file descriptor |
139 | | * It goes along by returning a pointer to a WBMP struct. |
140 | | */ |
141 | | int readwbmp(int (*getin)(void *in), void *in, Wbmp **return_wbmp) |
142 | 287 | { |
143 | 287 | int row, col, byte, pel, pos; |
144 | 287 | Wbmp *wbmp; |
145 | | |
146 | 287 | if ((wbmp = (Wbmp *)gdMalloc(sizeof(Wbmp))) == NULL) { |
147 | 0 | return -1; |
148 | 0 | } |
149 | | |
150 | 287 | wbmp->type = getin(in); |
151 | 287 | if (wbmp->type != 0) { |
152 | 9 | gdFree(wbmp); |
153 | 9 | return -1; |
154 | 9 | } |
155 | | |
156 | 278 | if (skipheader(getin, in)) { |
157 | 15 | gdFree(wbmp); |
158 | 15 | return -1; |
159 | 15 | } |
160 | | |
161 | 263 | wbmp->width = getmbi(getin, in); |
162 | 263 | if (wbmp->width == -1) { |
163 | 17 | gdFree(wbmp); |
164 | 17 | return -1; |
165 | 17 | } |
166 | | |
167 | 246 | wbmp->height = getmbi(getin, in); |
168 | 246 | if (wbmp->height == -1) { |
169 | 87 | gdFree(wbmp); |
170 | 87 | return -1; |
171 | 87 | } |
172 | | |
173 | | #ifdef __DEBUG |
174 | | printf("W: %d, H: %d\n", wbmp->width, wbmp->height); |
175 | | #endif |
176 | | |
177 | 159 | if (overflow2(sizeof(int), wbmp->width) || overflow2(sizeof(int) * wbmp->width, wbmp->height)) { |
178 | 87 | gdFree(wbmp); |
179 | 87 | return -1; |
180 | 87 | } |
181 | | |
182 | 72 | if ((wbmp->bitmap = (int *)gdMalloc(sizeof(int) * wbmp->width * wbmp->height)) == NULL) { |
183 | 0 | gdFree(wbmp); |
184 | 0 | return -1; |
185 | 0 | } |
186 | | |
187 | | #ifdef __DEBUG |
188 | | printf("DATA CONSTRUCTED\n"); |
189 | | #endif |
190 | | |
191 | 72 | pos = 0; |
192 | 190k | for (row = 0; row < wbmp->height; row++) { |
193 | 404k | for (col = 0; col < wbmp->width;) { |
194 | 213k | byte = getin(in); |
195 | | |
196 | 1.92M | for (pel = 7; pel >= 0; pel--) { |
197 | 1.70M | if (col++ < wbmp->width) { |
198 | 380k | if (byte & 1 << pel) { |
199 | 361k | wbmp->bitmap[pos] = WBMP_WHITE; |
200 | 361k | } else { |
201 | 18.2k | wbmp->bitmap[pos] = WBMP_BLACK; |
202 | 18.2k | } |
203 | 380k | pos++; |
204 | 380k | } |
205 | 1.70M | } |
206 | 213k | } |
207 | 190k | } |
208 | | |
209 | 72 | *return_wbmp = wbmp; |
210 | | |
211 | 72 | return 0; |
212 | 72 | } |
213 | | |
214 | | /* writewbmp |
215 | | * --------- |
216 | | * Write a wbmp to a file descriptor |
217 | | * |
218 | | * Why not just giving a filedescriptor to this function? |
219 | | * Well, the incentive to write this function was the complete |
220 | | * integration in gd library from www.libgd.org. They use |
221 | | * their own io functions, so the passing of a function seemed to be |
222 | | * a logic(?) decision ... |
223 | | */ |
224 | | int writewbmp(Wbmp *wbmp, void (*putout)(int c, void *out), void *out) |
225 | 0 | { |
226 | 0 | int row, col; |
227 | 0 | int bitpos, octet; |
228 | | |
229 | | /* Generate the header */ |
230 | 0 | putout(0, out); /* WBMP Type 0: B/W, Uncompressed bitmap */ |
231 | 0 | putout(0, out); /* FixHeaderField */ |
232 | | |
233 | | /* Size of the image */ |
234 | 0 | putmbi(wbmp->width, putout, out); /* width */ |
235 | 0 | putmbi(wbmp->height, putout, out); /* height */ |
236 | | |
237 | | /* Image data */ |
238 | 0 | for (row = 0; row < wbmp->height; row++) { |
239 | 0 | bitpos = 8; |
240 | 0 | octet = 0; |
241 | |
|
242 | 0 | for (col = 0; col < wbmp->width; col++) { |
243 | 0 | octet |= ((wbmp->bitmap[row * wbmp->width + col] == 1) ? WBMP_WHITE : WBMP_BLACK) |
244 | 0 | << --bitpos; |
245 | 0 | if (bitpos == 0) { |
246 | 0 | bitpos = 8; |
247 | 0 | putout(octet, out); |
248 | 0 | octet = 0; |
249 | 0 | } |
250 | 0 | } |
251 | |
|
252 | 0 | if (bitpos != 8) { |
253 | 0 | putout(octet, out); |
254 | 0 | } |
255 | 0 | } |
256 | |
|
257 | 0 | return 0; |
258 | 0 | } |
259 | | |
260 | | /* freewbmp |
261 | | * -------- |
262 | | * gdFrees up memory occupied by a WBMP structure |
263 | | */ |
264 | | void freewbmp(Wbmp *wbmp) |
265 | 72 | { |
266 | 72 | gdFree(wbmp->bitmap); |
267 | 72 | gdFree(wbmp); |
268 | 72 | } |
269 | | |
270 | | /* printwbmp |
271 | | * --------- |
272 | | * print a WBMP to stdout for visualisation |
273 | | */ |
274 | | void printwbmp(Wbmp *wbmp) |
275 | 0 | { |
276 | 0 | int row, col; |
277 | |
|
278 | 0 | for (row = 0; row < wbmp->height; row++) { |
279 | 0 | for (col = 0; col < wbmp->width; col++) { |
280 | 0 | if (wbmp->bitmap[wbmp->width * row + col] == WBMP_BLACK) { |
281 | 0 | putchar('#'); |
282 | 0 | } else { |
283 | 0 | putchar(' '); |
284 | 0 | } |
285 | 0 | } |
286 | 0 | putchar('\n'); |
287 | 0 | } |
288 | 0 | } |
289 | | |
290 | | #ifdef __TEST |
291 | | |
292 | | /* putout to file descriptor |
293 | | * ------------------------- |
294 | | */ |
295 | | int putout(int c, void *out) { return (putc(c, (FILE *)out)); } |
296 | | |
297 | | /* getin from file descriptor |
298 | | * -------------------------- |
299 | | */ |
300 | | int getin(void *in) { return (getc((FILE *)in)); } |
301 | | |
302 | | /* Main function |
303 | | * ------------- |
304 | | */ |
305 | | int main(int argc, char *argv[]) |
306 | | { |
307 | | FILE *wbmp_file; |
308 | | Wbmp *wbmp; |
309 | | |
310 | | wbmp_file = fopen(argv[1], "rb"); |
311 | | if (wbmp_file) { |
312 | | readwbmp(&getin, wbmp_file, &wbmp); |
313 | | #ifdef __VIEW |
314 | | #ifdef __DEBUG |
315 | | printf("\nVIEWING IMAGE\n"); |
316 | | #endif |
317 | | printwbmp(wbmp); |
318 | | #endif |
319 | | #ifdef __WRITE |
320 | | #ifdef __DEBUG |
321 | | printf("\nDUMPING WBMP to STDOUT\n"); |
322 | | #endif |
323 | | writewbmp(wbmp, &putout, stdout); |
324 | | #endif |
325 | | freewbmp(wbmp); |
326 | | fclose(wbmp_file); |
327 | | } |
328 | | } |
329 | | #endif |