/***************************************************************** * 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 # include # include # 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; rbm[r * image->hdr.rowlen]); /* Pack bits into a row of 8 bits per byte, then call writepcxrow */ for (i=0; i 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; rbm[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> (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>3; mask = 0x80 >> (c&7); *bmp++ = (buf[byte] & mask) ? WHITE : BLACK; } } else { for (k=0; kbm[r * rowlen]); bit = 1 << k; for (c=0; c>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); }