Category : Files from Magazines
Archive   : CUJ0894.ZIP
Filename : PCX.C

 
Output of file : PCX.C contained in archive : CUJ0894.ZIP
/***************************************************************
* file: PCX.C
* purpose: pcx monochrome reading/writing routines
* contains:
* copyright: 1994 by David Weber. All rights reserved.
* notes: Intel dependency in open_pcx_read()
* all file handles are from UNIX style open()
* image file format sticks with convention which is:
* 1 bit = black, 0 bit = white, bits 7 to 0 in byte go
* left to right in image.
* history:
* 06/03/92 - initial code - adapted from Paul Armstrong's original
* 04/4/94 - interface changed and simplified
**************************************************************/

#include
#include
#include
#include "pcx.h"


/* local functions */
static unsigned int read_source_buffer(void);
static unsigned int write_dest_buffer(void);


/* pcx structure and defines */

#define PCX_HEADER_SIZE 128
#define PCX_HEADER_USED 72
#define MAX_PCX_ENC_LEN (63) /* maximum pcx run length */
#define PCX_MANUFACTURER 10 /* manufacturer's code */
#define PCX_RUN_LENGTH 1 /* encoding type */
#define PCX_8_BITS_PER_PIX 1 /* code for 8 bits per pixel */
#define DCX_ID 987654321L /* dcx id code */
#define PIXELS_PER_BYTE 8 /* what it sez */

typedef struct
{
unsigned char manuf; /* always 10 decimal */
unsigned char hardvers; /* version */
unsigned char pcxencodmode; /* 1 if run length encoding */
unsigned char bitsppix; /* bits per pixel, 1 in our case */
unsigned int x1; /* window */
unsigned int y1;
unsigned int x2;
unsigned int y2;
unsigned int hres; /* card horizontal res. */
unsigned int vres; /* card vertical res. */
unsigned char clrpa[16][3]; /* palette info */
unsigned char vmode; /* ignored, should be 0 */
unsigned char nplanes; /* number of planes */
unsigned int bplin; /* bytes per line */
unsigned int page_start;
unsigned int page_length; /* page length in pixels */
unsigned char reserved[PCX_HEADER_SIZE-PCX_HEADER_USED];
} PCX_HEADER;


/* macros for accessing buffer */
#define bget() \
((src_bytes < src_size) ? *(src_file_buffer+(src_bytes++)) : \
((read_source_buffer() == IO_ERROR) ? (IO_ERROR) : \
(*(src_file_buffer+(src_bytes++)))))

#define bput(c) \
((*(dest_file_buffer+(dest_bytes++))=(unsigned char)(c)),(count++), \
((dest_bytes >= dest_size) ? (write_dest_buffer()) : 0))


/* read PCX local data */
static int src_handle; /* file handle for input file */
static unsigned char *src_file_buffer; /* source file buffer pointer */
static unsigned int src_max_size; /* maximum size of the source buffer */
static unsigned int src_bytes,src_size; /* source buffer usage */


/* write PCX local data */
static int dest_handle; /* file handle for output files */
static unsigned char *dest_file_buffer; /* destination file buffer pointer */
static unsigned int dest_bytes,dest_size; /* destination buffer usage */
static unsigned int dest_bytes_per_line; /* bytes in a destination scan line */
static unsigned int dest_length; /* length of destination page in scanlines */
static PCX_HEADER pcx_default_header =
{
PCX_MANUFACTURER, /* manuf; always 10 decimal */
5, /* hardvers; version */
PCX_RUN_LENGTH, /* pcxencodmode; 1 if run length encoding */
PCX_8_BITS_PER_PIX, /* bitsppix; */
0, /* x1; */
0, /* y1; */
0, /* x2; filled by put_pcx_header */
0, /* y2; filled by put_pcx_trailer */
0, /* hres; horizontal res. is unknown */
0, /* vres; vertical res. is unknown */
{ /* clrpa[16][3]; palette info, monochrome */
{0x00,0x00,0x00},{0xff,0xff,0xff},{0xff,0xff,0xff},{0xff,0xff,0xff},
{0xff,0xff,0xff},{0xff,0xff,0xff},{0xff,0xff,0xff},{0xff,0xff,0xff},
{0xff,0xff,0xff},{0xff,0xff,0xff},{0xff,0xff,0xff},{0xff,0xff,0xff},
{0xff,0xff,0xff},{0xff,0xff,0xff},{0xff,0xff,0xff},{0xff,0xff,0xff}
},
0, /* vmode; ignored, should be 0 */
1, /* nplanes; number or planes */
0, /* bplin; bytes per line, filled by put_pcx_header */
0, /* always 0 */
0, /* filled by put_pcx_trailer */
{ 0 } /* reserved, set to 0 */
};


