| 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*/
|
|---|