source: trunk/JPGPROC/source/gbmsrc/gbmpcx.c@ 2

Last change on this file since 2 was 2, checked in by stevenhl, 8 years ago

Import sources from cwmm-full.zip dated 2005-03-21

File size: 11.0 KB
Line 
1/*
2
3gbmpcx.c - ZSoft PC Paintbrush support
4
5Reads 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
28static 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
42typedef struct
43 {
44 byte version, bpppp, planes;
45 int bytes_per_line;
46 BOOLEAN trunc;
47 } PCX_PRIV;
48
49/*...spcx_qft:0:*/
50GBM_ERR pcx_qft(GBMFT *gbmft)
51 {
52 *gbmft = pcx_gbmft;
53 return GBM_ERR_OK;
54 }
55/*...e*/
56/*...spcx_rhdr:0:*/
57GBM_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:*/
110GBM_ERR pcx_rpal(int fd, GBM *gbm, GBMRGB *gbmrgb)
111 {
112 switch ( gbm->bpp )
113 {
114/*...s1 \45\ fixed b\47\w palette:16:*/
115case 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:*/
121case 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:*/
139case 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:*/
166static 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:*/
210static 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
223GBM_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:*/
247case 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:*/
258case 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:*/
291case 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:*/
302case 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:*/
330static int bright(const GBMRGB *gbmrgb)
331 {
332 return gbmrgb->r*30+gbmrgb->g*60+gbmrgb->b*10;
333 }
334/*...e*/
335/*...spcx_rle:0:*/
336static 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
348static 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
372GBM_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:*/
425case 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:*/
454case 4:
455case 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:*/
468case 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:*/
521const 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*/
Note: See TracBrowser for help on using the repository browser.