/* read PCX functions */
/************************************************
* function: int open_pcx_read(int file_handle,unsigned char *buffer,unsigned int buffer_size,unsigned int *bytes_per_line)
* read the PCX header and decode it.
* parameters: handle of opened source file, file i/o buffer, size of buffer
* pointer to unsigned int filled with bytes per line
* returns: 1 if success or 0 if error
************************************************/
int open_pcx_read(int file_handle,unsigned char *buffer,unsigned int buffer_size,unsigned int *bytes_per_line)
{
PCX_HEADER header;
long *l;

src_handle = file_handle;
src_max_size = buffer_size;
if (read(src_handle,(void *) &header,sizeof(header)) != sizeof(header))
return 0; /* read header */
l = (long *) &header;
if (*l == DCX_ID) /* see if DCX, note Intel code */
{
if (lseek(src_handle,*(++l),SEEK_SET) == -1) /* move to PCX header */
return 0;
if (read(src_handle,(void *) &header,sizeof(header)) != sizeof(header))
return 0; /* and read it */
}
if (header.manuf!=PCX_MANUFACTURER || header.pcxencodmode!=PCX_RUN_LENGTH ||
header.bitsppix!=PCX_8_BITS_PER_PIX || header.nplanes != 1 ||
header.x1>header.x2 || header.y1>header.y2)
{ /* only stuff we will digest */
return 0;
}
*bytes_per_line = header.bplin; /* decode header */
src_bytes = src_size = src_max_size; /* preset buffer variables for later read */
src_file_buffer = buffer;
return 1; /* page length is unreliable so do it on the fly */
}


/************************************************
* function: unsigned int read_pcx(unsigned char *buffer,unsigned int number_of_bytes)
* decode a requested number of bytes of PCX data into the buffer
* parameters: buffer to decode lines to and the number of bytes to read.
* returns: size put into buffer if OK or IO_ERROR if failed. A returned
* count less than number_of_bytes means an EOF
************************************************/
unsigned int read_pcx(unsigned char *buffer,unsigned int number_of_bytes)
{
unsigned int count,byt,cnt;

count = 0;
while (count < number_of_bytes) /* until we hit the end */
{
if ((byt = bget()) == IO_ERROR) /* get a byte */
return count;
if ((byt & 0xc0) == 0xc0) /* if upper two bits are 1 */
{
cnt = 0x3f & byt;
if ((byt = bget()) == IO_ERROR) /* get run length */
return IO_ERROR;
memset(buffer+count,~byt & 0xff,cnt); /* and spit it out */
}
else /* otherwise a single byte */
{
cnt = 1;
*(buffer+count) = ~byt & 0xff;
}
count += cnt;
}
return count; /* actual number of bytes in buffer */
}


/************************************************
* function: int close_pcx_read(void)
* Null function included for symmetry with other
* graphics file converters
* parameters: none

* returns: 1 for Ok
************************************************/
int close_pcx_read(void)
{
return 1;
}


/************************************************
* function: unsigned int read_source_buffer(void)
* read a buffer full from the source file
* parameters: none
* returns: size read if OK or IO_ERROR if EOF/ERROR
************************************************/
static unsigned int read_source_buffer(void)
{
src_bytes = 0;
src_size = read(src_handle,src_file_buffer,src_max_size);
if (src_size == IO_ERROR || src_size == 0)
return IO_ERROR;
return src_size;
}


