home *** CD-ROM | disk | FTP | other *** search
- /*
-
- GBMPCX.C ZSoft PC Paintbrush support
-
- Reads and writes 1,4,8 and 24 bit colour files.
-
- */
-
- /*...sincludes:0:*/
- #include <stdio.h>
- #include <ctype.h>
- #include <stddef.h>
- #include <stdlib.h>
- #include <string.h>
- #include <memory.h>
- #include <malloc.h>
- #ifdef AIX
- #include <unistd.h>
- #else
- #include <io.h>
- #endif
- #include <fcntl.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include "standard.h"
- #include "gbm.h"
-
- /*...vgbm\46\h:0:*/
- /*...e*/
-
- /*...suseful:0:*/
- #define low_byte(w) ((byte) ((w)&0x00ff) )
- #define high_byte(w) ((byte) (((w)&0xff00)>>8))
- #define make_word(a,b) (((word)a) + (((word)b) << 8))
- /*...e*/
- /*...ssame:0:*/
- static BOOLEAN same(char *s1, char *s2, int n)
- {
- for ( ; n--; s1++, s2++ )
- if ( tolower(*s1) != tolower(*s2) )
- return ( FALSE );
- return ( TRUE );
- }
- /*...e*/
- /*...sfind_word:0:*/
- static char *find_word(char *str, char *substr)
- {
- char buf [100+1], *s;
- int len = strlen(substr);
-
- for ( s = strtok(strcpy(buf, str), " \t,");
- s != NULL;
- s = strtok(NULL, " \t,") )
- if ( same(s, substr, len) && s [len] == '\0' )
- return ( str + (s - buf) );
- return ( NULL );
- }
- /*...e*/
- /*...sreading ahead:0:*/
- #define AHEAD_BUF 0x4000
-
- typedef struct
- {
- byte buf [AHEAD_BUF];
- int inx, cnt;
- int fd;
- } AHEAD;
-
- static AHEAD *create_ahead(int fd)
- {
- AHEAD *ahead;
-
- if ( (ahead = malloc(sizeof(AHEAD))) == NULL )
- return ( NULL );
-
- ahead -> inx = 0;
- ahead -> cnt = 0;
- ahead -> fd = fd;
-
- return ( ahead );
- }
-
- static void destroy_ahead(AHEAD *ahead)
- {
- free(ahead);
- }
-
- static byte next(AHEAD *ahead)
- {
- if ( ahead -> inx >= ahead -> cnt )
- {
- ahead -> cnt = read(ahead -> fd, (char *) ahead -> buf, AHEAD_BUF);
- ahead -> inx = 0;
- }
- return ( ahead -> buf [ahead -> inx++] );
- }
- /*...e*/
-
- static GBMFT pcx_gbmft =
- {
- "PCX",
- "ZSoft PC Paintbrush Image format",
- "PCX",
- GBM_FT_R1|GBM_FT_R4|GBM_FT_R8|GBM_FT_R24|
- GBM_FT_W1|GBM_FT_W4|GBM_FT_W8|GBM_FT_W24,
- };
-
- #define GBM_ERR_PCX_BAD_VERSION ((GBM_ERR) 700)
- #define GBM_ERR_PCX_BAD_ENCMODE ((GBM_ERR) 701)
- #define GBM_ERR_PCX_BAD_BITS ((GBM_ERR) 702)
- #define GBM_ERR_PCX_BAD_TRAILER ((GBM_ERR) 703)
-
- typedef struct
- {
- byte version, bpppp, planes;
- int bytes_per_line;
- BOOLEAN trunc;
- } PCX_PRIV;
-
- /*...spcx_qft:0:*/
- GBM_ERR pcx_qft(GBMFT *gbmft)
- {
- *gbmft = pcx_gbmft;
- return ( GBM_ERR_OK );
- }
- /*...e*/
- /*...spcx_rhdr:0:*/
- GBM_ERR pcx_rhdr(char *fn, int fd, GBM *gbm, char *opt)
- {
- PCX_PRIV *pcx_priv = (PCX_PRIV *) gbm -> priv;
- byte hdr [70];
- word x1, y1, x2, y2;
- int w, h, bpp;
-
- fn=fn; /* Suppress 'unref arg' compiler warning */
-
- pcx_priv -> trunc = ( find_word(opt, "trunc" ) != NULL );
-
- lseek(fd, 0L, SEEK_SET);
-
- read(fd, hdr, 70);
- if ( hdr [0] != 0x0a )
- return ( GBM_ERR_BAD_MAGIC );
- pcx_priv -> version = hdr [1];
- if ( pcx_priv -> version == 4 || pcx_priv -> version > 5 )
- return ( GBM_ERR_PCX_BAD_VERSION );
- if ( hdr [2] != 1 )
- return ( GBM_ERR_PCX_BAD_ENCMODE );
-
- pcx_priv -> bpppp = hdr [3]; pcx_priv -> planes = hdr [65];
- #define SWITCH2(a,b) (((a)<<8)|(b))
- switch ( SWITCH2(pcx_priv -> bpppp, pcx_priv -> planes) )
- {
- case SWITCH2(1,1): bpp = 1; break;
- case SWITCH2(4,1): bpp = 4; break;
- case SWITCH2(8,1): bpp = 8; break;
- case SWITCH2(8,3): bpp = 24; break; /* Extended 24 bit style */
- case SWITCH2(1,4): bpp = 4; break; /* EGA RGBI style */
- default: return ( GBM_ERR_PCX_BAD_BITS );
- }
-
- x1 = make_word(hdr [ 4], hdr [ 5]);
- y1 = make_word(hdr [ 6], hdr [ 7]);
- x2 = make_word(hdr [ 8], hdr [ 9]);
- y2 = make_word(hdr [10], hdr [11]);
-
- w = x2 - x1 + 1;
- h = y2 - y1 + 1;
-
- if ( w <= 0 || h <= 0 )
- return ( GBM_ERR_BAD_SIZE );
-
- pcx_priv -> bytes_per_line = make_word(hdr [66], hdr [67]);
-
- gbm -> w = w;
- gbm -> h = h;
- gbm -> bpp = bpp;
-
- return ( GBM_ERR_OK );
- }
- /*...e*/
- /*...spcx_rpal:0:*/
- GBM_ERR pcx_rpal(int fd, GBM *gbm, GBMRGB *gbmrgb)
- {
- switch ( gbm -> bpp )
- {
- /*...s1 \45\ fixed b\47\w palette:16:*/
- case 1:
- gbmrgb [0].r = gbmrgb [0].g = gbmrgb [0].b = 0x00;
- gbmrgb [1].r = gbmrgb [1].g = gbmrgb [1].b = 0xff;
- break;
- /*...e*/
- /*...s4 \45\ read palette if 1 plane\44\ fix one if 4 plane RGBI:16:*/
- case 4:
- /* Use inline palette */
- {
- byte b [16*3];
- int i;
-
- lseek(fd, 16L, SEEK_SET);
- read(fd, b, 16 * 3);
- for ( i = 0; i < 16; i++ )
- {
- gbmrgb [i].r = b [i * 3 + 0];
- gbmrgb [i].g = b [i * 3 + 1];
- gbmrgb [i].b = b [i * 3 + 2];
- }
- }
- break;
- /*...e*/
- /*...s8 \45\ read palette from end of file:16:*/
- case 8:
- {
- byte trailer_id;
- byte b [0x100*3];
- int i;
-
- lseek(fd, -0x301L, SEEK_END);
- read(fd, &trailer_id, 1);
- if ( trailer_id != 0x0c )
- return ( GBM_ERR_PCX_BAD_TRAILER );
-
- read(fd, b, 0x100 * 3);
- for ( i = 0; i < 0x100; i++ )
- {
- gbmrgb [i].r = b [i * 3 + 0];
- gbmrgb [i].g = b [i * 3 + 1];
- gbmrgb [i].b = b [i * 3 + 2];
- }
- }
- break;
- /*...e*/
- }
- return ( GBM_ERR_OK );
- }
- /*...e*/
- /*...spcx_rdata:0:*/
- /*...sread_pcx_line:0:*/
- static void read_pcx_line(
- AHEAD *ahead, byte *line, int bytes_per_line,
- byte *runleft, byte *runval
- )
- {
- /* Handle left overs from previous line */
-
- while ( *runleft > 0 && bytes_per_line > 0 )
- {
- *line++ = *runval;
- (*runleft)--;
- bytes_per_line--;
- }
-
- /* Normal code */
-
- while ( bytes_per_line )
- {
- byte b1 = next(ahead);
-
- if ( (b1 & 0xc0) == 0xc0 )
- {
- byte b2 = next(ahead);
-
- b1 &= 0x3f;
- if ( b1 > bytes_per_line )
- {
- (*runleft) = (byte) (b1 - bytes_per_line);
- (*runval) = b2;
- b1 = bytes_per_line;
- }
- memset(line, b2, b1);
- line += b1;
- bytes_per_line -= b1;
- }
- else
- {
- *line++ = b1;
- bytes_per_line--;
- }
- }
- }
- /*...e*/
- /*...sspread:0:*/
- static void spread(byte b, byte bit_to_set, byte *dest)
- {
- if ( b & 0x80 ) dest [0] |= (bit_to_set & 0xf0);
- if ( b & 0x40 ) dest [0] |= (bit_to_set & 0x0f);
- if ( b & 0x20 ) dest [1] |= (bit_to_set & 0xf0);
- if ( b & 0x10 ) dest [1] |= (bit_to_set & 0x0f);
- if ( b & 0x08 ) dest [2] |= (bit_to_set & 0xf0);
- if ( b & 0x04 ) dest [2] |= (bit_to_set & 0x0f);
- if ( b & 0x02 ) dest [3] |= (bit_to_set & 0xf0);
- if ( b & 0x01 ) dest [3] |= (bit_to_set & 0x0f);
- }
- /*...e*/
-
- GBM_ERR pcx_rdata(int fd, GBM *gbm, byte *data)
- {
- PCX_PRIV *pcx_priv = (PCX_PRIV *) gbm -> priv;
- BOOLEAN trunc = pcx_priv -> trunc;
- int bytes_per_line = pcx_priv -> bytes_per_line;
- int stride, y;
- byte *line;
- AHEAD *ahead;
- byte runleft = 0, runval;
-
- if ( (ahead = create_ahead(fd)) == NULL )
- return ( GBM_ERR_MEM );
-
- lseek(fd, 128L, SEEK_SET);
-
- if ( (line = malloc(bytes_per_line)) == NULL )
- {
- destroy_ahead(ahead);
- return ( GBM_ERR_MEM );
- }
-
- switch ( gbm -> bpp )
- {
- /*...s1:16:*/
- case 1:
- stride = ((gbm -> w + 31) / 32) * 4;
- for ( y = gbm -> h - 1; y >= 0; y-- )
- {
- read_pcx_line(ahead, data + y * stride, bytes_per_line, &runleft, &runval);
- if ( trunc )
- runleft = 0;
- }
- break;
- /*...e*/
- /*...s4:16:*/
- case 4:
- stride = ((gbm -> w * 4 + 31) / 32) * 4;
- if ( pcx_priv -> planes == 1 )
- for ( y = gbm -> h - 1; y >= 0; y-- )
- {
- read_pcx_line(ahead, data + y * stride, bytes_per_line, &runleft, &runval);
- if ( trunc )
- runleft = 0;
- }
- else
- {
- int p, x;
- int bytes = (gbm -> w / 8);
- int bits = (gbm -> w & 7);
-
- memset(data, 0, gbm -> h * stride);
- for ( y = gbm -> h - 1; y >= 0; y-- )
- for ( p = 0x11; p <= 0x88 ; p <<= 1 )
- {
- byte *dest = data + y * stride;
-
- read_pcx_line(ahead, line, bytes_per_line, &runleft, &runval);
- if ( trunc )
- runleft = 0;
- for ( x = 0; x < bytes; x++, dest += 4 )
- spread(line [x], p, dest);
- if ( bits )
- spread((byte) (line [x] & (0xff00 >> bits)), p, dest);
- }
- }
- break;
- /*...e*/
- /*...s8:16:*/
- case 8:
- stride = ((gbm -> w + 3) & ~3);
- for ( y = gbm -> h - 1; y >= 0; y-- )
- {
- read_pcx_line(ahead, data + y * stride, bytes_per_line, &runleft, &runval);
- if ( trunc )
- runleft = 0;
- }
- break;
- /*...e*/
- /*...s24:16:*/
- case 24:
- {
- int p, x;
-
- stride = ((gbm -> w * 3 + 3) & ~3);
- for ( y = gbm -> h - 1; y >= 0; y-- )
- for ( p = 2; p >= 0; p-- )
- {
- read_pcx_line(ahead, line, bytes_per_line, &runleft, &runval);
- if ( trunc )
- runleft = 0;
- for ( x = 0; x < gbm -> w; x++ )
- data [y * stride + p + x * 3] = line [x];
- }
- }
- break;
- /*...e*/
- }
-
- free(line);
-
- destroy_ahead(ahead);
-
- return ( GBM_ERR_OK );
- }
- /*...e*/
- /*...spcx_w:0:*/
- /*...spcx_rle:0:*/
- static byte pcx_run(byte *src, int n_src)
- {
- byte cnt = 1;
- byte b = *src++;
-
- --n_src;
- while ( cnt < 0x3f && n_src > 0 && *src == b )
- { cnt++; n_src--; src++; }
-
- return ( cnt );
- }
-
- static void pcx_rle(byte *src, int n_src, byte *dst, int *n_dst)
- {
- *n_dst = 0;
- while ( n_src )
- {
- byte len;
-
- if ( (len = pcx_run(src, n_src)) > 1 || (*src & 0xc0) == 0xc0 )
- {
- *dst++ = (byte) (0xc0 | len);
- *dst++ = *src;
- (*n_dst) += 2;
- }
- else
- {
- *dst++ = *src;
- (*n_dst)++;
- }
- src += len;
- n_src -= len;
- }
- }
- /*...e*/
-
- GBM_ERR pcx_w(char *fn, int fd, GBM *gbm, GBMRGB *gbmrgb, byte *data, char *opt)
- {
- int i, y, stride = ((gbm -> bpp * gbm -> w + 31) / 32) * 4;
- byte *line;
- byte hdr [128];
- int bytes_per_line, cnt;
-
- fn=fn; opt=opt; /* Suppress 'unref arg' compiler warning */
-
- memset(hdr, 0, 128);
- hdr [ 0] = 0x0a; /* Magic # */
- hdr [ 1] = 5; /* Version 5 */
- hdr [ 2] = 1; /* RLE compression */
- hdr [ 3] = (byte) ( ( gbm -> bpp == 24 ) ? 8 : gbm -> bpp );
- /* Bits per plane */
- hdr [ 4] = low_byte(0);
- hdr [ 5] = high_byte(0); /* Top left x */
- hdr [ 6] = low_byte(0);
- hdr [ 7] = high_byte(0); /* Top left y */
- hdr [ 8] = low_byte(gbm -> w - 1);
- hdr [ 9] = high_byte(gbm -> w - 1); /* Bottom right x */
- hdr [10] = low_byte(gbm -> h - 1);
- hdr [11] = high_byte(gbm -> h - 1); /* Bottom right y */
- hdr [12] = low_byte(0);
- hdr [13] = high_byte(0); /* Horizontal resolution ??? */
- hdr [14] = low_byte(0);
- hdr [15] = high_byte(0); /* Vertical resolution ??? */
-
- if ( gbm -> bpp == 4 )
- for ( i = 0; i < 16; i++ )
- {
- hdr [16 + i * 3 ] = gbmrgb [i].r;
- hdr [16 + i * 3 + 1] = gbmrgb [i].g;
- hdr [16 + i * 3 + 2] = gbmrgb [i].b;
- }
-
- hdr [65] = (byte) ( ( gbm -> bpp == 24 ) ? 3 : 1 );
- /* Planes */
- bytes_per_line = (gbm -> w * hdr [3] + 7) / 8;
- if ( bytes_per_line & 1 )
- bytes_per_line++;
- hdr [66] = low_byte(bytes_per_line);
- hdr [67] = high_byte(bytes_per_line);
- hdr [68] = 1; /* Colour or b/w */
-
- write(fd, hdr, 128);
-
- if ( (line = malloc(bytes_per_line * 2)) == NULL )
- return ( GBM_ERR_MEM );
-
- switch ( gbm -> bpp )
- {
- /*...s1\44\4\44\8:16:*/
- case 1:
- case 4:
- case 8:
- for ( y = gbm -> h - 1; y >= 0; y-- )
- {
- pcx_rle(data + y * stride, bytes_per_line, line, &cnt);
- if ( write(fd, line, cnt) != cnt )
- {
- free(line);
- return ( GBM_ERR_WRITE );
- }
- }
- break;
- /*...e*/
- /*...s24:16:*/
- case 24:
- {
- byte *line2;
- int p, x;
-
- if ( (line2 = malloc(bytes_per_line)) == NULL )
- {
- free(line);
- return ( GBM_ERR_MEM );
- }
-
- for ( y = gbm -> h - 1; y >= 0; y-- )
- for ( p = 2; p >= 0; p-- )
- {
- byte *src = data + y * stride;
-
- for ( x = 0; x < gbm -> w; x++ )
- line2 [x] = src [x * 3 + p];
-
- pcx_rle(line2, bytes_per_line, line, &cnt);
- if ( write(fd, line, cnt) != cnt )
- {
- free(line2);
- free(line);
- return ( GBM_ERR_WRITE );
- }
- }
- free(line2);
- }
- break;
- /*...e*/
- }
-
- free(line);
-
- if ( gbm -> bpp == 8 )
- {
- byte pal [1 + 0x100 * 3];
-
- pal [0] = 0x0c;
- for ( i = 0; i < 0x100; i++ )
- {
- pal [i * 3 + 1] = gbmrgb [i].r;
- pal [i * 3 + 2] = gbmrgb [i].g;
- pal [i * 3 + 3] = gbmrgb [i].b;
- }
- write(fd, pal, 1 + 0x100 * 3);
- }
-
- return ( GBM_ERR_OK );
- }
- /*...e*/
- /*...spcx_err:0:*/
- char *pcx_err(GBM_ERR rc)
- {
- switch ( (int) rc )
- {
- case GBM_ERR_PCX_BAD_VERSION:
- return ( "version number not 4 or 5" );
- case GBM_ERR_PCX_BAD_ENCMODE:
- return ( "encoding mode not 1" );
- case GBM_ERR_PCX_BAD_BITS:
- return ( "unsupported bpp/plane / plane combination" );
- case GBM_ERR_PCX_BAD_TRAILER:
- return ( "corrupt file trailer" );
- }
- return ( NULL );
- }
- /*...e*/
-