1 | /*
|
---|
2 |
|
---|
3 | gbmbmp.c - OS/2 1.1, 1.2, 2.0 and Windows 3.0 support
|
---|
4 |
|
---|
5 | Reads and writes any OS/2 1.x bitmap.
|
---|
6 | Will also read uncompressed, RLE4 and RLE8 Windows 3.x bitmaps too.
|
---|
7 | There are horrific file structure alignment considerations hence each
|
---|
8 | word,dword is read individually.
|
---|
9 | Input options: index=# (default: 0)
|
---|
10 |
|
---|
11 | */
|
---|
12 |
|
---|
13 | /*...sincludes:0:*/
|
---|
14 | #include <stdio.h>
|
---|
15 | #include <ctype.h>
|
---|
16 | #include <stddef.h>
|
---|
17 | #include <stdlib.h>
|
---|
18 | #include <string.h>
|
---|
19 | #include "gbm.h"
|
---|
20 | #include "gbmhelp.h"
|
---|
21 |
|
---|
22 | /*...vgbm\46\h:0:*/
|
---|
23 | /*...vgbmhelp\46\h:0:*/
|
---|
24 |
|
---|
25 | #ifndef min
|
---|
26 | #define min(a,b) (((a)<(b))?(a):(b))
|
---|
27 | #endif
|
---|
28 | /*...e*/
|
---|
29 |
|
---|
30 | /*...suseful:0:*/
|
---|
31 | #define low_byte(w) ((byte) ((w)&0x00ff) )
|
---|
32 | #define high_byte(w) ((byte) (((w)&0xff00)>>8))
|
---|
33 | #define make_word(a,b) (((word)a) + (((word)b) << 8))
|
---|
34 |
|
---|
35 | /*...sread_word:0:*/
|
---|
36 | static BOOLEAN read_word(int fd, word *w)
|
---|
37 | {
|
---|
38 | byte low = 0, high = 0;
|
---|
39 |
|
---|
40 | if ( gbm_file_read(fd, (char *) &low, 1) != 1 )
|
---|
41 | return FALSE;
|
---|
42 | if ( gbm_file_read(fd, (char *) &high, 1) != 1 )
|
---|
43 | return FALSE;
|
---|
44 | *w = (word) (low + ((word) high << 8));
|
---|
45 | return TRUE;
|
---|
46 | }
|
---|
47 | /*...e*/
|
---|
48 | /*...sread_dword:0:*/
|
---|
49 | static BOOLEAN read_dword(int fd, dword *d)
|
---|
50 | {
|
---|
51 | word low, high;
|
---|
52 | if ( !read_word(fd, &low) )
|
---|
53 | return FALSE;
|
---|
54 | if ( !read_word(fd, &high) )
|
---|
55 | return FALSE;
|
---|
56 | *d = low + ((dword) high << 16);
|
---|
57 | return TRUE;
|
---|
58 | }
|
---|
59 | /*...e*/
|
---|
60 | /*...swrite_word:0:*/
|
---|
61 | static BOOLEAN write_word(int fd, word w)
|
---|
62 | {
|
---|
63 | byte low = (byte) w;
|
---|
64 | byte high = (byte) (w >> 8);
|
---|
65 |
|
---|
66 | gbm_file_write(fd, &low, 1);
|
---|
67 | gbm_file_write(fd, &high, 1);
|
---|
68 | return TRUE;
|
---|
69 | }
|
---|
70 | /*...e*/
|
---|
71 | /*...swrite_dword:0:*/
|
---|
72 | static BOOLEAN write_dword(int fd, dword d)
|
---|
73 | {
|
---|
74 | write_word(fd, (word) d);
|
---|
75 | write_word(fd, (word) (d >> 16));
|
---|
76 | return TRUE;
|
---|
77 | }
|
---|
78 | /*...e*/
|
---|
79 | /*...e*/
|
---|
80 |
|
---|
81 | static GBMFT bmp_gbmft =
|
---|
82 | {
|
---|
83 | "Bitmap",
|
---|
84 | "OS/2 1.1, 1.2, 2.0 / Windows 3.0 bitmap",
|
---|
85 | "BMP VGA BGA RLE DIB RL4 RL8",
|
---|
86 | GBM_FT_R1|GBM_FT_R4|GBM_FT_R8|GBM_FT_R24|
|
---|
87 | GBM_FT_W1|GBM_FT_W4|GBM_FT_W8|GBM_FT_W24,
|
---|
88 | };
|
---|
89 |
|
---|
90 | #define GBM_ERR_BMP_PLANES ((GBM_ERR) 300)
|
---|
91 | #define GBM_ERR_BMP_BITCOUNT ((GBM_ERR) 301)
|
---|
92 | #define GBM_ERR_BMP_CBFIX ((GBM_ERR) 302)
|
---|
93 | #define GBM_ERR_BMP_COMP ((GBM_ERR) 303)
|
---|
94 | #define GBM_ERR_BMP_OFFSET ((GBM_ERR) 304)
|
---|
95 |
|
---|
96 | typedef struct
|
---|
97 | {
|
---|
98 | dword base;
|
---|
99 | BOOLEAN windows;
|
---|
100 | dword cbFix;
|
---|
101 | dword ulCompression;
|
---|
102 | dword cclrUsed;
|
---|
103 | dword offBits;
|
---|
104 | BOOLEAN inv, invb;
|
---|
105 | } BMP_PRIV;
|
---|
106 |
|
---|
107 | #define BFT_BMAP 0x4d42
|
---|
108 | #define BFT_BITMAPARRAY 0x4142
|
---|
109 | #define BCA_UNCOMP 0x00000000L
|
---|
110 | #define BCA_RLE8 0x00000001L
|
---|
111 | #define BCA_RLE4 0x00000002L
|
---|
112 | #define BCA_HUFFFMAN1D 0x00000003L
|
---|
113 | #define BCA_RLE24 0x00000004L
|
---|
114 | #define MSWCC_EOL 0
|
---|
115 | #define MSWCC_EOB 1
|
---|
116 | #define MSWCC_DELTA 2
|
---|
117 |
|
---|
118 | /*...sinvert:0:*/
|
---|
119 | static void invert(byte *buffer, unsigned count)
|
---|
120 | {
|
---|
121 | while ( count-- )
|
---|
122 | *buffer++ ^= (byte) 0xffU;
|
---|
123 | }
|
---|
124 | /*...e*/
|
---|
125 | /*...sswap_pal:0:*/
|
---|
126 | static void swap_pal(GBMRGB *gbmrgb)
|
---|
127 | {
|
---|
128 | GBMRGB tmp = gbmrgb[0];
|
---|
129 | gbmrgb[0] = gbmrgb[1];
|
---|
130 | gbmrgb[1] = tmp;
|
---|
131 | }
|
---|
132 | /*...e*/
|
---|
133 |
|
---|
134 | /*...sbmp_qft:0:*/
|
---|
135 | GBM_ERR bmp_qft(GBMFT *gbmft)
|
---|
136 | {
|
---|
137 | *gbmft = bmp_gbmft;
|
---|
138 | return GBM_ERR_OK;
|
---|
139 | }
|
---|
140 | /*...e*/
|
---|
141 | /*...sbmp_rhdr:0:*/
|
---|
142 | GBM_ERR bmp_rhdr(const char *fn, int fd, GBM *gbm, const char *opt)
|
---|
143 | {
|
---|
144 | word usType, xHotspot, yHotspot;
|
---|
145 | dword cbSize, offBits, cbFix;
|
---|
146 | BMP_PRIV *bmp_priv = (BMP_PRIV *) gbm->priv;
|
---|
147 | bmp_priv->inv = ( gbm_find_word(opt, "inv" ) != NULL );
|
---|
148 | bmp_priv->invb = ( gbm_find_word(opt, "invb") != NULL );
|
---|
149 |
|
---|
150 | fn=fn; /* Suppress 'unref arg' compiler warnings */
|
---|
151 |
|
---|
152 | if ( !read_word(fd, &usType) )
|
---|
153 | return GBM_ERR_READ;
|
---|
154 | if ( usType == BFT_BITMAPARRAY )
|
---|
155 | /*...shandle bitmap arrays:16:*/
|
---|
156 | {
|
---|
157 | const char *index;
|
---|
158 | int i;
|
---|
159 |
|
---|
160 | if ( (index = gbm_find_word_prefix(opt, "index=")) != NULL )
|
---|
161 | sscanf(index + 6, "%d", &i);
|
---|
162 | else
|
---|
163 | i = 0;
|
---|
164 |
|
---|
165 | while ( i-- > 0 )
|
---|
166 | {
|
---|
167 | dword cbSize2, offNext;
|
---|
168 |
|
---|
169 | if ( !read_dword(fd, &cbSize2) )
|
---|
170 | return GBM_ERR_READ;
|
---|
171 | if ( !read_dword(fd, &offNext) )
|
---|
172 | return GBM_ERR_READ;
|
---|
173 | if ( offNext == 0L )
|
---|
174 | return GBM_ERR_BMP_OFFSET;
|
---|
175 | gbm_file_lseek(fd, (long) offNext, SEEK_SET);
|
---|
176 | if ( !read_word(fd, &usType) )
|
---|
177 | return GBM_ERR_READ;
|
---|
178 | if ( usType != BFT_BITMAPARRAY )
|
---|
179 | return GBM_ERR_BAD_MAGIC;
|
---|
180 | }
|
---|
181 | gbm_file_lseek(fd, 4L + 4L + 2L + 2L, SEEK_CUR);
|
---|
182 | if ( !read_word(fd, &usType) )
|
---|
183 | return GBM_ERR_READ;
|
---|
184 | }
|
---|
185 | /*...e*/
|
---|
186 |
|
---|
187 | if ( usType != BFT_BMAP )
|
---|
188 | return GBM_ERR_BAD_MAGIC;
|
---|
189 |
|
---|
190 | bmp_priv->base = (dword) ( gbm_file_lseek(fd, 0L, SEEK_CUR) - 2L );
|
---|
191 |
|
---|
192 | if ( !read_dword(fd, &cbSize) )
|
---|
193 | return GBM_ERR_READ;
|
---|
194 | if ( !read_word(fd, &xHotspot) )
|
---|
195 | return GBM_ERR_READ;
|
---|
196 | if ( !read_word(fd, &yHotspot) )
|
---|
197 | return GBM_ERR_READ;
|
---|
198 | if ( !read_dword(fd, &offBits) )
|
---|
199 | return GBM_ERR_READ;
|
---|
200 | if ( !read_dword(fd, &cbFix) )
|
---|
201 | return GBM_ERR_READ;
|
---|
202 |
|
---|
203 | bmp_priv->offBits = offBits;
|
---|
204 |
|
---|
205 | if ( cbFix == 12 )
|
---|
206 | /*...sOS\47\2 1\46\1\44\ 1\46\2:16:*/
|
---|
207 | /* OS/2 1.x uncompressed bitmap */
|
---|
208 | {
|
---|
209 | word cx, cy, cPlanes, cBitCount;
|
---|
210 |
|
---|
211 | if ( !read_word(fd, &cx) )
|
---|
212 | return GBM_ERR_READ;
|
---|
213 | if ( !read_word(fd, &cy) )
|
---|
214 | return GBM_ERR_READ;
|
---|
215 | if ( !read_word(fd, &cPlanes) )
|
---|
216 | return GBM_ERR_READ;
|
---|
217 | if ( !read_word(fd, &cBitCount) )
|
---|
218 | return GBM_ERR_READ;
|
---|
219 |
|
---|
220 | if ( cx == 0 || cy == 0 )
|
---|
221 | return GBM_ERR_BAD_SIZE;
|
---|
222 | if ( cPlanes != 1 )
|
---|
223 | return GBM_ERR_BMP_PLANES;
|
---|
224 | if ( cBitCount != 1 && cBitCount != 4 && cBitCount != 8 && cBitCount != 24 )
|
---|
225 | return GBM_ERR_BMP_BITCOUNT;
|
---|
226 |
|
---|
227 | gbm->w = (int) cx;
|
---|
228 | gbm->h = (int) cy;
|
---|
229 | gbm->bpp = (int) cBitCount;
|
---|
230 |
|
---|
231 | bmp_priv->windows = FALSE;
|
---|
232 | }
|
---|
233 | /*...e*/
|
---|
234 | else if ( cbFix >= 16 && cbFix <= 64 &&
|
---|
235 | ((cbFix & 3) == 0 || cbFix == 42 || cbFix == 46) )
|
---|
236 | /*...sOS\47\2 2\46\0 and Windows 3\46\0:16:*/
|
---|
237 | {
|
---|
238 | word cPlanes, cBitCount, usUnits, usReserved, usRecording, usRendering;
|
---|
239 | dword ulWidth, ulHeight, ulCompression;
|
---|
240 | dword ulSizeImage, ulXPelsPerMeter, ulYPelsPerMeter;
|
---|
241 | dword cclrUsed, cclrImportant, cSize1, cSize2, ulColorEncoding, ulIdentifier;
|
---|
242 | BOOLEAN ok;
|
---|
243 |
|
---|
244 | ok = read_dword(fd, &ulWidth);
|
---|
245 | ok &= read_dword(fd, &ulHeight);
|
---|
246 | ok &= read_word(fd, &cPlanes);
|
---|
247 | ok &= read_word(fd, &cBitCount);
|
---|
248 | if ( cbFix > 16 )
|
---|
249 | ok &= read_dword(fd, &ulCompression);
|
---|
250 | else
|
---|
251 | ulCompression = BCA_UNCOMP;
|
---|
252 | if ( cbFix > 20 )
|
---|
253 | ok &= read_dword(fd, &ulSizeImage);
|
---|
254 | if ( cbFix > 24 )
|
---|
255 | ok &= read_dword(fd, &ulXPelsPerMeter);
|
---|
256 | if ( cbFix > 28 )
|
---|
257 | ok &= read_dword(fd, &ulYPelsPerMeter);
|
---|
258 | if ( cbFix > 32 )
|
---|
259 | ok &= read_dword(fd, &cclrUsed);
|
---|
260 | else
|
---|
261 | cclrUsed = ( (dword)1 << cBitCount );
|
---|
262 | if ( cBitCount != 24 && cclrUsed == 0 )
|
---|
263 | cclrUsed = ( (dword)1 << cBitCount );
|
---|
264 |
|
---|
265 | /* Protect against badly written bitmaps! */
|
---|
266 | if ( cclrUsed > ( (dword)1 << cBitCount ) )
|
---|
267 | cclrUsed = ( (dword)1 << cBitCount );
|
---|
268 |
|
---|
269 | if ( cbFix > 36 )
|
---|
270 | ok &= read_dword(fd, &cclrImportant);
|
---|
271 | if ( cbFix > 40 )
|
---|
272 | ok &= read_word(fd, &usUnits);
|
---|
273 | if ( cbFix > 42 )
|
---|
274 | ok &= read_word(fd, &usReserved);
|
---|
275 | if ( cbFix > 44 )
|
---|
276 | ok &= read_word(fd, &usRecording);
|
---|
277 | if ( cbFix > 46 )
|
---|
278 | ok &= read_word(fd, &usRendering);
|
---|
279 | if ( cbFix > 48 )
|
---|
280 | ok &= read_dword(fd, &cSize1);
|
---|
281 | if ( cbFix > 52 )
|
---|
282 | ok &= read_dword(fd, &cSize2);
|
---|
283 | if ( cbFix > 56 )
|
---|
284 | ok &= read_dword(fd, &ulColorEncoding);
|
---|
285 | if ( cbFix > 60 )
|
---|
286 | ok &= read_dword(fd, &ulIdentifier);
|
---|
287 |
|
---|
288 | if ( !ok )
|
---|
289 | return GBM_ERR_READ;
|
---|
290 |
|
---|
291 | if ( ulWidth == 0L || ulHeight == 0L )
|
---|
292 | return GBM_ERR_BAD_SIZE;
|
---|
293 | if ( cPlanes != 1 )
|
---|
294 | return GBM_ERR_BMP_PLANES;
|
---|
295 | if ( cBitCount != 1 && cBitCount != 4 && cBitCount != 8 && cBitCount != 24 )
|
---|
296 | return GBM_ERR_BMP_BITCOUNT;
|
---|
297 |
|
---|
298 | gbm->w = (int) ulWidth;
|
---|
299 | gbm->h = (int) ulHeight;
|
---|
300 | gbm->bpp = (int) cBitCount;
|
---|
301 |
|
---|
302 | bmp_priv->windows = TRUE;
|
---|
303 | bmp_priv->cbFix = cbFix;
|
---|
304 | bmp_priv->ulCompression = ulCompression;
|
---|
305 | bmp_priv->cclrUsed = cclrUsed;
|
---|
306 | }
|
---|
307 | /*...e*/
|
---|
308 | else
|
---|
309 | return GBM_ERR_BMP_CBFIX;
|
---|
310 |
|
---|
311 | return GBM_ERR_OK;
|
---|
312 | }
|
---|
313 | /*...e*/
|
---|
314 | /*...sbmp_rpal:0:*/
|
---|
315 | GBM_ERR bmp_rpal(int fd, GBM *gbm, GBMRGB *gbmrgb)
|
---|
316 | {
|
---|
317 | BMP_PRIV *bmp_priv = (BMP_PRIV *) gbm->priv;
|
---|
318 |
|
---|
319 | if ( gbm->bpp != 24 )
|
---|
320 | {
|
---|
321 | int i;
|
---|
322 | byte b[4];
|
---|
323 |
|
---|
324 | if ( bmp_priv->windows )
|
---|
325 | /*...sOS\47\2 2\46\0 and Windows 3\46\0:24:*/
|
---|
326 | {
|
---|
327 | gbm_file_lseek(fd, (long) (bmp_priv->base + 14L + bmp_priv->cbFix), SEEK_SET);
|
---|
328 | for ( i = 0; i < (1 << gbm->bpp); i++ )
|
---|
329 | /* Used to use bmp_priv->cclrUsed, but bitmaps have been found which have
|
---|
330 | their used colours not at the start of the palette. */
|
---|
331 | {
|
---|
332 | gbm_file_read(fd, b, 4);
|
---|
333 | gbmrgb[i].b = b[0];
|
---|
334 | gbmrgb[i].g = b[1];
|
---|
335 | gbmrgb[i].r = b[2];
|
---|
336 | }
|
---|
337 | }
|
---|
338 | /*...e*/
|
---|
339 | else
|
---|
340 | /*...sOS\47\2 1\46\1\44\ 1\46\2:24:*/
|
---|
341 | {
|
---|
342 | gbm_file_lseek(fd, (long) (bmp_priv->base + 26L), SEEK_SET);
|
---|
343 | for ( i = 0; i < (1 << gbm->bpp); i++ )
|
---|
344 | {
|
---|
345 | gbm_file_read(fd, b, 3);
|
---|
346 | gbmrgb[i].b = b[0];
|
---|
347 | gbmrgb[i].g = b[1];
|
---|
348 | gbmrgb[i].r = b[2];
|
---|
349 | }
|
---|
350 | }
|
---|
351 | /*...e*/
|
---|
352 | }
|
---|
353 |
|
---|
354 | if ( gbm->bpp == 1 && !bmp_priv->inv )
|
---|
355 | swap_pal(gbmrgb);
|
---|
356 |
|
---|
357 | return GBM_ERR_OK;
|
---|
358 | }
|
---|
359 | /*...e*/
|
---|
360 | /*...sbmp_rdata:0:*/
|
---|
361 | GBM_ERR bmp_rdata(int fd, GBM *gbm, byte *data)
|
---|
362 | {
|
---|
363 | BMP_PRIV *bmp_priv = (BMP_PRIV *) gbm->priv;
|
---|
364 | int cLinesWorth = ((gbm->bpp * gbm->w + 31) / 32) * 4;
|
---|
365 |
|
---|
366 | if ( bmp_priv->windows )
|
---|
367 | /*...sOS\47\2 2\46\0 and Windows 3\46\0:16:*/
|
---|
368 | {
|
---|
369 | gbm_file_lseek(fd, (long)bmp_priv->offBits, SEEK_SET);
|
---|
370 |
|
---|
371 | switch ( (int) bmp_priv->ulCompression )
|
---|
372 | {
|
---|
373 | /*...sBCA_UNCOMP:24:*/
|
---|
374 | case BCA_UNCOMP:
|
---|
375 | gbm_file_read(fd, data, gbm->h * cLinesWorth);
|
---|
376 | break;
|
---|
377 | /*...e*/
|
---|
378 | /*...sBCA_RLE8:24:*/
|
---|
379 | case BCA_RLE8:
|
---|
380 | {
|
---|
381 | AHEAD *ahead;
|
---|
382 | int x = 0, y = 0;
|
---|
383 | BOOLEAN eof8 = FALSE;
|
---|
384 |
|
---|
385 | if ( (ahead = gbm_create_ahead(fd)) == NULL )
|
---|
386 | return GBM_ERR_MEM;
|
---|
387 |
|
---|
388 | while ( !eof8 )
|
---|
389 | {
|
---|
390 | byte c = (byte) gbm_read_ahead(ahead);
|
---|
391 | byte d = (byte) gbm_read_ahead(ahead);
|
---|
392 | /* fprintf(stderr, "(%d,%d) c=%d,d=%d\n", x, y, c, d); debug*/
|
---|
393 |
|
---|
394 | if ( c )
|
---|
395 | {
|
---|
396 | memset(data, d, c);
|
---|
397 | x += c;
|
---|
398 | data += c;
|
---|
399 | }
|
---|
400 | else
|
---|
401 | switch ( d )
|
---|
402 | {
|
---|
403 | /*...sMSWCC_EOL:56:*/
|
---|
404 | case MSWCC_EOL:
|
---|
405 | {
|
---|
406 | int to_eol = cLinesWorth - x;
|
---|
407 |
|
---|
408 | memset(data, 0, (size_t) to_eol);
|
---|
409 | data += to_eol;
|
---|
410 | x = 0;
|
---|
411 | if ( ++y == gbm->h )
|
---|
412 | eof8 = TRUE;
|
---|
413 | }
|
---|
414 | break;
|
---|
415 | /*...e*/
|
---|
416 | /*...sMSWCC_EOB:56:*/
|
---|
417 | case MSWCC_EOB:
|
---|
418 | if ( y < gbm->h )
|
---|
419 | {
|
---|
420 | int to_eol = cLinesWorth - x;
|
---|
421 |
|
---|
422 | memset(data, 0, (size_t) to_eol);
|
---|
423 | x = 0; y++;
|
---|
424 | data += to_eol;
|
---|
425 | while ( y < gbm->h )
|
---|
426 | {
|
---|
427 | memset(data, 0, (size_t) cLinesWorth);
|
---|
428 | data += cLinesWorth;
|
---|
429 | y++;
|
---|
430 | }
|
---|
431 | }
|
---|
432 | eof8 = TRUE;
|
---|
433 | break;
|
---|
434 | /*...e*/
|
---|
435 | /*...sMSWCC_DELTA:56:*/
|
---|
436 | case MSWCC_DELTA:
|
---|
437 | {
|
---|
438 | byte dx = (byte) gbm_read_ahead(ahead);
|
---|
439 | byte dy = (byte) gbm_read_ahead(ahead);
|
---|
440 | int fill = dx + dy * cLinesWorth;
|
---|
441 | memset(data, 0, (size_t) fill);
|
---|
442 | data += fill;
|
---|
443 | x += dx; y += dy;
|
---|
444 | if ( y == gbm->h )
|
---|
445 | eof8 = TRUE;
|
---|
446 | }
|
---|
447 | break;
|
---|
448 | /*...e*/
|
---|
449 | /*...sdefault:56:*/
|
---|
450 | default:
|
---|
451 | {
|
---|
452 | int n = (int) d;
|
---|
453 |
|
---|
454 | while ( n-- > 0 )
|
---|
455 | *data++ = (byte) gbm_read_ahead(ahead);
|
---|
456 | x += d;
|
---|
457 | if ( x > gbm->w ) { x = 0; ++y; } /* @@@AK */
|
---|
458 | if ( d & 1 )
|
---|
459 | gbm_read_ahead(ahead); /* Align */
|
---|
460 | }
|
---|
461 | break;
|
---|
462 | /*...e*/
|
---|
463 | }
|
---|
464 | }
|
---|
465 |
|
---|
466 | gbm_destroy_ahead(ahead);
|
---|
467 | }
|
---|
468 | break;
|
---|
469 | /*...e*/
|
---|
470 | /*...sBCA_RLE4:24:*/
|
---|
471 | case BCA_RLE4:
|
---|
472 | {
|
---|
473 | AHEAD *ahead;
|
---|
474 | int x = 0, y = 0;
|
---|
475 | BOOLEAN eof4 = FALSE;
|
---|
476 | int inx = 0;
|
---|
477 |
|
---|
478 | if ( (ahead = gbm_create_ahead(fd)) == NULL )
|
---|
479 | return GBM_ERR_MEM;
|
---|
480 |
|
---|
481 | memset(data, 0, (size_t) (gbm->h * cLinesWorth));
|
---|
482 |
|
---|
483 | while ( !eof4 )
|
---|
484 | {
|
---|
485 | byte c = (byte) gbm_read_ahead(ahead);
|
---|
486 | byte d = (byte) gbm_read_ahead(ahead);
|
---|
487 |
|
---|
488 | if ( c )
|
---|
489 | {
|
---|
490 | byte h, l;
|
---|
491 | int i;
|
---|
492 | if ( x & 1 )
|
---|
493 | { h = (byte) (d >> 4); l = (byte) (d << 4); }
|
---|
494 | else
|
---|
495 | { h = (byte) (d&0xf0); l = (byte) (d&0x0f); }
|
---|
496 | for ( i = 0; i < (int) c; i++, x++ )
|
---|
497 | {
|
---|
498 | if ( x & 1U )
|
---|
499 | data[inx++] |= l;
|
---|
500 | else
|
---|
501 | data[inx] |= h;
|
---|
502 | }
|
---|
503 | }
|
---|
504 | else
|
---|
505 | switch ( d )
|
---|
506 | {
|
---|
507 | /*...sMSWCC_EOL:56:*/
|
---|
508 | case MSWCC_EOL:
|
---|
509 | x = 0;
|
---|
510 | if ( ++y == gbm->h )
|
---|
511 | eof4 = TRUE;
|
---|
512 | inx = cLinesWorth * y;
|
---|
513 | break;
|
---|
514 | /*...e*/
|
---|
515 | /*...sMSWCC_EOB:56:*/
|
---|
516 | case MSWCC_EOB:
|
---|
517 | eof4 = TRUE;
|
---|
518 | break;
|
---|
519 | /*...e*/
|
---|
520 | /*...sMSWCC_DELTA:56:*/
|
---|
521 | case MSWCC_DELTA:
|
---|
522 | {
|
---|
523 | byte dx = (byte) gbm_read_ahead(ahead);
|
---|
524 | byte dy = (byte) gbm_read_ahead(ahead);
|
---|
525 |
|
---|
526 | x += dx; y += dy;
|
---|
527 | inx = y * cLinesWorth + (x/2);
|
---|
528 |
|
---|
529 | if ( y == gbm->h )
|
---|
530 | eof4 = TRUE;
|
---|
531 | }
|
---|
532 | break;
|
---|
533 | /*...e*/
|
---|
534 | /*...sdefault:56:*/
|
---|
535 | default:
|
---|
536 | {
|
---|
537 | int i, nr = 0;
|
---|
538 |
|
---|
539 | if ( x & 1 )
|
---|
540 | {
|
---|
541 | for ( i = 0; i+2 <= (int) d; i += 2 )
|
---|
542 | {
|
---|
543 | byte b = (byte) gbm_read_ahead(ahead);
|
---|
544 | data[inx++] |= (b >> 4);
|
---|
545 | data[inx ] |= (b << 4);
|
---|
546 | nr++;
|
---|
547 | }
|
---|
548 | if ( i < (int) d )
|
---|
549 | {
|
---|
550 | data[inx++] |= ((byte) gbm_read_ahead(ahead) >> 4);
|
---|
551 | nr++;
|
---|
552 | }
|
---|
553 | }
|
---|
554 | else
|
---|
555 | {
|
---|
556 | for ( i = 0; i+2 <= (int) d; i += 2 )
|
---|
557 | {
|
---|
558 | data[inx++] = (byte) gbm_read_ahead(ahead);
|
---|
559 | nr++;
|
---|
560 | }
|
---|
561 | if ( i < (int) d )
|
---|
562 | {
|
---|
563 | data[inx] = (byte) gbm_read_ahead(ahead);
|
---|
564 | nr++;
|
---|
565 | }
|
---|
566 | }
|
---|
567 | x += d;
|
---|
568 |
|
---|
569 | if ( nr & 1 )
|
---|
570 | gbm_read_ahead(ahead); /* Align input stream to next word */
|
---|
571 | }
|
---|
572 | break;
|
---|
573 | /*...e*/
|
---|
574 | }
|
---|
575 | }
|
---|
576 |
|
---|
577 | gbm_destroy_ahead(ahead);
|
---|
578 | }
|
---|
579 | break;
|
---|
580 | /*...e*/
|
---|
581 | /*...sdefault:24:*/
|
---|
582 | default:
|
---|
583 | return GBM_ERR_BMP_COMP;
|
---|
584 | /*...e*/
|
---|
585 | }
|
---|
586 | }
|
---|
587 | /*...e*/
|
---|
588 | else
|
---|
589 | /*...sOS\47\2 1\46\1\44\ 1\46\2:16:*/
|
---|
590 | {
|
---|
591 | gbm_file_lseek(fd, (long) bmp_priv->offBits, SEEK_SET);
|
---|
592 | gbm_file_read(fd, data, cLinesWorth * gbm->h);
|
---|
593 | }
|
---|
594 | /*...e*/
|
---|
595 |
|
---|
596 | if ( bmp_priv->invb )
|
---|
597 | invert(data, (unsigned) (cLinesWorth * gbm->h));
|
---|
598 |
|
---|
599 | return GBM_ERR_OK;
|
---|
600 | }
|
---|
601 | /*...e*/
|
---|
602 | /*...sbmp_w:0:*/
|
---|
603 | /*...sbright:0:*/
|
---|
604 | static int bright(const GBMRGB *gbmrgb)
|
---|
605 | {
|
---|
606 | return gbmrgb->r*30+gbmrgb->g*60+gbmrgb->b*10;
|
---|
607 | }
|
---|
608 | /*...e*/
|
---|
609 | /*...swrite_inv:0:*/
|
---|
610 | static int write_inv(int fd, const byte *buffer, int count)
|
---|
611 | {
|
---|
612 | byte small_buf[1024];
|
---|
613 | int so_far = 0, this_go, written;
|
---|
614 |
|
---|
615 | while ( so_far < count )
|
---|
616 | {
|
---|
617 | this_go = min(count - so_far, 1024);
|
---|
618 | memcpy(small_buf, buffer + so_far, (size_t) this_go);
|
---|
619 | invert(small_buf, (unsigned) this_go);
|
---|
620 | if ( (written = gbm_file_write(fd, small_buf, this_go)) != this_go )
|
---|
621 | return so_far + written;
|
---|
622 | so_far += written;
|
---|
623 | }
|
---|
624 |
|
---|
625 | return so_far;
|
---|
626 | }
|
---|
627 | /*...e*/
|
---|
628 |
|
---|
629 | GBM_ERR bmp_w(const char *fn, int fd, const GBM *gbm, const GBMRGB *gbmrgb, const byte *data, const char *opt)
|
---|
630 | {
|
---|
631 | BOOLEAN pm11 = ( gbm_find_word(opt, "1.1" ) != NULL );
|
---|
632 | BOOLEAN win = ( gbm_find_word(opt, "win" ) != NULL ||
|
---|
633 | gbm_find_word(opt, "2.0" ) != NULL );
|
---|
634 | BOOLEAN inv = ( gbm_find_word(opt, "inv" ) != NULL );
|
---|
635 | BOOLEAN invb = ( gbm_find_word(opt, "invb" ) != NULL );
|
---|
636 | BOOLEAN darkfg = ( gbm_find_word(opt, "darkfg" ) != NULL );
|
---|
637 | BOOLEAN lightfg = ( gbm_find_word(opt, "lightfg") != NULL );
|
---|
638 | int cRGB;
|
---|
639 | GBMRGB gbmrgb_1bpp[2];
|
---|
640 |
|
---|
641 | if ( pm11 && win )
|
---|
642 | return GBM_ERR_BAD_OPTION;
|
---|
643 |
|
---|
644 | fn=fn; /* Suppress 'unref arg' compiler warning */
|
---|
645 |
|
---|
646 | cRGB = ( (1 << gbm->bpp) & 0x1ff );
|
---|
647 | /* 1->2, 4->16, 8->256, 24->0 */
|
---|
648 |
|
---|
649 | if ( cRGB == 2 )
|
---|
650 | /*...shandle messy 1bpp case:16:*/
|
---|
651 | {
|
---|
652 | /*
|
---|
653 | The palette entries inside a 1bpp PM bitmap are not honored, or handled
|
---|
654 | correctly by most programs. Current thinking is that they have no actual
|
---|
655 | meaning. Under OS/2 PM, bitmap 1's re fg and 0's are bg, and it is the job of
|
---|
656 | the displayer to pick fg and bg. We will pick fg=black, bg=white in the bitmap
|
---|
657 | file we save. If we do not write black and white, we find that most programs
|
---|
658 | will incorrectly honor these entries giving unpredicatable (and often black on
|
---|
659 | a black background!) results.
|
---|
660 | */
|
---|
661 |
|
---|
662 | gbmrgb_1bpp[0].r = gbmrgb_1bpp[0].g = gbmrgb_1bpp[0].b = 0xff;
|
---|
663 | gbmrgb_1bpp[1].r = gbmrgb_1bpp[1].g = gbmrgb_1bpp[1].b = 0x00;
|
---|
664 |
|
---|
665 | /*
|
---|
666 | We observe these values must be the wrong way around to keep most PM
|
---|
667 | programs happy, such as WorkPlace Shell WPFolder backgrounds.
|
---|
668 | */
|
---|
669 |
|
---|
670 | if ( !inv )
|
---|
671 | swap_pal(gbmrgb_1bpp);
|
---|
672 |
|
---|
673 | /*
|
---|
674 | If the user has picked the darkfg option, then they intend that the darkest
|
---|
675 | colour in the image is to be the foreground. This is a very sensible option
|
---|
676 | because the foreground will appear to be black when the image is reloaded.
|
---|
677 | To acheive this we must invert the bitmap bits, if the palette dictates.
|
---|
678 | */
|
---|
679 |
|
---|
680 | if ( darkfg && bright(&gbmrgb[0]) < bright(&gbmrgb[1]) )
|
---|
681 | invb = !invb;
|
---|
682 | if ( lightfg && bright(&gbmrgb[0]) >= bright(&gbmrgb[1]) )
|
---|
683 | invb = !invb;
|
---|
684 |
|
---|
685 | gbmrgb = gbmrgb_1bpp;
|
---|
686 | }
|
---|
687 | /*...e*/
|
---|
688 |
|
---|
689 | if ( pm11 )
|
---|
690 | /*...sOS\47\2 1\46\1:16:*/
|
---|
691 | {
|
---|
692 | word usType = BFT_BMAP;
|
---|
693 | word xHotspot = 0;
|
---|
694 | word yHotspot = 0;
|
---|
695 | dword cbFix = (dword) 12;
|
---|
696 | word cx = (word) gbm->w;
|
---|
697 | word cy = (word) gbm->h;
|
---|
698 | word cPlanes = (word) 1;
|
---|
699 | word cBitCount = (word) gbm->bpp;
|
---|
700 | int cLinesWorth = (((cBitCount * cx + 31) / 32) * cPlanes) * 4;
|
---|
701 | dword offBits = (dword) 26 + cRGB * (dword) 3;
|
---|
702 | dword cbSize = offBits + (dword) cy * (dword) cLinesWorth;
|
---|
703 | int i, total, actual;
|
---|
704 |
|
---|
705 | write_word(fd, usType);
|
---|
706 | write_dword(fd, cbSize);
|
---|
707 | write_word(fd, xHotspot);
|
---|
708 | write_word(fd, yHotspot);
|
---|
709 | write_dword(fd, offBits);
|
---|
710 | write_dword(fd, cbFix);
|
---|
711 | write_word(fd, cx);
|
---|
712 | write_word(fd, cy);
|
---|
713 | write_word(fd, cPlanes);
|
---|
714 | write_word(fd, cBitCount);
|
---|
715 |
|
---|
716 | for ( i = 0; i < cRGB; i++ )
|
---|
717 | {
|
---|
718 | byte b[3];
|
---|
719 |
|
---|
720 | b[0] = gbmrgb[i].b;
|
---|
721 | b[1] = gbmrgb[i].g;
|
---|
722 | b[2] = gbmrgb[i].r;
|
---|
723 | if ( gbm_file_write(fd, b, 3) != 3 )
|
---|
724 | return GBM_ERR_WRITE;
|
---|
725 | }
|
---|
726 |
|
---|
727 | total = gbm->h * cLinesWorth;
|
---|
728 | if ( invb )
|
---|
729 | actual = write_inv(fd, data, total);
|
---|
730 | else
|
---|
731 | actual = gbm_file_write(fd, data, total);
|
---|
732 | if ( actual != total )
|
---|
733 | return GBM_ERR_WRITE;
|
---|
734 | }
|
---|
735 | /*...e*/
|
---|
736 | else
|
---|
737 | /*...sOS\47\2 2\46\0 and Windows 3\46\0:16:*/
|
---|
738 | {
|
---|
739 | word usType = BFT_BMAP;
|
---|
740 | word xHotspot = 0;
|
---|
741 | word yHotspot = 0;
|
---|
742 | dword cbFix = (dword) 40;
|
---|
743 | dword cx = (dword) gbm->w;
|
---|
744 | dword cy = (dword) gbm->h;
|
---|
745 | word cPlanes = (word) 1;
|
---|
746 | word cBitCount = (word) gbm->bpp;
|
---|
747 | int cLinesWorth = (((cBitCount * (int) cx + 31) / 32) * cPlanes) * 4;
|
---|
748 | dword offBits = (dword) 54 + cRGB * (dword) 4;
|
---|
749 | dword cbSize = offBits + (dword) cy * (dword) cLinesWorth;
|
---|
750 | dword ulCompression = BCA_UNCOMP;
|
---|
751 | dword cbImage = (dword) cLinesWorth * (dword) gbm->h;
|
---|
752 | dword cxResolution = 0;
|
---|
753 | dword cyResolution = 0;
|
---|
754 | dword cclrUsed = 0;
|
---|
755 | dword cclrImportant = 0;
|
---|
756 | int i, total, actual;
|
---|
757 |
|
---|
758 | write_word(fd, usType);
|
---|
759 | write_dword(fd, cbSize);
|
---|
760 | write_word(fd, xHotspot);
|
---|
761 | write_word(fd, yHotspot);
|
---|
762 | write_dword(fd, offBits);
|
---|
763 |
|
---|
764 | write_dword(fd, cbFix);
|
---|
765 | write_dword(fd, cx);
|
---|
766 | write_dword(fd, cy);
|
---|
767 | write_word(fd, cPlanes);
|
---|
768 | write_word(fd, cBitCount);
|
---|
769 | write_dword(fd, ulCompression);
|
---|
770 | write_dword(fd, cbImage);
|
---|
771 | write_dword(fd, cxResolution);
|
---|
772 | write_dword(fd, cyResolution);
|
---|
773 | write_dword(fd, cclrUsed);
|
---|
774 | write_dword(fd, cclrImportant);
|
---|
775 |
|
---|
776 | for ( i = 0; i < cRGB; i++ )
|
---|
777 | {
|
---|
778 | byte b[4];
|
---|
779 |
|
---|
780 | b[0] = gbmrgb[i].b;
|
---|
781 | b[1] = gbmrgb[i].g;
|
---|
782 | b[2] = gbmrgb[i].r;
|
---|
783 | b[3] = 0;
|
---|
784 | if ( gbm_file_write(fd, b, 4) != 4 )
|
---|
785 | return GBM_ERR_WRITE;
|
---|
786 | }
|
---|
787 |
|
---|
788 | total = gbm->h * cLinesWorth;
|
---|
789 | if ( invb )
|
---|
790 | actual = write_inv(fd, data, total);
|
---|
791 | else
|
---|
792 | actual = gbm_file_write(fd, data, total);
|
---|
793 | if ( actual != total )
|
---|
794 | return GBM_ERR_WRITE;
|
---|
795 | }
|
---|
796 | /*...e*/
|
---|
797 |
|
---|
798 | return GBM_ERR_OK;
|
---|
799 | }
|
---|
800 | /*...e*/
|
---|
801 | /*...sbmp_err:0:*/
|
---|
802 | const char *bmp_err(GBM_ERR rc)
|
---|
803 | {
|
---|
804 | switch ( (int) rc )
|
---|
805 | {
|
---|
806 | case GBM_ERR_BMP_PLANES:
|
---|
807 | return "number of bitmap planes is not 1";
|
---|
808 | case GBM_ERR_BMP_BITCOUNT:
|
---|
809 | return "bit count not 1, 4, 8 or 24";
|
---|
810 | case GBM_ERR_BMP_CBFIX:
|
---|
811 | return "cbFix bad";
|
---|
812 | case GBM_ERR_BMP_COMP:
|
---|
813 | return "compression type not uncompressed, RLE4 or RLE8";
|
---|
814 | case GBM_ERR_BMP_OFFSET:
|
---|
815 | return "less bitmaps in file than index requested";
|
---|
816 | }
|
---|
817 | return NULL;
|
---|
818 | }
|
---|
819 | /*...e*/
|
---|