home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
rexx
/
library2
/
gbmrexx
/
gbm
/
gbmpcx.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-09-12
|
12KB
|
576 lines
/*
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*/