/* write PCX functions */
/************************************************
* function: int open_pcx_write(int file_handle,unsigned char *buffer,unsigned int buffer_size,unsigned int bytes_per_line)
* write out a preliminary header (updated when closed) and preset the variables
* and counters.
* parameters: handle of opened destination file, file i/o buffer, size of buffer,
* destination bytes per line
* returns: 1 if success or 0 if error
************************************************/
int open_pcx_write(int file_handle,unsigned char *buffer,unsigned int buffer_size,unsigned int bytes_per_line)
{
dest_bytes_per_line = bytes_per_line; /* set up local variables */
dest_handle = file_handle;
dest_file_buffer = buffer;
dest_size = buffer_size;
dest_length = 0;
dest_bytes = 0; /* preset buffer counter */
pcx_default_header.bplin = dest_bytes_per_line; /* output preliminary PCX header */
pcx_default_header.x2 = dest_bytes_per_line * PIXELS_PER_BYTE - 1;
if (write(dest_handle,(void *) &pcx_default_header,sizeof(pcx_default_header)) != sizeof(pcx_default_header))
return 0;
return 1;
}


/************************************************
* function: unsigned int write_pcx(unsigned char *buffer,unsigned int number_of_bytes)
* encode a buffer of data as PCX.
* although ZSoft PCX doesn't require run lengths to end exactly
* on scan lines, everybody does it. So the number_of_bytes in the
* buffer should be a multiple of the dest_bytes_per_line.
* parameters: buffer to write lines from and the number of bytes to write.
* returns: size written if OK or IO_ERROR if failed
************************************************/
unsigned int write_pcx(unsigned char *buffer,unsigned int number_of_bytes)
{
unsigned int number_of_lines,count;
unsigned int i;
unsigned int byt,runlen;

number_of_lines = number_of_bytes/dest_bytes_per_line; /* lines in buffer */
dest_length += number_of_lines;
count = 0; /* incremented in bput() */
while (number_of_lines) /* for each line */
{
i = 0;
while (i < dest_bytes_per_line) /* for a single line */
{
byt = *(buffer+i);
for (i++, runlen = 1 ; ; runlen++, i++) /* scan run length */
if (*(buffer+i) != byt || runlen >= MAX_PCX_ENC_LEN || i >= dest_bytes_per_line)
break;
byt = (~byt) & 0xff;
if (runlen == 1 && ((byt & 0xc0) != 0xc0))
{ /* single byte */
if (bput(byt) == IO_ERROR)
return IO_ERROR;
}
else
{ /* run length encoded */
if (bput(runlen|0xc0) == IO_ERROR)
return IO_ERROR;
if (bput(byt) == IO_ERROR)
return IO_ERROR;
}
}
number_of_lines--; /* next line */
buffer += dest_bytes_per_line;
}
return count; /* bytes written */
}


/************************************************
* function: int close_pcx_write(void)
* flush buffer and update header with length of page
* parameters: none
* returns: 1 if success or 0 if error
************************************************/
int close_pcx_write(void)
{
if (write_dest_buffer() == IO_ERROR) /* flush buffer */
return 0;
if (lseek(dest_handle,0L,SEEK_SET) == -1) /* update header */
return 0;
pcx_default_header.page_length = dest_length;
pcx_default_header.y2 = dest_length - 1;
if (write(dest_handle,(void *) &pcx_default_header,sizeof(pcx_default_header)) != sizeof(pcx_default_header))
return 0;
return 1;
}


/************************************************
* function: unsigned int write_dest_buffer(void)
* write out the bytes in the destination file buffer
* parameters: none
* returns: amount written if OK or IO_ERROR if ERROR
************************************************/
static unsigned int write_dest_buffer(void)
{

unsigned int i;

if (dest_bytes == 0)
return 0;
i = write(dest_handle,dest_file_buffer,dest_bytes);
if (i != dest_bytes)
return IO_ERROR;
dest_bytes = 0;
return i;
}


  3 Responses to “Category : Files from Magazines
Archive   : CUJ0894.ZIP
Filename : PCX.C

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/