home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mega CD-ROM 1
/
megacd_rom_1.zip
/
megacd_rom_1
/
MAGAZINE
/
DDJMAG
/
DDJ8908.ZIP
/
QUIRK.LST
< prev
next >
Wrap
File List
|
1989-07-06
|
15KB
|
502 lines
TRANSLATING PCX FILES
by Kent Quirk
[LISTING ONE]
/*+
Name: pcx.c
Author: Kent J. Quirk
Abstract: This file contains subroutines to read PCX files.
-*/
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include "pcx.h"
/**** p c x _ r e a d _ h e a d e r ****
Abstract: Reads the header of a PCX file.
Parameters: A data storage area for the header, an open file.
Returns: The pointer to the data storage area passed, or NULL if error.
Comments: The file should be opened in binary mode.
****************************/
PCX_HDR *pcx_read_header(PCX_HDR *hdr, FILE *f)
{
fseek(f, 0L, SEEK_SET); /* header is at top of file */
if (fread(hdr, 1, sizeof(PCX_HDR), f) != sizeof(PCX_HDR))
return(NULL);
else
return(hdr);
}
/**** p c x _ p r i n t _ h e a d e r ****
Abstract: Printf's a PCX file header data to a given file.
Parameters: The PCX file header, the file to write the data to.
Returns: Nothing
****************************/
void pcx_print_header(PCX_HDR *hdr, FILE *f)
{
char *t;
if (hdr->pcx_id != 0x0A)
{
fprintf(f, "Not a PCX file.\n");
return;
}
switch (hdr->version) {
case 0: t="2.5"; break;
case 2: t="2.8 with palette info."; break;
case 3: t="2.8 without palette info."; break;
case 5: t="3.0"; break;
default: t="unknown."; break;
}
fprintf(f, "PCX Version %s\n", t);
fprintf(f, "Compression: %s\n",
hdr->encoding==1 ? "Run length" : "Unknown");
fprintf(f, "%d bits per pixel\n", hdr->bpp);
fprintf(f, "Image from (%d, %d) to (%d, %d) pixels.\n",
hdr->upleftx, hdr->uplefty, hdr->lorightx, hdr->lorighty);
fprintf(f, "Created on a device with %d x %d dpi resolution.\n",
hdr->display_xres, hdr->display_yres);
fprintf(f, "The image contains %d image planes.\n", hdr->nplanes);
fprintf(f, "There are %d bytes per line of data after decompression.\n",
hdr->bytesperline);
fprintf(f, "There are %ld total bytes in the image.\n",
((long)hdr->lorighty - (long)hdr->uplefty + 1) *
(long)hdr->bytesperline);
return;
}
/**** p c x _ a l l o c _ l i n e ****
Abstract: Allocates enough space to store a complete scan line from the
current PCX file.
Parameters: The header pointer.
Returns: A pointer to a "big enough" block of allocated space, or
null if not enough space or an error occurred.
****************************/
BYTE *pcx_alloc_line(PCX_HDR *hdr)
{
return(calloc(hdr->nplanes, hdr->bytesperline));
}
/**** p c x _ n e x t _ l i n e ****
Abstract: Reads the next line from the PCX file.
Parameters: Pointer to the header, a pointer to the line area (or NULL
for automatic allocation), and the open data file.
Returns: A pointer to the line area, or NULL if there was a problem.
Comments: To read the first line, call pcx_read_header() first.
This sets the file position to the beginning of the data.
****************************/
BYTE *pcx_next_line(PCX_HDR *hdr, BYTE *line, FILE *f)
{
int c, len;
BYTE *dp;
WORD linesize = hdr->nplanes * hdr->bytesperline;
WORD i;
if (line == NULL)
if ((line = pcx_alloc_line(hdr)) == NULL)
return(line);
dp = line; /* point to data */
for (i=0; i<linesize; )
{
if ((c = fgetc(f)) == EOF)
return(NULL);
if ((c & PCX_COMPRESSED) == PCX_COMPRESSED)
{
len = (c & PCX_MASK);
if ((c = fgetc(f)) == EOF)
return(NULL);
memset(dp, (BYTE)c, len);
dp += len;
i += len;
}
else
{
*dp++ = (BYTE)c;
i++;
}
}
return(line);
}
[LISTING TWO]
/*+
Name: pcx.h
Author: Kent J. Quirk
Abstract: This file contains information required when handling
PCX files.
-*/
/********************
Need these to handle the PCX data below.
*********************/
typedef unsigned char BYTE;
typedef unsigned int WORD;
/********************
This is the definition of the PCX header.
*********************/
typedef struct {
BYTE pcx_id; /* Always 0x0A for PCX files */
BYTE version; /* Version of the PCX format */
BYTE encoding; /* 1 = RLE (RLL) compression */
BYTE bpp; /* Number of bits per pixel */
WORD upleftx, uplefty; /* position of upper left corner */
WORD lorightx, lorighty; /* lower right corner (inclusive) */
WORD display_xres, display_yres; /* resolution in dpi of display */
BYTE palette[48]; /* palette data if it fits */
BYTE reserved;
BYTE nplanes; /* number of bit planes of data */
WORD bytesperline; /* # bytes in an uncompressed line */
WORD palletteinfo;
BYTE reserved2[58];
} PCX_HDR;
/********************
These two definitions are used to decompress data in the PCX file.
(The compressed count byte has the top two bits set).
*********************/
#define PCX_COMPRESSED 0xC0
#define PCX_MASK 0x3F
/********************
These prototypes declare the PCX read subroutines.
*********************/
PCX_HDR *pcx_read_header(PCX_HDR *hdr, FILE *f);
BYTE *pcx_alloc_line(PCX_HDR *hdr);
BYTE *pcx_next_line(PCX_HDR *hdr, BYTE *line, FILE *f);
void pcx_print_header(PCX_HDR *hdr, FILE *f);
[LISTING THREE]
/*+
Name: prpcx.c
Author: Kent J. Quirk
Abstract: This program prints .PCX files (as created by PC Paintbrush
and other software) on a PostScript printer by converting
them to a PS-compatible image. The user can scale and
position the image.
-*/
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <string.h>
#define BUFSIZE 100
#include "pcx.h"
typedef struct {
int xpos;
int ypos;
int width;
int height;
int scale;
int invert;
int prt_res;
int dumphdr;
} MAPPING;
/**** c o p y _ p s _ h e a d e r ****
Abstract: Opens the PS header file and copies it to the output.
Parameters: Filename of the current file (the .PS extension is added
here) and the output file pointer.
Returns: 0 if successful, 1 if failure.
****************************/
char *copy_ps_header(char *name, FILE *outfile, char *stop)
{
static char buf[BUFSIZE];
char *bp;
static FILE *f = NULL;
if (f == NULL)
{
strcpy(buf, name);
if ((bp = strchr(buf, '.')) != NULL)
*bp = 0;
strcat(buf, ".ps"); /* open file with this name but .ps ext */
if ((f = fopen(buf, "r")) == NULL)
{
fprintf(stderr, "Unable to open PostScript header file '%s'\n",
buf);
return(NULL);
}
}
else
{
fputs(buf, outfile);
}
while (fgets(buf, BUFSIZE, f) != NULL)
{
if ((stop != NULL) && (strncmp(buf, stop, strlen(stop)) == 0))
return(buf); /* bail out right now */
fputs(buf, outfile);
}
fclose(f);
f = NULL;
return(NULL);
}
/**** d o f i l e ****
Abstract: Processes a single PCX file.
Parameters: char *filename - the input PCX filename (.PCX optional)
MAPPING *map - the structure containing page position info
char *psname - the PostScript prologue (.PS will be forced)
FILE *outfile - the open output file
Returns: 0 if successful, 1 if no file generated
****************************/
int dofile(char *filename, MAPPING *map, char *psname, FILE *outfile)
{
FILE *f;
PCX_HDR hdr;
WORD i, j, xsize, ysize;
BYTE *lineptr = NULL;
char *t;
char buf[BUFSIZE];
long bbox_x, bbox_y;
strcpy(buf, filename);
if (strchr(buf, '.') == NULL)
strcat(buf, ".pcx"); /* add .PCX if needed */
if ((f = fopen(buf, "rb")) == NULL)
{
fprintf(stderr, "Unable to open '%s'\n", buf);
return(1);
}
if (pcx_read_header(&hdr, f) == NULL)
{
fprintf(stderr, "Unable to read header for file '%s'.\n", buf);
fclose(f);
return(1);
}
if (map->dumphdr)
{
pcx_print_header(&hdr, stdout);
return(1);
}
if (hdr.nplanes != 1)
{
fprintf(stderr, "Only able to read monochrome .PCX files.\n");
fclose(f);
return(1);
}
xsize = hdr.lorightx - hdr.upleftx + 1;
ysize = hdr.lorighty - hdr.uplefty + 1;
t = copy_ps_header(psname, outfile, "%%BoundingBox");
bbox_x = (long)xsize * (long)map->width * (long)map->scale / 10000L;
bbox_y = (long)ysize * (long)map->height * (long)map->scale / 10000L;
bbox_x += map->xpos;
bbox_y += map->ypos;
sprintf(t, "%%%%BoundingBox: %d %d %ld %ld\n", map->xpos, map->ypos,
bbox_x, bbox_y);
t = copy_ps_header(psname, outfile, NULL);
fprintf(outfile, "/bmap_wid %d def\n", xsize);
fprintf(outfile, "/bmap_hgt %d def\n", ysize);
fprintf(outfile, "/bpp %d def\n", hdr.bpp);
fprintf(outfile, "/res %d def\n\n", map->prt_res);
fprintf(outfile, "/x %d def\n", map->xpos);
fprintf(outfile, "/y %d def\n\n", map->ypos);
fprintf(outfile, "/scy %d 100 div def\n", map->height);
fprintf(outfile, "/scx %d 100 div def\n", map->width);
fprintf(outfile, "/scg %d 100 div def\n\n", map->scale);
fprintf(outfile, "scaleit\n");
fprintf(outfile, "imagedata\n\n");
for (i=0; i<ysize; i++)
{
lineptr = pcx_next_line(&hdr, lineptr, f);
if (map->invert) /* invert if necessary */
for (j=0; j < xsize/8; j++)
lineptr[j] = ~lineptr[j];
for (j=0; j < xsize/8; j++)
fprintf(outfile, "%02X", lineptr[j]);
fprintf(outfile, "\n");
}
fprintf(outfile, "\nshowit\n");
free(lineptr);
fclose(f);
return(0);
}
/**** u s a g e ****
Abstract: Prints a usage message and dies.
Parameters: None
Returns: Never returns.
****************************/
void usage()
{
printf("PRPCX: by Kent Quirk\n");
printf(" Given a .PCX file, this program creates a PostScript file \n");
printf(" which will print the image.\n");
printf(" PRPCX [-wW] [-hH] [-xX] [-yY] [-sS] [-rR] [-d] [-i] filename\n");
printf(" Options include: (units) [default]\n");
printf(" -sSCA set overall scale factor (percent) [100]\n");
printf(" -wWID set horizontal scale factor (percent) [100]\n");
printf(" -hHGT set vertical scale factor (percent) [100]\n");
printf(" -xPOS set horizontal position (points from left) [0]\n");
printf(" -yPOS set vertical position (points from bottom) [0]\n");
printf(" -rRES set printer resolution (dpi) [300]\n");
printf(" -d dump PCX file info to stdout [off]\n");
printf(" -i invert image [off]\n");
printf(" -oFIL set output filename, or use SET PRPCX=filename\n");
printf(" The defaults print the image at one pixel per device pixel\n");
printf(" at the lower left corner of the page.\n");
printf(" PRPCX.PS must be in the same directory as PRPCX.EXE.\n");
exit(1);
}
/**** m a i n ****
The main routine for PRPCX. Sets defaults, parses command line,
and calls dofile().
****************************/
int main(int argc, char *argv[])
{
int i;
MAPPING map;
FILE *outfile = stdout;
char *outfname = NULL;
char *filename = NULL;
map.xpos = map.ypos = 0;
map.width = map.height = map.scale = 100;
map.invert = 0;
map.prt_res = 300;
map.dumphdr = 0;
if (argc < 2)
usage();
for (i=1; i<argc; i++)
{
if (argv[i][0] == '-' || argv[i][0] == '/')
{
switch (argv[i][1])
{
case 'x': case 'X':
map.xpos = atoi(argv[i]+2);
break;
case 'y': case 'Y':
map.ypos = atoi(argv[i]+2);
break;
case 'h': case 'H':
map.height = atoi(argv[i]+2);
break;
case 'w': case 'W':
map.width = atoi(argv[i]+2);
break;
case 's': case 'S':
map.scale = atoi(argv[i]+2);
break;
case 'r': case 'R':
map.prt_res = atoi(argv[i]+2);
break;
case 'i': case 'I':
map.invert = !map.invert;
break;
case 'd': case 'D':
map.dumphdr = 1;
break;
case 'o': case 'O':
outfname = argv[i]+2;
break;
case '?':
usage();
break;
default:
fprintf(stderr, "Unknown option %s\n", argv[i]);
usage();
break;
}
}
else /* process a file */
{
filename = argv[i];
}
}
if ((outfname != NULL) || ((outfname = getenv("PRPCX")) != NULL))
{
if ((outfile = fopen(outfname, "w")) == NULL)
{
fprintf(stderr,"Unable to open output file %s", outfname);
exit(1);
}
}
i = dofile(filename, &map, argv[0], outfile);
fclose(outfile);
return(i);
}
[LISTING FOUR]
#
# Program: PRPCX
#
.c.obj:
cl -c -W2 -Zid -Od -AS $*.c
pcx.obj : pcx.c pcx.h
prpcx.obj : prpcx.c pcx.h
prpcx.exe : prpcx.obj pcx.obj
echo prpcx.obj+ >prpcx.lnk
echo pcx.obj >>prpcx.lnk
echo prpcx.exe >>prpcx.lnk
echo nul >>prpcx.lnk
link /NOI $(LDFLAGS) @prpcx.lnk;
[LISTING FIVE]
%!PS-Adobe 1.0
%%Title:
%%Creator:
%%Pages: 1
%%BoundingBox:
%%EndComments
gsave
% the next item translates the image from
% top-to-bottom .PCX format to PS bottom-to-top
/xform
{
[ bmap_wid 0 0 bmap_hgt neg 0 bmap_hgt ]
} def
/readproc
{
{ currentfile picstr readhexstring pop }
} def
/scaleit
{
x y translate
bmap_wid bmap_hgt scale
72 res div 72 res div scale
scx scg mul scy scg mul scale
/picstr bmap_wid 8 idiv string def
} def
/imagedata
{
bmap_wid bmap_hgt bpp xform readproc image
} def
/showit
{
grestore
showpage
} def
% Will generate <bmap_hgt> lines of image data,
% each with <bmap_wid>/8 bytes of data (in hex).
%%EndProlog