| 1 | /*
|
|---|
| 2 |
|
|---|
| 3 | gbmpcx.c - ZSoft PC Paintbrush support
|
|---|
| 4 |
|
|---|
| 5 | Reads and writes 1,4,8 and 24 bit colour files.
|
|---|
| 6 |
|
|---|
| 7 | */
|
|---|
| 8 |
|
|---|
| 9 | /*...sincludes:0:*/
|
|---|
| 10 | #include <stdio.h>
|
|---|
| 11 | #include <ctype.h>
|
|---|
| 12 | #include <stddef.h>
|
|---|
| 13 | #include <stdlib.h>
|
|---|
| 14 | #include <string.h>
|
|---|
| 15 | #include "gbm.h"
|
|---|
| 16 | #include "gbmhelp.h"
|
|---|
| 17 |
|
|---|
| 18 | /*...vgbm\46\h:0:*/
|
|---|
| 19 | /*...vgbmhelp\46\h:0:*/
|
|---|
| 20 | /*...e*/
|
|---|
| 21 |
|
|---|
| 22 | /*...suseful:0:*/
|
|---|
| 23 | #define low_byte(w) ((byte) ( (w)&0x00ffU) )
|
|---|
| 24 | #define high_byte(w) ((byte) (((unsigned)(w)&0xff00U)>>8))
|
|---|
| 25 | #define make_word(a,b) (((word)a) + (((word)b) << 8))
|
|---|
| 26 | /*...e*/
|
|---|
| 27 |
|
|---|
| 28 | static GBMFT pcx_gbmft =
|
|---|
| 29 | {
|
|---|
| 30 | "PCX",
|
|---|
| 31 | "ZSoft PC Paintbrush Image format",
|
|---|
| 32 | "PCX PCC",
|
|---|
| 33 | GBM_FT_R1|GBM_FT_R4|GBM_FT_R8|GBM_FT_R24|
|
|---|
| 34 | GBM_FT_W1|GBM_FT_W4|GBM_FT_W8|GBM_FT_W24,
|
|---|
| 35 | };
|
|---|
| 36 |
|
|---|
| 37 | #define GBM_ERR_PCX_BAD_VERSION ((GBM_ERR) 700)
|
|---|
| 38 | #define GBM_ERR_PCX_BAD_ENCMODE ((GBM_ERR) 701)
|
|---|
| 39 | #define GBM_ERR_PCX_BAD_BITS ((GBM_ERR) 702)
|
|---|
| 40 | #define GBM_ERR_PCX_BAD_TRAILER ((GBM_ERR) 703)
|
|---|
| 41 |
|
|---|
| 42 | typedef struct
|
|---|
| 43 | {
|
|---|
| 44 | byte version, bpppp, planes;
|
|---|
| 45 | int bytes_per_line;
|
|---|
| 46 | BOOLEAN trunc;
|
|---|
| 47 | } PCX_PRIV;
|
|---|
| 48 |
|
|---|
| 49 | /*...spcx_qft:0:*/
|
|---|
| 50 | GBM_ERR pcx_qft(GBMFT *gbmft)
|
|---|
| 51 | {
|
|---|
| 52 | *gbmft = pcx_gbmft;
|
|---|
| 53 | return GBM_ERR_OK;
|
|---|
| 54 | }
|
|---|
| 55 | /*...e*/
|
|---|
| 56 | /*...spcx_rhdr:0:*/
|
|---|
| 57 | GBM_ERR pcx_rhdr(const char *fn, int fd, GBM *gbm, const char *opt)
|
|---|
| 58 | {
|
|---|
| 59 | PCX_PRIV *pcx_priv = (PCX_PRIV *) gbm->priv;
|
|---|
| 60 | byte hdr[70];
|
|---|
| 61 | word x1, y1, x2, y2;
|
|---|
| 62 | int w, h, bpp;
|
|---|
| 63 |
|
|---|
| 64 | fn=fn; /* Suppress 'unref arg' compiler warning */
|
|---|
| 65 |
|
|---|
| 66 | pcx_priv->trunc = ( gbm_find_word(opt, "trunc" ) != NULL );
|
|---|
| 67 |
|
|---|
| 68 | gbm_file_read(fd, hdr, 70);
|
|---|
| 69 | if ( hdr[0] != 0x0a )
|
|---|
| 70 | return GBM_ERR_BAD_MAGIC;
|
|---|
| 71 | pcx_priv->version = hdr[1];
|
|---|
| 72 | if ( pcx_priv->version == 4 || pcx_priv->version > 5 )
|
|---|
| 73 | return GBM_ERR_PCX_BAD_VERSION;
|
|---|
| 74 | if ( hdr[2] != 1 )
|
|---|
| 75 | return GBM_ERR_PCX_BAD_ENCMODE;
|
|---|
| 76 |
|
|---|
| 77 | pcx_priv->bpppp = hdr[3]; pcx_priv->planes = hdr[65];
|
|---|
| 78 | #define SWITCH2(a,b) (((a)<<8)|(b))
|
|---|
| 79 | switch ( SWITCH2(pcx_priv->bpppp, pcx_priv->planes) )
|
|---|
| 80 | {
|
|---|
| 81 | case SWITCH2(1,1): bpp = 1; break;
|
|---|
| 82 | case SWITCH2(4,1): bpp = 4; break;
|
|---|
| 83 | case SWITCH2(8,1): bpp = 8; break;
|
|---|
| 84 | case SWITCH2(8,3): bpp = 24; break; /* Extended 24 bit style */
|
|---|
| 85 | case SWITCH2(1,4): bpp = 4; break; /* EGA RGBI style */
|
|---|
| 86 | default: return GBM_ERR_PCX_BAD_BITS;
|
|---|
| 87 | }
|
|---|
| 88 |
|
|---|
| 89 | x1 = make_word(hdr[ 4], hdr[ 5]);
|
|---|
| 90 | y1 = make_word(hdr[ 6], hdr[ 7]);
|
|---|
| 91 | x2 = make_word(hdr[ 8], hdr[ 9]);
|
|---|
| 92 | y2 = make_word(hdr[10], hdr[11]);
|
|---|
| 93 |
|
|---|
| 94 | w = x2 - x1 + 1;
|
|---|
| 95 | h = y2 - y1 + 1;
|
|---|
| 96 |
|
|---|
| 97 | if ( w <= 0 || h <= 0 )
|
|---|
| 98 | return GBM_ERR_BAD_SIZE;
|
|---|
| 99 |
|
|---|
| 100 | pcx_priv->bytes_per_line = make_word(hdr[66], hdr[67]);
|
|---|
| 101 |
|
|---|
| 102 | gbm->w = w;
|
|---|
| 103 | gbm->h = h;
|
|---|
| 104 | gbm->bpp = bpp;
|
|---|
| 105 |
|
|---|
| 106 | return GBM_ERR_OK;
|
|---|
| 107 | }
|
|---|
| 108 | /*...e*/
|
|---|
| 109 | /*...spcx_rpal:0:*/
|
|---|
| 110 | GBM_ERR pcx_rpal(int fd, GBM *gbm, GBMRGB *gbmrgb)
|
|---|
| 111 | {
|
|---|
| 112 | switch ( gbm->bpp )
|
|---|
| 113 | {
|
|---|
| 114 | /*...s1 \45\ fixed b\47\w palette:16:*/
|
|---|
| 115 | case 1:
|
|---|
| 116 | gbmrgb[0].r = gbmrgb[0].g = gbmrgb[0].b = 0x00;
|
|---|
| 117 | gbmrgb[1].r = gbmrgb[1].g = gbmrgb[1].b = 0xff;
|
|---|
| 118 | break;
|
|---|
| 119 | /*...e*/
|
|---|
| 120 | /*...s4 \45\ read palette if 1 plane\44\ fix one if 4 plane RGBI:16:*/
|
|---|
| 121 | case 4:
|
|---|
| 122 | /* Use inline palette */
|
|---|
| 123 | {
|
|---|
| 124 | byte b[16*3];
|
|---|
| 125 | int i;
|
|---|
| 126 |
|
|---|
| 127 | gbm_file_lseek(fd, 16L, SEEK_SET);
|
|---|
| 128 | gbm_file_read(fd, b, 16 * 3);
|
|---|
| 129 | for ( i = 0; i < 16; i++ )
|
|---|
| 130 | {
|
|---|
| 131 | gbmrgb[i].r = b[i * 3 + 0];
|
|---|
| 132 | gbmrgb[i].g = b[i * 3 + 1];
|
|---|
| 133 | gbmrgb[i].b = b[i * 3 + 2];
|
|---|
| 134 | }
|
|---|
| 135 | }
|
|---|
| 136 | break;
|
|---|
| 137 | /*...e*/
|
|---|
| 138 | /*...s8 \45\ read palette from end of file:16:*/
|
|---|
| 139 | case 8:
|
|---|
| 140 | {
|
|---|
| 141 | byte trailer_id;
|
|---|
| 142 | byte b[0x100*3];
|
|---|
| 143 | int i;
|
|---|
| 144 |
|
|---|
| 145 | gbm_file_lseek(fd, -0x301L, SEEK_END);
|
|---|
| 146 | gbm_file_read(fd, &trailer_id, 1);
|
|---|
| 147 | if ( trailer_id != 0x0c )
|
|---|
| 148 | return GBM_ERR_PCX_BAD_TRAILER;
|
|---|
| 149 |
|
|---|
| 150 | gbm_file_read(fd, b, 0x100 * 3);
|
|---|
| 151 | for ( i = 0; i < 0x100; i++ )
|
|---|
| 152 | {
|
|---|
| 153 | gbmrgb[i].r = b[i * 3 + 0];
|
|---|
| 154 | gbmrgb[i].g = b[i * 3 + 1];
|
|---|
| 155 | gbmrgb[i].b = b[i * 3 + 2];
|
|---|
| 156 | }
|
|---|
| 157 | }
|
|---|
| 158 | break;
|
|---|
| 159 | /*...e*/
|
|---|
| 160 | }
|
|---|
| 161 | return GBM_ERR_OK;
|
|---|
| 162 | }
|
|---|
| 163 | /*...e*/
|
|---|
| 164 | /*...spcx_rdata:0:*/
|
|---|
| 165 | /*...sread_pcx_line:0:*/
|
|---|
| 166 | static void read_pcx_line(
|
|---|
| 167 | AHEAD *ahead, byte *line, int bytes_per_line,
|
|---|
| 168 | byte *runleft, byte *runval
|
|---|
| 169 | )
|
|---|
| 170 | {
|
|---|
| 171 | /* Handle left overs from previous line */
|
|---|
| 172 |
|
|---|
| 173 | while ( *runleft > 0 && bytes_per_line > 0 )
|
|---|
| 174 | {
|
|---|
| 175 | *line++ = *runval;
|
|---|
| 176 | (*runleft)--;
|
|---|
| 177 | bytes_per_line--;
|
|---|
| 178 | }
|
|---|
| 179 |
|
|---|
| 180 | /* Normal code */
|
|---|
| 181 |
|
|---|
| 182 | while ( bytes_per_line )
|
|---|
| 183 | {
|
|---|
| 184 | byte b1 = (byte) gbm_read_ahead(ahead);
|
|---|
| 185 |
|
|---|
| 186 | if ( (b1 & 0xc0) == 0xc0 )
|
|---|
| 187 | {
|
|---|
| 188 | byte b2 = (byte) gbm_read_ahead(ahead);
|
|---|
| 189 |
|
|---|
| 190 | b1 &= 0x3f;
|
|---|
| 191 | if ( b1 > bytes_per_line )
|
|---|
| 192 | {
|
|---|
| 193 | (*runleft) = (byte) (b1 - bytes_per_line);
|
|---|
| 194 | (*runval) = b2;
|
|---|
| 195 | b1 = bytes_per_line;
|
|---|
| 196 | }
|
|---|
| 197 | memset(line, b2, b1);
|
|---|
| 198 | line += b1;
|
|---|
| 199 | bytes_per_line -= b1;
|
|---|
| 200 | }
|
|---|
| 201 | else
|
|---|
| 202 | {
|
|---|
| 203 | *line++ = b1;
|
|---|
| 204 | bytes_per_line--;
|
|---|
| 205 | }
|
|---|
| 206 | }
|
|---|
| 207 | }
|
|---|
| 208 | /*...e*/
|
|---|
| 209 | /*...sspread:0:*/
|
|---|
| 210 | static void spread(byte b, byte bit_to_set, byte *dest)
|
|---|
| 211 | {
|
|---|
| 212 | if ( b & 0x80 ) dest[0] |= (bit_to_set & 0xf0);
|
|---|
| 213 | if ( b & 0x40 ) dest[0] |= (bit_to_set & 0x0f);
|
|---|
| 214 | if ( b & 0x20 ) dest[1] |= (bit_to_set & 0xf0);
|
|---|
| 215 | if ( b & 0x10 ) dest[1] |= (bit_to_set & 0x0f);
|
|---|
| 216 | if ( b & 0x08 ) dest[2] |= (bit_to_set & 0xf0);
|
|---|
| 217 | if ( b & 0x04 ) dest[2] |= (bit_to_set & 0x0f);
|
|---|
| 218 | if ( b & 0x02 ) dest[3] |= (bit_to_set & 0xf0);
|
|---|
| 219 | if ( b & 0x01 ) dest[3] |= (bit_to_set & 0x0f);
|
|---|
| 220 | }
|
|---|
| 221 | /*...e*/
|
|---|
| 222 |
|
|---|
| 223 | GBM_ERR pcx_rdata(int fd, GBM *gbm, byte *data)
|
|---|
| 224 | {
|
|---|
| 225 | PCX_PRIV *pcx_priv = (PCX_PRIV *) gbm->priv;
|
|---|
| 226 | BOOLEAN trunc = pcx_priv->trunc;
|
|---|
| 227 | int bytes_per_line = pcx_priv->bytes_per_line;
|
|---|
| 228 | int stride, y;
|
|---|
| 229 | byte *line;
|
|---|
| 230 | AHEAD *ahead;
|
|---|
| 231 | byte runleft = 0, runval;
|
|---|
| 232 |
|
|---|
| 233 | if ( (ahead = gbm_create_ahead(fd)) == NULL )
|
|---|
| 234 | return GBM_ERR_MEM;
|
|---|
| 235 |
|
|---|
| 236 | gbm_file_lseek(fd, 128L, SEEK_SET);
|
|---|
| 237 |
|
|---|
| 238 | if ( (line = malloc((size_t) bytes_per_line)) == NULL )
|
|---|
| 239 | {
|
|---|
| 240 | gbm_destroy_ahead(ahead);
|
|---|
| 241 | return GBM_ERR_MEM;
|
|---|
| 242 | }
|
|---|
| 243 |
|
|---|
| 244 | switch ( gbm->bpp )
|
|---|
| 245 | {
|
|---|
| 246 | /*...s1:16:*/
|
|---|
| 247 | case 1:
|
|---|
| 248 | stride = ((gbm->w + 31) / 32) * 4;
|
|---|
| 249 | for ( y = gbm->h - 1; y >= 0; y-- )
|
|---|
| 250 | {
|
|---|
| 251 | read_pcx_line(ahead, data + y * stride, bytes_per_line, &runleft, &runval);
|
|---|
| 252 | if ( trunc )
|
|---|
| 253 | runleft = 0;
|
|---|
| 254 | }
|
|---|
| 255 | break;
|
|---|
| 256 | /*...e*/
|
|---|
| 257 | /*...s4:16:*/
|
|---|
| 258 | case 4:
|
|---|
| 259 | stride = ((gbm->w * 4 + 31) / 32) * 4;
|
|---|
| 260 | if ( pcx_priv->planes == 1 )
|
|---|
| 261 | for ( y = gbm->h - 1; y >= 0; y-- )
|
|---|
| 262 | {
|
|---|
| 263 | read_pcx_line(ahead, data + y * stride, bytes_per_line, &runleft, &runval);
|
|---|
| 264 | if ( trunc )
|
|---|
| 265 | runleft = 0;
|
|---|
| 266 | }
|
|---|
| 267 | else
|
|---|
| 268 | {
|
|---|
| 269 | int p, x;
|
|---|
| 270 | int bytes = (gbm->w / 8);
|
|---|
| 271 | int bits = (gbm->w & 7);
|
|---|
| 272 |
|
|---|
| 273 | memset(data, 0, gbm->h * stride);
|
|---|
| 274 | for ( y = gbm->h - 1; y >= 0; y-- )
|
|---|
| 275 | for ( p = 0x11; p <= 0x88 ; p <<= 1 )
|
|---|
| 276 | {
|
|---|
| 277 | byte *dest = data + y * stride;
|
|---|
| 278 |
|
|---|
| 279 | read_pcx_line(ahead, line, bytes_per_line, &runleft, &runval);
|
|---|
| 280 | if ( trunc )
|
|---|
| 281 | runleft = 0;
|
|---|
| 282 | for ( x = 0; x < bytes; x++, dest += 4 )
|
|---|
| 283 | spread(line[x], (byte) p, dest);
|
|---|
| 284 | if ( bits )
|
|---|
| 285 | spread((byte) (line[x] & (0xff00U >> bits)), (byte) p, dest);
|
|---|
| 286 | }
|
|---|
| 287 | }
|
|---|
| 288 | break;
|
|---|
| 289 | /*...e*/
|
|---|
| 290 | /*...s8:16:*/
|
|---|
| 291 | case 8:
|
|---|
| 292 | stride = ((gbm->w + 3) & ~3);
|
|---|
| 293 | for ( y = gbm->h - 1; y >= 0; y-- )
|
|---|
| 294 | {
|
|---|
| 295 | read_pcx_line(ahead, data + y * stride, bytes_per_line, &runleft, &runval);
|
|---|
| 296 | if ( trunc )
|
|---|
| 297 | runleft = 0;
|
|---|
| 298 | }
|
|---|
| 299 | break;
|
|---|
| 300 | /*...e*/
|
|---|
| 301 | /*...s24:16:*/
|
|---|
| 302 | case 24:
|
|---|
| 303 | {
|
|---|
| 304 | int p, x;
|
|---|
| 305 |
|
|---|
| 306 | stride = ((gbm->w * 3 + 3) & ~3);
|
|---|
| 307 | for ( y = gbm->h - 1; y >= 0; y-- )
|
|---|
| 308 | for ( p = 2; p >= 0; p-- )
|
|---|
| 309 | {
|
|---|
| 310 | read_pcx_line(ahead, line, bytes_per_line, &runleft, &runval);
|
|---|
| 311 | if ( trunc )
|
|---|
| 312 | runleft = 0;
|
|---|
| 313 | for ( x = 0; x < gbm->w; x++ )
|
|---|
| 314 | data[y * stride + p + x * 3] = line[x];
|
|---|
| 315 | }
|
|---|
| 316 | }
|
|---|
| 317 | break;
|
|---|
| 318 | /*...e*/
|
|---|
| 319 | }
|
|---|
| 320 |
|
|---|
| 321 | free(line);
|
|---|
| 322 |
|
|---|
| 323 | gbm_destroy_ahead(ahead);
|
|---|
| 324 |
|
|---|
| 325 | return GBM_ERR_OK;
|
|---|
| 326 | }
|
|---|
| 327 | /*...e*/
|
|---|
| 328 | /*...spcx_w:0:*/
|
|---|
| 329 | /*...sbright:0:*/
|
|---|
| 330 | static int bright(const GBMRGB *gbmrgb)
|
|---|
| 331 | {
|
|---|
| 332 | return gbmrgb->r*30+gbmrgb->g*60+gbmrgb->b*10;
|
|---|
| 333 | }
|
|---|
| 334 | /*...e*/
|
|---|
| 335 | /*...spcx_rle:0:*/
|
|---|
| 336 | static byte pcx_run(const byte *src, int n_src)
|
|---|
| 337 | {
|
|---|
| 338 | byte cnt = 1;
|
|---|
| 339 | byte b = *src++;
|
|---|
| 340 |
|
|---|
| 341 | --n_src;
|
|---|
| 342 | while ( cnt < 0x3f && n_src > 0 && *src == b )
|
|---|
| 343 | { cnt++; n_src--; src++; }
|
|---|
| 344 |
|
|---|
| 345 | return cnt;
|
|---|
| 346 | }
|
|---|
| 347 |
|
|---|
| 348 | static void pcx_rle(const byte *src, int n_src, byte *dst, int *n_dst)
|
|---|
| 349 | {
|
|---|
| 350 | *n_dst = 0;
|
|---|
| 351 | while ( n_src )
|
|---|
| 352 | {
|
|---|
| 353 | byte len;
|
|---|
| 354 |
|
|---|
| 355 | if ( (len = pcx_run(src, n_src)) > 1 || (*src & 0xc0) == 0xc0 )
|
|---|
| 356 | {
|
|---|
| 357 | *dst++ = (byte) (0xc0 | len);
|
|---|
| 358 | *dst++ = *src;
|
|---|
| 359 | (*n_dst) += 2;
|
|---|
| 360 | }
|
|---|
| 361 | else
|
|---|
| 362 | {
|
|---|
| 363 | *dst++ = *src;
|
|---|
| 364 | (*n_dst)++;
|
|---|
| 365 | }
|
|---|
| 366 | src += len;
|
|---|
| 367 | n_src -= len;
|
|---|
| 368 | }
|
|---|
| 369 | }
|
|---|
| 370 | /*...e*/
|
|---|
| 371 |
|
|---|
| 372 | GBM_ERR pcx_w(const char *fn, int fd, const GBM *gbm, const GBMRGB *gbmrgb, const byte *data, const char *opt)
|
|---|
| 373 | {
|
|---|
| 374 | int i, y, stride = ((gbm->bpp * gbm->w + 31) / 32) * 4;
|
|---|
| 375 | byte *line;
|
|---|
| 376 | byte hdr[128];
|
|---|
| 377 | int bytes_per_line, cnt;
|
|---|
| 378 |
|
|---|
| 379 | fn=fn; opt=opt; /* Suppress 'unref arg' compiler warning */
|
|---|
| 380 |
|
|---|
| 381 | memset(hdr, 0, 128);
|
|---|
| 382 | hdr[ 0] = 0x0a; /* Magic # */
|
|---|
| 383 | hdr[ 1] = 5; /* Version 5 */
|
|---|
| 384 | hdr[ 2] = 1; /* RLE compression */
|
|---|
| 385 | hdr[ 3] = (byte) ( ( gbm->bpp == 24 ) ? 8 : gbm->bpp );
|
|---|
| 386 | /* Bits per plane */
|
|---|
| 387 | hdr[ 4] = low_byte(0);
|
|---|
| 388 | hdr[ 5] = high_byte(0); /* Top left x */
|
|---|
| 389 | hdr[ 6] = low_byte(0);
|
|---|
| 390 | hdr[ 7] = high_byte(0); /* Top left y */
|
|---|
| 391 | hdr[ 8] = low_byte(gbm->w - 1);
|
|---|
| 392 | hdr[ 9] = high_byte(gbm->w - 1); /* Bottom right x */
|
|---|
| 393 | hdr[10] = low_byte(gbm->h - 1);
|
|---|
| 394 | hdr[11] = high_byte(gbm->h - 1); /* Bottom right y */
|
|---|
| 395 | hdr[12] = low_byte(0);
|
|---|
| 396 | hdr[13] = high_byte(0); /* Horizontal resolution ??? */
|
|---|
| 397 | hdr[14] = low_byte(0);
|
|---|
| 398 | hdr[15] = high_byte(0); /* Vertical resolution ??? */
|
|---|
| 399 |
|
|---|
| 400 | if ( gbm->bpp == 4 )
|
|---|
| 401 | for ( i = 0; i < 16; i++ )
|
|---|
| 402 | {
|
|---|
| 403 | hdr[16 + i * 3 ] = gbmrgb[i].r;
|
|---|
| 404 | hdr[16 + i * 3 + 1] = gbmrgb[i].g;
|
|---|
| 405 | hdr[16 + i * 3 + 2] = gbmrgb[i].b;
|
|---|
| 406 | }
|
|---|
| 407 |
|
|---|
| 408 | hdr[65] = (byte) ( ( gbm->bpp == 24 ) ? 3 : 1 );
|
|---|
| 409 | /* Planes */
|
|---|
| 410 | bytes_per_line = (gbm->w * hdr[3] + 7) / 8;
|
|---|
| 411 | if ( bytes_per_line & 1 )
|
|---|
| 412 | bytes_per_line++;
|
|---|
| 413 | hdr[66] = low_byte(bytes_per_line);
|
|---|
| 414 | hdr[67] = high_byte(bytes_per_line);
|
|---|
| 415 | hdr[68] = 1; /* Colour or b/w */
|
|---|
| 416 |
|
|---|
| 417 | gbm_file_write(fd, hdr, 128);
|
|---|
| 418 |
|
|---|
| 419 | if ( (line = malloc((size_t) (bytes_per_line * 2))) == NULL )
|
|---|
| 420 | return GBM_ERR_MEM;
|
|---|
| 421 |
|
|---|
| 422 | switch ( gbm->bpp )
|
|---|
| 423 | {
|
|---|
| 424 | /*...s1:16:*/
|
|---|
| 425 | case 1:
|
|---|
| 426 | if ( bright(&gbmrgb[0]) > bright(&gbmrgb[1]) )
|
|---|
| 427 | /* Need to invert bitmap bits */
|
|---|
| 428 | {
|
|---|
| 429 | byte *b;
|
|---|
| 430 | if ( (b = malloc(bytes_per_line)) == NULL )
|
|---|
| 431 | {
|
|---|
| 432 | free(line);
|
|---|
| 433 | return GBM_ERR_MEM;
|
|---|
| 434 | }
|
|---|
| 435 | for ( y = gbm->h - 1; y >= 0; y-- )
|
|---|
| 436 | {
|
|---|
| 437 | int i;
|
|---|
| 438 | for ( i = 0; i < bytes_per_line; i++ )
|
|---|
| 439 | b[i] = data[y*stride+i] ^ 0xffU;
|
|---|
| 440 | pcx_rle(b, bytes_per_line, line, &cnt);
|
|---|
| 441 | if ( gbm_file_write(fd, line, cnt) != cnt )
|
|---|
| 442 | {
|
|---|
| 443 | free(b);
|
|---|
| 444 | free(line);
|
|---|
| 445 | return GBM_ERR_WRITE;
|
|---|
| 446 | }
|
|---|
| 447 | }
|
|---|
| 448 | free(b);
|
|---|
| 449 | break;
|
|---|
| 450 | }
|
|---|
| 451 | /* Fall through to regular non-invert case */
|
|---|
| 452 | /*...e*/
|
|---|
| 453 | /*...s4\44\8:16:*/
|
|---|
| 454 | case 4:
|
|---|
| 455 | case 8:
|
|---|
| 456 | for ( y = gbm->h - 1; y >= 0; y-- )
|
|---|
| 457 | {
|
|---|
| 458 | pcx_rle(data + y * stride, bytes_per_line, line, &cnt);
|
|---|
| 459 | if ( gbm_file_write(fd, line, cnt) != cnt )
|
|---|
| 460 | {
|
|---|
| 461 | free(line);
|
|---|
| 462 | return GBM_ERR_WRITE;
|
|---|
| 463 | }
|
|---|
| 464 | }
|
|---|
| 465 | break;
|
|---|
| 466 | /*...e*/
|
|---|
| 467 | /*...s24:16:*/
|
|---|
| 468 | case 24:
|
|---|
| 469 | {
|
|---|
| 470 | byte *line2;
|
|---|
| 471 | int p, x;
|
|---|
| 472 |
|
|---|
| 473 | if ( (line2 = malloc((size_t) bytes_per_line)) == NULL )
|
|---|
| 474 | {
|
|---|
| 475 | free(line);
|
|---|
| 476 | return GBM_ERR_MEM;
|
|---|
| 477 | }
|
|---|
| 478 |
|
|---|
| 479 | for ( y = gbm->h - 1; y >= 0; y-- )
|
|---|
| 480 | for ( p = 2; p >= 0; p-- )
|
|---|
| 481 | {
|
|---|
| 482 | const byte *src = data + y * stride;
|
|---|
| 483 |
|
|---|
| 484 | for ( x = 0; x < gbm->w; x++ )
|
|---|
| 485 | line2[x] = src[x * 3 + p];
|
|---|
| 486 |
|
|---|
| 487 | pcx_rle(line2, bytes_per_line, line, &cnt);
|
|---|
| 488 | if ( gbm_file_write(fd, line, cnt) != cnt )
|
|---|
| 489 | {
|
|---|
| 490 | free(line2);
|
|---|
| 491 | free(line);
|
|---|
| 492 | return GBM_ERR_WRITE;
|
|---|
| 493 | }
|
|---|
| 494 | }
|
|---|
| 495 | free(line2);
|
|---|
| 496 | }
|
|---|
| 497 | break;
|
|---|
| 498 | /*...e*/
|
|---|
| 499 | }
|
|---|
| 500 |
|
|---|
| 501 | free(line);
|
|---|
| 502 |
|
|---|
| 503 | if ( gbm->bpp == 8 )
|
|---|
| 504 | {
|
|---|
| 505 | byte pal[1 + 0x100 * 3];
|
|---|
| 506 |
|
|---|
| 507 | pal[0] = 0x0c;
|
|---|
| 508 | for ( i = 0; i < 0x100; i++ )
|
|---|
| 509 | {
|
|---|
| 510 | pal[i * 3 + 1] = gbmrgb[i].r;
|
|---|
| 511 | pal[i * 3 + 2] = gbmrgb[i].g;
|
|---|
| 512 | pal[i * 3 + 3] = gbmrgb[i].b;
|
|---|
| 513 | }
|
|---|
| 514 | gbm_file_write(fd, pal, 1 + 0x100 * 3);
|
|---|
| 515 | }
|
|---|
| 516 |
|
|---|
| 517 | return GBM_ERR_OK;
|
|---|
| 518 | }
|
|---|
| 519 | /*...e*/
|
|---|
| 520 | /*...spcx_err:0:*/
|
|---|
| 521 | const char *pcx_err(GBM_ERR rc)
|
|---|
| 522 | {
|
|---|
| 523 | switch ( (int) rc )
|
|---|
| 524 | {
|
|---|
| 525 | case GBM_ERR_PCX_BAD_VERSION:
|
|---|
| 526 | return "version number not 4 or 5";
|
|---|
| 527 | case GBM_ERR_PCX_BAD_ENCMODE:
|
|---|
| 528 | return "encoding mode not 1";
|
|---|
| 529 | case GBM_ERR_PCX_BAD_BITS:
|
|---|
| 530 | return "unsupported bpp/plane / plane combination";
|
|---|
| 531 | case GBM_ERR_PCX_BAD_TRAILER:
|
|---|
| 532 | return "corrupt file trailer";
|
|---|
| 533 | }
|
|---|
| 534 | return NULL;
|
|---|
| 535 | }
|
|---|
| 536 | /*...e*/
|
|---|