home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Photo CD Demo 1
/
Demo.bin
/
fbm
/
src
/
flpcx.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-06-24
|
14KB
|
459 lines
/*****************************************************************
* flpcx.c: FBM Release 1.0 25-Feb-90 Michael Mauldin
*
* Copyright (C) 1989,1990 by Michael Mauldin. Permission is granted
* to use this file in whole or in part for any purpose, educational,
* recreational or commercial, provided that this copyright notice
* is retained unchanged. This software is available to all free of
* charge by anonymous FTP and in the UUNET archives.
*
* flpcx.c:
*
* CONTENTS
* write_pcx (image, stream)
* read_pcx (image, stream, mstr, mlen)
*
* EDITLOG
* LastEditDate = Mon Jun 25 00:17:11 1990 - Michael Mauldin
* LastFileName = /usr2/mlm/src/misc/fbm/flpcx.c
*
* HISTORY
* 25-Jun-90 Michael Mauldin (mlm@cs.cmu.edu) Carnegie Mellon
* Package for Release 1.0
*
* 03-Jan-90 Michael Mauldin (mlm) at Carnegie Mellon University
* Added write_pcx, fixed bugs with read_pcx
* Beta release (version 0.97) mlm@cs.cmu.edu
*
* 12-Nov-88 Michael Mauldin (mlm) at Carnegie-Mellon University
* Created.
*****************************************************************/
# include <stdio.h>
# include <math.h>
# include <ctype.h>
# include "fbm.h"
/****************************************************************
* pcx.h: Paintbrush file format header, as per "ZSoft Technical
* Reference Manual for Publisher's Paintbrush, PC Paintbrush Plus,
* PC Paintbrush and Frieze Graphics.", 1988, ZSoft corporation,
*
* 450 Franklin Rd. Suite 100 / Marietta, GA 30067 / 404-428-0008
*
* HISTORY
* {1} 1-Sep-87 Michael L. Mauldin (mlm) at cognac
* Created.
*
****************************************************************/
# define UBYTE unsigned char /* 8 bits unsigned */
# define WORD short /* 16 bits signed */
typedef struct pcxstruct {
UBYTE Manufacturer; /* 10 == ZSoft PCX */
UBYTE Version; /* Version Information */
/* 0 == ver 2.5 */
/* 2 == ver 2.8 w/pallete */
/* 3 == 2.8 w/o pallete */
/* 5 == ver 3.0 w/pallete */
UBYTE Encoding; /* 01 == PCX run-length encoding */
UBYTE BitsPerPixel; /* 8/number of pixels per byte */
WORD Window[4]; /* xmin, ymin, xmax, ymax */
WORD Hres; /* Horizontal resolution */
WORD Vres; /* Vertical resolution */
UBYTE Colormap[16][3]; /* Color Pallete, RGB in 0..255 */
UBYTE Reserved; /* Reserved */
UBYTE NPlanes; /* Number of Color Planes */
WORD BytesPerLine; /* Number of bytes per scan line */
WORD Palette; /* 1 = color/BW, 2 = grayscale */
UBYTE Filler[58]; /* Pad header to 128 bytes */
} PCXHDR;
# define XMIN 0
# define YMIN 1
# define XMAX 2
# define YMAX 3
# define CNTMSK 0xc0
# define MAXCNT 0x3f
# define swapword(X) ((((X)&0xff) << 8) | (((X) & 0xff00) >> 8))
/****************************************************************
* write_pcx: Write PC Paintbrush format
****************************************************************/
#ifndef lint
static char *fbmid =
"$FBM flpcx.c <1.0> 25-Jun-90 (C) 1989,1990 by Michael Mauldin, source \
code available free from MLM@CS.CMU.EDU and from UUNET archives$";
#endif
write_pcx (image, stream)
FBM *image;
FILE *stream;
{ register unsigned char *line = NULL, *bmp;
register int r, c, i, word, width, height;
int rowlen;
PCXHDR phdr;
width = image->hdr.cols;
height = image->hdr.rows;
if (image->hdr.bits != 1)
{ fprintf (stderr, "write_pcx: can't handle %d bits per pixel\n", image->hdr.bits);
return (0);
}
if (image->hdr.physbits != 8)
{ fprintf (stderr, "write_pcx: can't handle %d bits per pixel\n", image->hdr.physbits);
return (0);
}
rowlen = (width + 7) / 8;
line = (unsigned char *) malloc ((unsigned) rowlen);
/* Initialize the PCX header */
phdr.Manufacturer = 10; /* 10 == ZSoft PCX */
phdr.Version = 3; /* ver 2.8 with pallette */
phdr.Encoding = 1; /* 1 == PCX run-length encoding */
phdr.BitsPerPixel = 1; /* 8/number of pixels per byte */
phdr.Window[0] = 1; /* xmin */
phdr.Window[1] = 1; /* ymin */
phdr.Window[2] = width; /* xmax */
phdr.Window[3] = height; /* ymax */
phdr.Hres = 300; /* Horizontal resolution (300 dpi) */
phdr.Vres = 300 * image->hdr.aspect; /* Vertical resolution */
/* Clear out the color map */
for (c=0; c<16; c++)
for (r=0; r<3; r++)
phdr.Colormap[c][r] = 0;
phdr.Reserved = 0; /* Reserved */
phdr.NPlanes = 1; /* Number of Color Planes */
phdr.BytesPerLine = rowlen; /* Number of bytes per scan line */
phdr.Palette = 0; /* 0=bw, 1=color, 2==grey */
/* Clear filler */
for (c=0; c<58; c++) phdr.Filler[c] = 0;
/* PCX uses Little Indian byte order, swap on SUNS, RTs, ... */
if (machine_byte_order () == BIG)
{ phdr.Window[0] = swapword (phdr.Window[0]);
phdr.Window[1] = swapword (phdr.Window[1]);
phdr.Window[2] = swapword (phdr.Window[2]);
phdr.Window[3] = swapword (phdr.Window[3]);
phdr.Hres = swapword (phdr.Hres);
phdr.Vres = swapword (phdr.Vres);
phdr.BytesPerLine = swapword (phdr.BytesPerLine);
phdr.Palette = swapword (phdr.Palette);
}
/* Write out header */
fwrite ((char *) &phdr, sizeof (phdr), 1, stream);
/* For each scan line */
for (r=0; r<height; r++)
{
/* bmp points to scan line in memory in FBM format */
bmp = &(image->bm[r * image->hdr.rowlen]);
/* Pack bits into a row of 8 bits per byte, then call writepcxrow */
for (i=0; i<rowlen; i++)
{ word = 0;
for (c=0; c<8; c++)
{ word <<= 1;
word |= *bmp++ ? 1 : 0;
}
line[i] = word;
}
writepcxrow (line, rowlen, stream);
}
free ((char *) line);
return (1);
}
/****************************************************************
* Writepcxrow
****************************************************************/
# define CNTMSK 0xc0
# define MAXCNT 0x3f
writepcxrow (row, len, stream)
UBYTE *row;
FILE *stream;
{ register int cnt, byte;
cnt=1;
byte = *row++;
len--;
while (len > 0 || cnt > 0)
{ if (len > 0 && cnt < MAXCNT && *row == byte)
{ cnt++; row++; len--; }
else
{ if (cnt > 1 || (byte & CNTMSK) == CNTMSK)
{ fputc (CNTMSK | cnt, stream);
fputc (byte, stream);
}
else if (cnt == 1)
{ fputc (byte, stream); }
cnt=0;
if (len > 0)
{ byte = *row++; cnt++; len--; }
}
}
}
/****************************************************************
* read_pcx: Read PC Paintbrush format
****************************************************************/
read_pcx (image, rfile, mstr, mlen)
FBM *image;
FILE *rfile;
char *mstr;
int mlen;
{ PCXHDR phdr;
char *hp;
register unsigned char *bmp;
register int k, r, c, bit, byte, mask, width, height, rowlen;
int depth, ptype, color, enc, clrlen, totalbytes;
unsigned char *buf, *tail;
/* Read PCX file header */
hp = (char *) &phdr;
if (mlen > 0) strncpy (hp, mstr, mlen);
if (! fread ((char *) hp+mlen, sizeof (phdr) - mlen, 1, rfile))
{ perror ("read_fbm (header)"); return (0); }
if (phdr.Manufacturer != PCX_MAGIC)
{ fprintf (stderr,
"Error, file is not a PCX file, magic %02x is not 0a\n",
phdr.Manufacturer);
return (0);
}
/* PCX uses Little Indian byte order, swap on SUNS, RTs, ... */
if (machine_byte_order () == BIG)
{ phdr.Window[0] = swapword (phdr.Window[0]);
phdr.Window[1] = swapword (phdr.Window[1]);
phdr.Window[2] = swapword (phdr.Window[2]);
phdr.Window[3] = swapword (phdr.Window[3]);
phdr.Hres = swapword (phdr.Hres);
phdr.Vres = swapword (phdr.Vres);
phdr.BytesPerLine = swapword (phdr.BytesPerLine);
phdr.Palette = swapword (phdr.Palette);
}
# ifdef DEBUG
fprintf (stderr, "Manufacturer %d\n", phdr.Manufacturer);
fprintf (stderr, "Version %d\n", phdr.Version);
fprintf (stderr, "Encoding %d\n", phdr.Encoding);
fprintf (stderr, "BitsPerPixel %d\n", phdr.BitsPerPixel);
fprintf (stderr, "Window0 %d\n", phdr.Window[0]);
fprintf (stderr, "Window1 %d\n", phdr.Window[1]);
fprintf (stderr, "Window2 %d\n", phdr.Window[2]);
fprintf (stderr, "Window3 %d\n", phdr.Window[3]);
fprintf (stderr, "Hres %d\n", phdr.Hres);
fprintf (stderr, "Vres %d\n", phdr.Vres);
fprintf (stderr, "Reserved %d\n", phdr.Reserved);
fprintf (stderr, "NPlanes %d\n", phdr.NPlanes);
fprintf (stderr, "BytesPerLine %d\n", phdr.BytesPerLine);
fprintf (stderr, "Palette %d\n", phdr.Palette);
# endif
/* Now extract relevant features of PCX file header */
width = phdr.Window[XMAX] - phdr.Window[XMIN] + 1;
height = phdr.Window[YMAX] - phdr.Window[YMIN] + 1;
depth = phdr.NPlanes;
ptype = phdr.Version;
color = ((ptype == 2) || (ptype == 5)) &&
phdr.NPlanes > 1 &&
phdr.Palette != 2;
enc = phdr.Encoding;
if (phdr.BitsPerPixel != 1)
{ fprintf (stderr, "%s %d bits per pixel with %d planes\n",
"Error in PCX file, can't handle",
phdr.BitsPerPixel, depth);
return (0);
}
/* Initialize image header */
image->hdr.cols = width;
image->hdr.rows = height;
image->hdr.planes = 1;
image->hdr.bits = (color || depth > 1) ? 8 : 1;
image->hdr.physbits = 8;
image->hdr.rowlen = rowlen = 16 * ((width + 15) / 16);
image->hdr.plnlen = rowlen * height;
image->hdr.clrlen = clrlen = color ? (16 * 3) : 0;
image->hdr.aspect = 1.0;
image->hdr.title[0] = '\0';
image->hdr.credits[0] = '\0';
/* Describe what we are doing */
fprintf (stderr, "Reading PCX file [%dx%d]", width, height);
if (phdr.BitsPerPixel > 1)
fprintf (stderr, ", %d bits per pixel", phdr.BitsPerPixel);
if (depth > 1)
fprintf (stderr, ", %d planes", depth);
if (clrlen > 0)
fprintf (stderr, ", %d colors", clrlen/3);
fprintf (stderr, "\n");
/* Allocate space */
alloc_fbm (image);
/* Read colormap if need be */
if (clrlen > 0)
{ fprintf (stderr, "reading %d (really 16) colors\n", clrlen / 3);
for (c=0; c<16; c++)
{ image->cm[c] = phdr.Colormap[c][0];
image->cm[c+16] = phdr.Colormap[c][1];
image->cm[c+32] = phdr.Colormap[c][2];
}
}
/* Zero out the bits */
bmp = image->bm;
tail = bmp + image->hdr.plnlen;
while (bmp < tail) { *bmp++ = 0; }
/* Bytes per scan line */
totalbytes = depth * phdr.BytesPerLine;
buf = (unsigned char *) malloc ((unsigned) totalbytes);
/* Now read bits */
for (r=0; r<height; r++)
{ bmp = &(image->bm[r * rowlen]);
/* Read a scan line */
if (pcxline_read (enc, buf, totalbytes, rfile) == 0)
{ fprintf (stderr, "Premature EOF in row %d, totalbytes %d\n",
r, totalbytes);
free ((char *) buf);
return (1);
}
# ifdef MONDO_DEBUG
if (r == 211)
{ register int col = 0;
fprintf (stderr, "Row %d, %d bytes:", r, totalbytes);
for (c=0; c<totalbytes; c++)
{ if (col%32 == 0 || c%(width/8) == 0) { fprintf (stderr, "\n%3d:", c); col = 0; }
if (col++ %8 == 0) fprintf (stderr, " ");
fprintf (stderr, "%02x", buf[c]);
}
fprintf (stderr, "\n");
col = 0;
for (c=0; c<width; c++)
{ byte = c/8;
mask = 0x80 >> (c%8);
bit = ((buf[byte ] & mask) ? 1 : 0) |
((buf[byte+(width/8) ] & mask) ? 2 : 0) |
((buf[byte+2*(width/8)] & mask) ? 4 : 0) |
((buf[byte+3*(width/8)] & mask) ? 8 : 0);
if (col%50 == 0) { fprintf (stderr, "\n%3d:", c); col=0; }
if (col++%10 == 0) { fprintf (stderr, " ", c); }
fprintf (stderr, "%1x", bit);
}
fprintf (stderr, "\n");
}
# endif
/* Decode scan line into row of image */
if (depth == 1)
{ bmp = &(image->bm[r * rowlen]);
for (c=0; c<width; c++)
{ byte = c>>3;
mask = 0x80 >> (c&7);
*bmp++ = (buf[byte] & mask) ? WHITE : BLACK;
}
}
else
{ for (k=0; k<depth; k++)
{ bmp = &(image->bm[r * rowlen]);
bit = 1 << k;
for (c=0; c<width; c++)
{ byte = ((c + k*width)>>3);
mask = 0x80 >> (c&7);
*bmp++ |= (buf[byte] & mask) ? bit : 0;
}
}
}
}
if (depth > 1)
{ fprintf (stderr, "Read %d planes successfully\n", depth); }
free ((char *) buf);
return (1);
}
/****************************************************************
* encget (pbyt, pcnt, fid) Page 10 of ZSoft Manual
****************************************************************/
encget (pbyt, pcnt, fid)
int *pbyt; /* Where to place data */
int *pcnt; /* Where to place count */
FILE *fid; /* Image file stream */
{ register int i;
*pcnt = 1; /* Safety play */
if (EOF == (i = getc (fid))) return (EOF);
if (CNTMSK == (CNTMSK & i))
{ *pcnt = MAXCNT & i;
if (EOF == (i = getc (fid))) return (EOF);
}
*pbyt = i;
return (0);
}
/****************************************************************
* pcxline_read
****************************************************************/
pcxline_read (enc, buf, total, fid)
unsigned char *buf; /* Output buffer */
int total; /* Bytes in one scan line */
FILE *fid; /* Input stream */
{ int data, count, len=0;
if (enc != 1)
{ return (fread ((char *) buf, 1, total, fid)); }
while (len < total)
{ if (EOF == encget (&data, &count, fid))
return (len);
while (count > 0) { *buf++ = data; len++; count--; }
}
if (count > 0)
{ fprintf (stderr, "%s, after %d bytes, lost %d bytes of %02x\n",
"Error in reading scan lines", total, count, data);
}
return (len);
}