Path: utzoo!attcan!uunet!lll-winken!ames!ncar!tank!shamash!com50!midgard!dal From: dal@midgard.Midgard.MN.ORG (Dale Schumacher) Newsgroups: comp.graphics Subject: Re: Extending PBM to handle Greyscale and Color images Summary: Here is the base library Message-ID: <610@midgard.Midgard.MN.ORG> Date: 26 Jan 89 07:13:45 GMT References: <589@midgard.Midgard.MN.ORG> Reply-To: dal@syntel.UUCP (Dale Schumacher) Organization: The Midgard Realm, St Paul MN Lines: 1671 Well, I had some last minute trouble with the compression code, but everything appears to be working now, so here (for your amusement :-) is the PXM library. Feedback to: or #----------------------------------cut here----------------------------------- #! /bin/sh # # This is a "shar" archive; to extract files from it, type the command # "sh sharfile" or "ksh sharfile". The "csh" shell will NOT work to extract # files. # # Wrapped by midgard!dal on Thu Jan 26 00:53:30 CST 1989. # # The contents of this archive are: # # -rw-r--r-- 1 dal users 1658 Jan 26 00:39 libpxm1.c # -rw-r--r-- 1 dal users 7391 Jan 26 00:41 libpxm2.c # -rw-r--r-- 1 dal users 7743 Jan 26 00:43 libpxm3.c # -rw-r--r-- 1 dal users 5280 Jan 26 00:45 libpxm6.c # -rw-r--r-- 1 dal users 12169 Jan 26 00:49 pxm.doc # -rw-r--r-- 1 dal users 3390 Jan 26 00:46 pxm.h # if test -f "pxm.doc"; then echo 'shar: will not overwrite "'pxm.doc'"' else echo 'shar: extracting "'pxm.doc'"' sed -e 's/^X//' << \@FOOBIE@BLETCH@ > "pxm.doc" X X Portable Pixmap (PXM) Image File Format X by Dale Schumacher X X X0. INTRODUCTION X In early December of 1988, Jef Poskanzer released the "Portable X Bitmap" source code to the comp.sources.misc newsgroup on Usenet. X This was a very useful format for exchange of images between X nearly any systems. Unfortunately, the format was limited to X 1-bit deep pixmaps (bitmaps) and thus only represented monochrome X on/off images. I've attempted to extend this concept to handle X greyscale images (up to 8-bits/pixel) and color images, both X colormapped and 24-bit RGB "true color". X X1. LIBRARY X The pxm library contains a core set of functions for manipulating X images in the pxm format. Use of these functions makes expression X of image manipulation algorithms much cleaner and simpler. The X storage mechanics are hidden in the library routines, which give X the image processing programs an idealized pixel-by-pixel, X scan-line-at-a-time or whole-image model for accessing images in X a variety of storage formats. The pbm library, from which the X pxm concepts are derived, had only to deal with images of different X dimensions, since all pbm's where simple bitmaps. The pxm library X handles 4 basic image types and 3 storage techniques in an X orthogonal way. As you will see, the original pbm is still handled X (though not the "compressed pbm") by the new pxm library, giving X a smooth upgrade path. X X 1.1 IMAGE TYPES. The 4 basic image types are monochrome (bitmaps), X greyscale, colormapped and truecolor. The monochrome type is a X simple bitmap, like the pbm format. One bit is allocated for each X pixel in the image. The greyscale format has the additional X dimension of "depth" in bits, with a maximum of 8. This allows X up to 256 greyscales, which is quite sufficient. The colormapped X format also has a "depth" dimension, allowing up to 16 bits per X pixel (which should be plenty), and the colormap gives 24-bit X RGB values for each of the colormap entries. The size of the X colormap is determined strictly by the depth of the image. The X final format, truecolor, has a fixed depth of 24 bits/pixel, since X each pixel in represented by a direct 24-bit RGB value. These X formats should cover any 2-d image with no loss of information. X X 1.2 STORAGE METHODS. The 3 storage methods are text, binary and X rle. The text method represents each pixel with an ascii printed X hexadecimal value. For all image types except monochrome, the X values MUST be whitespace separated, since they aren't known to X be exactly one digit. As with pbm's, the output is limited to X no more than 70 characters per line of text. The binary method X stores each pixel as a series of bytes (MSB to LSB). The bits X from consecutive pixels are not packed and the number of bytes X per pixel is strictly a function of the bits per pixel. The file X is read/written a byte at a time to avoid byte ordering problems X between machines. The rle method is also a binary method, ie. the X resulting file may contain non-printable characters. This method X first packs the bits of each pixel into consecutive bytes (msb to X lsb) and then encodes "runs" in the byte stream as a means of X compression. X X 1.3 THE PX_DEF STRUCTURE. Pictures attributes are stored in the X PX_DEF structure and passed to almost all pxm library functions. X This structure helps make the different picture types and storage X methods transparent to the application. The structure contains X a file pointer to the open file corresponding to the pixmap (unlike X the pbm functions, images are not always read entirely into memory X before processing), picture type/storage method, width, height, X depth, a colormap if needed, and various other precalculated values X and status variables. If you're curious, look at the actual X declaration in "pxm.h". X X 1.4 STORAGE ALLOCATION. In order to reduce the amount of memory X needed to process an image, the pxm routines don't load the image X into memory when it is opened. Various parts of the image structure X need to be allocated dynamically during processing. These functions X provide this allocation and include code to check for errors and X zero allocated storage (to simplify their use). X X 1.4.1 PX_BYTE *px_alloc(int size) X Allocate size byte of storage and zero fill. Like all X of the pxm allocation routines, if the allocation fails X the program is aborted with an error message, thus if X the function returns you are assured of having storage. X X 1.4.2 PX_BYTE *px_rowalloc(int width, int psize) X Allocate a row, width pixels wide, with psize bytes per X pixel. The bytes/pixel value is stored in the PX_DEF X structure px_psize field. X X 1.4.3 PX_BYTE **px_arrayalloc(int width, int height, int psize) X Allocate an image array of width by height pixels with X psize bytes per pixel. This can take a considerable X amount of memory and should only be used if the processing X algorithm requires more than a few scanlines at a time. X X 1.4.4 rgb *px_mapalloc(int colors) X Allocate a colormap with colors entries. The number of X colors is stored in the px_colors field of the PX_DEF. X X 1.5 IMAGE READING. Images may be process a single pixel at a time, X a few scanlines at a time, or all at once. The read functions X are used to open and incrementally read an image file. X X 1.5.1 PX_DEF *px_ropen(char *filename) X Open a picture file and load header information. This X function returns a pointer to a dynamically allocated X PX_DEF structure describing the image. Any errors X cause an appropriate error message and terminate the X program. X X 1.5.2 long px_rpixel(PX_DEF *px) X Read the next pixel from a picture. The pixel value is X always returned as a long value since it may be up to X 24 bits. The value range of the pixel is dependent on X the image type and number of bits per pixel. If you X need the raw pixel values (color index, for example) X rather than the ideal colors (explained in 1.7) you X should use this function. Otherwise the other functions X are much more efficient. X X 1.5.3 PX_BYTE *px_rrow(PX_DEF *px, PX_BYTE *rowbuf) X Read the next row of pixels from a picture into rowbuf. X The rowbuf is assumed to be the proper size (allocated by X px_rowalloc()). The rowbuf pointer is returned. X X 1.5.4 PX_BYTE **px_readpxm(PX_DEF *px) X Read an entire picture at once. This must be the first X (and only) read call after the picture is opened. The X pixel array is allocated automatically and becomes the X return value. X X 1.6 IMAGE WRITING. X X 1.6.1 PX_DEF *px_wopen(char *filename, int type, X int width, int height, int depth, rgb *colormap) X Open a picture file and write header information. This X function returns a pointer to a dynamically allocated X PX_DEF structure describing the image. The type value X is on of the picture type values PXT_BIT (monochrome X bitmap), PXT_PIX (greyscale pixmap), PXT_MAP (colormapped), X PXT_RGB (truecolor), logically ORed with one of the X storage methods PXT_TXT (ascii text), PXT_BIN (binary), X PXT_RLE (run-length encoded). The colormap value is X either NULL if there is no colormap, or a pointer to X an already allocated colormap. Any errors cause an X appropriate error message and terminate the program. X X 1.6.2 long px_wpixel(PX_DEF *px, long value) X Write the next pixel to a picture. The pixel value is X always a long, but only px_psize bytes will be stored X in the file. The value range of the pixel is dependent X on the image type and number of bits per pixel. If you X need to write raw pixel values (color index, for example) X rather than the ideal colors (explained in 1.7) you X should use this function. Otherwise the other functions X are much more efficient. X X 1.6.3 PX_BYTE *px_wrow(PX_DEF *px, PX_BYTE *rowbuf) X Write the next row of pixels to a picture from rowbuf. X The rowbuf is assumed to be the proper size (allocated by X px_rowalloc()). The rowbuf pointer is returned. X X 1.6.4 PX_BYTE **px_writepxm(PX_DEF *px, PX_BYTE **pixels) X Write an entire picture at once. This must be the first X (and only) write call after the picture is opened. The X pixel array must already exist and becomes the return value. X NOTE: The pixel array is NOT a simple rectangular array X of bytes. Please use px_arrayalloc() to allocate the array, X or use the array returned by px_readpxm(). X X 1.7 IDEAL PIXELS. In order to ease generalization of image X processing algorithms, the pxm library provides a set of routines X for dealing with "ideal" pixels. Regardless of which picture X type and storage method is used, these routines retrieve the X 8-bit greyscale or 24-bit color value of a pixel (depending on X which function you call). These routines are intended to be the X primary interface to the pixmap. They read/write pixels within X a row array, since there is nearly always enough memory for at X least one scanline of even a 24-bit color image. Conversion to X and from the ideal pixel form is handled internally by these X routines. Bitmaps return values of black (all zeros) or white X (all ones), note that to remain compatible with pbms, 'white' X is represented by '0' in the file, and 'black' by '1', but is X reversed when read as an ideal pixel. When writing bitmaps, any X non-zero pixel is 'white' and only all-zeros becomes 'black'. X For greyscale pixmaps, an 8-bit greyscale value is created, X either by scaling the given greyscale up to 8-bits, or by calc- X culating the luminence of the given color with the formula: X Luminence = 29.9% Red + 58.7% Green + 11.4% Blue. This is the X NTSC Y-component (luminence) of a Y-I-Q color value. Pixel X values for a colormapped image are looked up in the colormap X and then returned as RGB or computed greyscale. Truecolor is X handled similarly using the direct color. If RGB is requested X from a greyscale or monochrome image, the grey value is scaled X to 8-bits and assigned equally to each gun on the assumption X that equal portions of each gun gives a scale of neutral greys. X Several other pixel utility functions are also provided. X X 1.7.1 rgb px_rrgb(PX_DEF *px, PX_BYTE *rowbuf, int x) X Return the 24-bit RGB color value of the x'th pixel in X the rowbuf scanline. The PX_DEF px must be an open pixmap X descriptor. X X 1.7.2 rgb px_rgrey(PX_DEF *px, PX_BYTE *rowbuf, int x) X Return the 8-bit greyscale value of the x'th pixel in the X rowbuf scanline. The PX_DEF px must be an open pixmap X descriptor. X X 1.7.3 rgb px_wrgb(PX_DEF *px, PX_BYTE *rowbuf, int x, rgb value) X Return the 24-bit RGB color value of the x'th pixel in X the rowbuf scanline. The PX_DEF px must be an open pixmap X descriptor. X X 1.7.4 rgb px_wgrey(PX_DEF *px, PX_BYTE *rowbuf, int x, int value) X Return the 8-bit greyscale value of the x'th pixel in the X rowbuf scanline. The PX_DEF px must be an open pixmap X descriptor. NOTE: There is no transformation for greyscale X to colormapped output. The px_wrgb() function must be X used instead. X X 1.7.5 void px_close(PX_DEF *px) X Close the image and free dynamically allocated memory. The X pixel array, if any, is NOT free'd by this function since X there is no pointer to it in the PX_DEF structure. X X 1.7.6 int px_rgb2grey(rgb color) X Return the 8-bit greyscale luminence value of the given X 24-bit RGB color. X X 1.7.7 void px_splitrgb(rgb color, int *R, int *G, int *B) X Split a 24-bit RGB color int it's component parts. The X results are stored in the locations pointed to by R, G X and B. If a pointer in NULL, the corresponding component X is not stored. X X 1.7.8 rgb px_mergergb(rgb *color, int R, int G, int B) X Merge R, G and B components into a 24-bit RGB color. The X result is stored in the locations pointed to by color, if X the pointer is not NULL, and also becomes the return value. X X 1.7.9 int px_makeN(int value, int srcbits, int dstbits) X Normalize an int value with srcbits significant bits to X dstbits significant bits. This is accomplished by shifting X if the source has more than dstbits bits and replication X of the bit pattern (linear interpolation) if the source has X fewer than dstbits bits. X X[more sections will follow later explaining image processing programs, etc.] @FOOBIE@BLETCH@ if test `wc -l < "pxm.doc" | sed -e 's/^ *//'` != 248; then echo 'shar: "'pxm.doc'" unpacked with wrong size!' >&2 fi fi if test -f "pxm.h"; then echo 'shar: will not overwrite "'pxm.h'"' else echo 'shar: extracting "'pxm.h'"' sed -e 's/^X//' << \@FOOBIE@BLETCH@ > "pxm.h" X/* X * pxm.h - header file for libpxm portable pixmap library X * X * Copyright (C) 1988 by Dale Schumacher. X * X * Permission to use, copy, modify, and distribute this software and its X * documentation for any purpose and without fee is hereby granted, provided X * that the above copyright notice appear in all copies and that both that X * copyright notice and this permission notice appear in supporting X * documentation. This software is provided "as is" without express or X * implied warranty. X * X */ X X#define PX_READMODE "rb" X#define PX_WRITEMODE "wb" X Xtypedef long rgb; /* 24-bit RGB triplet */ Xtypedef unsigned char PX_BYTE; /* 8-bit unsigned */ X X/* X * pixmap type values X */ X#define PXT_BIT 0x01 /* simple bitmap */ X#define PXT_PIX 0x02 /* monochrome pixmap */ X#define PXT_MAP 0x04 /* color-mapped pixmap */ X#define PXT_RGB 0x08 /* RGB true-color pixmap */ X#define PXT_TYP 0x0F /* mask to type info only */ X X#define PXT_TXT 0x10 /* text representation */ X#define PXT_BIN 0x20 /* binary representation */ X#define PXT_RLE 0x40 /* run-length encoded binary */ X#define PXT_STO 0x70 /* mask to storage info only */ X X#define PXT_WRT 0x80 /* pxm open in write mode */ X X/* X * pixmap definition structure X */ Xtypedef struct X { X FILE *px_file; /* file pointer */ X int px_type; /* type of pixmap (PXT_*) */ X int px_width; /* width of pixmap in pixels */ X int px_height; /* height of pixmap in pixels */ X int px_depth; /* bits per pixel */ X int px_colors; /* # of colors/grey levels */ X int px_psize; /* pixel size (in bytes) */ X rgb *px_map; /* colormap pointer */ X int px_state; /* state variable for context changes */ X int px_runlen; /* chars remaining in a run */ X PX_BYTE px_runval; /* char value for the run */ X char *px_data; /* rle compression data pointer */ X int px_nbits; /* bit buffer counter */ X PX_BYTE px_bitbuf; /* bit pack/unpack buffer */ X } X PX_DEF; X X/* X * pixmap ident values (magic numbers) X */ X#define PXm1TXT 'P' /* text representation */ X#define PXm1BIN 'B' /* binary representation */ X#define PXm1RLE 'C' /* run-length encoded binary */ X X#define PXm2BIT '1' /* simple bitmap */ X#define PXm2PIX 'm' /* monochrome pixmap */ X#define PXm2MAP 'x' /* color-mapped pixmap */ X#define PXm2RGB 't' /* RGB true-color pixmap */ X X/* X * Declarations of routines. X */ X X/* LIBPXM1 */ Xextern PX_BYTE *px_alloc(/* size */); Xextern PX_BYTE *px_rowalloc(/* width, psize */); Xextern PX_BYTE **px_arrayalloc(/* width, height, psize */); Xextern rgb *px_mapalloc(/* colors */); X X/* LIBPXM2 */ Xextern PX_DEF *px_ropen(/* filename */); Xextern long px_rpixel(/* px */); Xextern PX_BYTE *px_rrow(/* px, rowbuf */); Xextern PX_BYTE **px_readpxm(/* px */); X X/* LIBPXM3 */ Xextern void px_flush(/* px */); Xextern PX_DEF *px_wopen(/* filename, type, width, height, depth, colormap */); Xextern long px_wpixel(/* px, pixel */); Xextern PX_BYTE *px_wrow(/* px, rowbuf */); Xextern PX_BYTE **px_writepxm(/* px, pixels */); X X/* LIBPXM6 */ Xextern int px_makeN(/* value, srcbits, dstbits */); Xextern void px_splitrgb(/* color, &R, &G, &B */); Xextern rgb px_mergergb(/* &color, R, G, B */); Xextern int px_rgb2grey(/* color */); Xextern rgb px_rrgb(/* px, rowbuf, x */); Xextern int px_rgrey(/* px, rowbuf, x */); Xextern rgb px_wrgb(/* px, rowbuf, x, value */); Xextern int px_wgrey(/* px, rowbuf, x, value */); Xextern void px_close(/* px */); X X/* MACROS */ X#define NEW(t) ((t *) px_alloc(sizeof(t))) @FOOBIE@BLETCH@ if test `wc -l < "pxm.h" | sed -e 's/^ *//'` != 106; then echo 'shar: "'pxm.h'" unpacked with wrong size!' >&2 fi fi if test -f "libpxm1.c"; then echo 'shar: will not overwrite "'libpxm1.c'"' else echo 'shar: extracting "'libpxm1.c'"' sed -e 's/^X//' << \@FOOBIE@BLETCH@ > "libpxm1.c" X/* libpxm1.c - pxm utility library part 1 X** X** Copyright (C) 1988 by Jef Poskanzer. X** Copyright (C) 1988 by Dale Schumacher. X** X** Permission to use, copy, modify, and distribute this software and its X** documentation for any purpose and without fee is hereby granted, provided X** that the above copyright notice appear in all copies and that both that X** copyright notice and this permission notice appear in supporting X** documentation. This software is provided "as is" without express or X** implied warranty. X*/ X X#include X#include "pxm.h" X X#define TRACE(x) if(0)/* x */ X#define DEBUG(x) if(0)/* x */ X X X#if 0 /* include this function if it's missing from your library */ Xbzero(p, n) X register PX_BYTE *p; X register int n; X { X while(n--) X *p++ = 0; X } X#endif X X/* X * allocate memory with error checking and zero storage X */ XPX_BYTE * Xpx_alloc(size) X int size; X { X register PX_BYTE *p; X char *malloc(); X X if((p = ((PX_BYTE *) malloc(size))) == NULL) X { X fprintf(stderr, "\nOut of memory!\n"); X exit(1); X } X bzero(p, size); X return(p); X } X X/* X * allocate space for a single row of pixels X */ XPX_BYTE * Xpx_rowalloc(width, psize) X int width, psize; X { X return(px_alloc(width * psize)); X } X X/* X * allocate an array of pointers pointing to rows of pixels storage X */ XPX_BYTE ** Xpx_arrayalloc(width, height, psize) X register int width, height, psize; X { X register PX_BYTE **p, **q; X X q = p = (PX_BYTE **) px_alloc(height * sizeof(PX_BYTE *)); X while(height--) X *q++ = px_alloc(width * psize); X return(p); X } X/* X * allocate storage for a colormap X */ Xrgb * Xpx_mapalloc(colors) X int colors; X { X return((rgb *) px_alloc(colors * sizeof(rgb))); X } @FOOBIE@BLETCH@ if test `wc -l < "libpxm1.c" | sed -e 's/^ *//'` != 82; then echo 'shar: "'libpxm1.c'" unpacked with wrong size!' >&2 fi fi if test -f "libpxm2.c"; then echo 'shar: will not overwrite "'libpxm2.c'"' else echo 'shar: extracting "'libpxm2.c'"' sed -e 's/^X//' << \@FOOBIE@BLETCH@ > "libpxm2.c" X/* libpxm2.c - pxm utility library part 2 X** X** Copyright (C) 1988 by Jef Poskanzer. X** Copyright (C) 1988 by Dale Schumacher. X** X** Permission to use, copy, modify, and distribute this software and its X** documentation for any purpose and without fee is hereby granted, provided X** that the above copyright notice appear in all copies and that both that X** copyright notice and this permission notice appear in supporting X** documentation. This software is provided "as is" without express or X** implied warranty. X*/ X X#include X#include X#include X#include "pxm.h" X X#define TRACE(x) if(0)/* x */ X#define DEBUG(x) if(0)/* x */ X X Xstatic int X_getc(f) X FILE *f; X { X register int c; X X errno = 0; X c = getc(f); X if(c == EOF) X { X if(errno) X perror("Read error"); X else X fprintf(stderr, "Premature EOF\n"); X exit(1); X } X return(c); X } X Xstatic int X_nextln(f) X FILE *f; X { X register int c; X X while((c = getc(f)) != '\n') X if(c == EOF) X return(EOF); X return('\n'); X } X Xstatic int X_skipspace(f) X FILE *f; X { X register int c; X X for(;;) X { X c = getc(f); X if(isascii(c) && isspace(c)) X continue; X if(c == '#') /* eat comment */ X { X if(_nextln(f) == EOF) X return(EOF); X } X else X { X /* X * anything other than whitespace or comments causes X * an unget and ends the whitespace skipping loop X */ X ungetc(c, f); X break; X } X } X return(c); X } X Xstatic int X_getbit(f) X FILE *f; X { X register int c; X X _skipspace(f); X c = _getc(f); X if((c == '0') || (c == '1')) X { X return((c == '0') ? 1 : 0); /* '0'=white, '1'=black */ X } X else X { X fprintf(stderr, "Expected '0' or '1', got c=%02x\n", X (c & 0xFF)); X exit(1); X } X } X Xstatic int X_getint(f) X FILE *f; X { X register int c, i; X X c = _skipspace(f); X X if(!isascii(c) || !isdigit(c)) X { X fprintf(stderr, "Expected decimal data, got c=%02x\n", X (c & 0xFF)); X exit(1); X } X i = 0; X while(isdigit(c = _getc(f))) X { X i *= 10; X i += (c - '0'); X } X X ungetc(c, f); /* unget the delimiter */ X return(i); X } X Xstatic long X_getlhex(f) X FILE *f; X { X int c; X long x; X X c = _skipspace(f); X X if(!isascii(c) || !isxdigit(c)) X { X fprintf(stderr, "Expected hexidecimal data, got c=%02x\n", X (c & 0xFF)); X exit(1); X } X x = 0L; X while(isascii(c = getc(f)) && isxdigit(c)) X { X x <<= 4; X if(isdigit(c)) X x |= (c - '0'); X else X x |= (toupper(c) - 'A' + 10); X } X if(c != EOF) X ungetc(c, f); /* unget the delimiter */ X return(x); X } X X#define PXS_HDR 0 X#define PXS_RAW 1 X#define PXS_RUN 2 X#define PX_ISRUN 0x80 X#define PX_EXTND 0x80 X Xstatic PX_BYTE X_getbyte(px) /* run-length decoder */ X register PX_DEF *px; X { X register FILE *f; X register int i, j; X register PX_BYTE b; X X f = px->px_file; X if(px->px_state == PXS_HDR) X { X j = _getc(f); X if(j & PX_ISRUN) X { X px->px_state = PXS_RUN; X if(j == PX_EXTND) X { X i = _getc(f); X px->px_runlen = (i << 8) + _getc(f); X } X else X px->px_runlen = (j & ~PX_ISRUN) + 1; X px->px_runval = (PX_BYTE) _getc(f); X } X else X { X px->px_state = PXS_RAW; X px->px_runlen = j + 1; X } X } X if(px->px_state == PXS_RAW) X b = (PX_BYTE) _getc(f); X else /* PXS_RUN */ X b = px->px_runval; X if(--(px->px_runlen) <= 0) X px->px_state = PXS_HDR; XTRACE(printf("_getbyte: b=%02x state=%d len=%d val=%02x j=%02x\n", X ((int) b), px->px_state, px->px_runlen, ((int) px->px_runval), j)); X return(b); X } X Xstatic long X_getnext(px) /* bit un-packer */ X register PX_DEF *px; X { X register int i; X register long n; X X n = 0L; X i = px->px_depth; X while(i--) X { X n <<= 1; X if(--(px->px_nbits) <= 0) X { X px->px_bitbuf = _getbyte(px); X px->px_nbits = 8; X } X if(px->px_bitbuf & 0x80) X n |= 1; X px->px_bitbuf <<= 1; X } XTRACE(printf("getnext: n=%06lx nbits=%d bitbuf=%02x\n", X n, px->px_nbits, px->px_bitbuf)); X return(n); X } X X/* X * open a pxm file for reading X */ X XPX_DEF * Xpx_ropen(filename) X char *filename; X { X FILE *f; X register PX_DEF *px; X register rgb *cm; X register int m1, m2, t, i, n; X int rw; X X /* Open file */ X if((filename == NULL) /* use standard input */ X || (strcmp(filename, "") == 0) X || (strcmp(filename, "-") == 0)) X { X f = stdin; X#ifdef dLibs X f->_flag |= _IOBIN; /* force binary mode */ X#endif X } X else if((f = fopen(filename, PX_READMODE)) == NULL) X { X fprintf(stderr, "Can't open pxm file '%s'\n", filename); X exit(1); X } X X /* Allocate pixmap definition block */ X px = NEW(PX_DEF); X px->px_file = f; X px->px_state = px->px_runlen = 0; X px->px_runval = 0; X px->px_map = NULL; X px->px_data = NULL; X px->px_nbits = 0; X X /* Check for magic number. */ X m1 = getc(f); X m2 = getc(f); X DEBUG(printf("[px_ropen: magic1=%c magic2=%c]\n", m1, m2)); X t = 0; X if(m1 == PXm1TXT) X t |= PXT_TXT; X else if(m1 == PXm1RLE) X t |= PXT_RLE; X else if(m1 == PXm1BIN) X t |= PXT_BIN; X else X { X fprintf(stderr, "Bad magic number.\n"); X exit(1); X } X if(m2 == PXm2BIT) X t |= PXT_BIT; X else if(m2 == PXm2PIX) X t |= PXT_PIX; X else if(m2 == PXm2MAP) X t |= PXT_MAP; X else if(m2 == PXm2RGB) X t |= PXT_RGB; X else X { X fprintf(stderr, "Bad magic number.\n"); X exit(1); X } X px->px_type = t; X X /* read sizes */ X px->px_width = _getint(f); X px->px_height = _getint(f); X if(t & PXT_BIT) X { X _nextln(f); X px->px_depth = 1; X px->px_colors = 2; X px->px_psize = 1; X } X else if(t & PXT_PIX) X { X i = _getint(f); X _nextln(f); X px->px_depth = i; X px->px_colors = (1 << i); X px->px_psize = 1; X } X else if(t & PXT_MAP) X { X i = _getint(f); X _nextln(f); X px->px_depth = i; X n = (1 << i); X px->px_colors = n; X if(i <= 8) X px->px_psize = 1; X else if(i <= 16) X px->px_psize = 2; X /* allocate and read colormap */ X cm = px_mapalloc(n); X px->px_map = cm; X if(t & PXT_TXT) X { X while(n--) X *cm++ = (rgb) _getlhex(f); X } X else X { X if(fread(cm, sizeof(rgb), n, f) != n) X { X fprintf(stderr, "Error reading colormap\n"); X exit(1); X } X } X } X else if(t & PXT_RGB) X { X _nextln(f); X px->px_depth = 24; X px->px_colors = (1 << 24); X px->px_psize = 3; X } X X DEBUG(printf("[px_ropen: done, px=%p]\n", px)); X return(px); X } X Xlong Xpx_rpixel(px) X register PX_DEF *px; X { X register int i, size; X register long m, n = 0L; X register int t; X FILE *f; X X f = px->px_file; X t = px->px_type; X if(t & PXT_RLE) X n = _getnext(px); X else if(t & PXT_BIT) X n = (long) _getbit(f); X else if(t & PXT_TXT) X n = _getlhex(f); X else /* PXT_BIN */ X { X for(size = px->px_psize, i = 0; i < size; ++i) X n = (n << 8) | _getc(f); X } X return(n); X } X XPX_BYTE * Xpx_rrow(px, pbuf) X register PX_DEF *px; X register PX_BYTE *pbuf; X { X register PX_BYTE *p; X register int k, step, cols; X register long n, m; X X step = px->px_psize; X cols = px->px_width; X if(px->px_type & (PXT_BIT | PXT_TXT | PXT_RLE)) X { X TRACE(printf("[px_rrow: loop read]\n")); X m = (0x0000FFFFL >> (16 - px->px_depth)); X for(p = pbuf; cols--; p += step) X { X n = px_rpixel(px) & m; X for(k = step; (k--); n >>= 8) X p[k] = n & 0xFF; X } X } X else X { X TRACE(printf("[px_rrow: block read (%dx%d)]\n", X cols, step)); X if(fread(pbuf, step, cols, px->px_file) != cols) X { X fprintf(stderr, "Error reading image\n"); X exit(1); X } X } X return(pbuf); X } X XPX_BYTE ** Xpx_readpxm(px) X register PX_DEF *px; X { X register PX_BYTE **pixels; X register int n, m; X X /* Read image */ X pixels = px_arrayalloc(px->px_width, px->px_height, px->px_psize); X for(n = 0, m = px->px_height; n < m; ++n) X px_rrow(px, pixels[n]); X return(pixels); X } @FOOBIE@BLETCH@ if test `wc -l < "libpxm2.c" | sed -e 's/^ *//'` != 430; then echo 'shar: "'libpxm2.c'" unpacked with wrong size!' >&2 fi fi if test -f "libpxm3.c"; then echo 'shar: will not overwrite "'libpxm3.c'"' else echo 'shar: extracting "'libpxm3.c'"' sed -e 's/^X//' << \@FOOBIE@BLETCH@ > "libpxm3.c" X/* libpxm3.c - pxm utility library part 3 X** X** Copyright (C) 1988 by Jef Poskanzer. X** Copyright (C) 1988 by Dale Schumacher. X** X** Permission to use, copy, modify, and distribute this software and its X** documentation for any purpose and without fee is hereby granted, provided X** that the above copyright notice appear in all copies and that both that X** copyright notice and this permission notice appear in supporting X** documentation. This software is provided "as is" without express or X** implied warranty. X*/ X X#include X#include X#include "pxm.h" X X#define TRACE(x) if(0)/* x */ X#define DEBUG(x) if(0)/* x */ X X Xstatic void X_outerr() X { X perror("Write error"); X exit(1); X } X Xstatic int X_putbit(i, f) X int i; X FILE *f; X { X errno = 0; X putc((i ? '0' : '1'), f); /* '0'=white, '1'=black */ X if(errno) X _outerr(); X return(i); X } X Xstatic int X_putint(i, f) X int i; X FILE *f; X { X errno = 0; X fprintf(f, "%d ", i); X if(errno) X _outerr(); X return(i); X } X Xstatic long X_putlhex(x, f) X long x; X FILE *f; X { X errno = 0; X fprintf(f, "%lx ", x); X if(errno) X _outerr(); X return(x); X } X X#define PX_L0 3 /* minumum run */ X#define PX_L1 128 /* 2^7 */ X#define PX_L2 32767 /* 2^15 - 1 */ X#define PX_ISRUN 0x80 X#define PX_EXTND 0x80 X Xstatic PX_BYTE X_putbyte(b, px) /* byte-stream run-length encoder */ X PX_BYTE b; X PX_DEF *px; X { X /* X * px_state is used to keep track of the number of X * consecutive identical pixel values X */ X register FILE *f; X register int i, j; X register PX_BYTE *rledata; X X f = px->px_file; X i = px->px_runlen; X j = (px->px_runval == b); X rledata = px->px_data; XTRACE(printf("_putbyte: b=%02x state=%d len=%d val=%02x %c\n", X ((int) b), px->px_state, i, ((int) px->px_runval), (j ? '+' : '-'))); X if(px->px_state == PX_ISRUN) X { X if(!j || (i >= PX_L2)) X { X px_flush(px); X px->px_state = 1; X px->px_runval = b; X rledata[0] = b; X } X } X else X { X if(i >= PX_L1) X { X px_flush(px); X px->px_runval = b; X } X if(j) X { X if(++(px->px_state) >= PX_L0) X { X px->px_runlen = (i - (PX_L0 - 1)); X px_flush(px); X px->px_runlen = PX_L0; X px->px_state = PX_ISRUN; X return(b); X } X } X else X { X px->px_state = 1; X px->px_runval = b; X } X rledata[px->px_runlen] = b; X } X ++(px->px_runlen); X return(b); X } X Xstatic long X_putnext(n, px) /* bit packer */ X register long n; X register PX_DEF *px; X { X register int i; X register long m; X XTRACE(printf("putnext: n=%06lx nbits=%d bitbuf=%02x\n", X n, px->px_nbits, px->px_bitbuf)); X i = px->px_depth; X m = 1L << (i - 1); X while(i--) X { X px->px_bitbuf <<= 1; X if(m & n) X px->px_bitbuf |= 1; X if(++(px->px_nbits) >= 8) X { X px->px_nbits = 0; X _putbyte(px->px_bitbuf, px); X } X n <<= 1; X } X } X Xvoid Xpx_flush(px) X register PX_DEF *px; X { X register FILE *f; X register int i, j, t; X register PX_BYTE b; X X t = px->px_type; X if((t & PXT_WRT) && ((t & PXT_STO) == PXT_RLE)) X { X if(px->px_nbits > 0) X { X px->px_bitbuf <<= (8 - px->px_nbits); X px->px_nbits = 0; X _putbyte(px->px_bitbuf, px); X } X f = px->px_file; X i = px->px_runlen; X if(i <= 0) X return; X errno = 0; X if(px->px_state == PX_ISRUN) X { X if(i <= PX_L1) X putc((PX_ISRUN | ((char) (i - 1))), f); X else X { X putc(((char) PX_EXTND), f); X putc(((char) ((i >> 8) & 0x7F)), f); X putc(((char) (i & 0xFF)), f); X } XTRACE(printf("px_flush: run of %d (pixel=%02x)\n", i, ((int) px->px_runval))); X putc(((char) px->px_runval), f); X } X else X { X putc(((char) (i - 1)), f); XTRACE(printf("px_flush: %d unique\n", i)); X fwrite(px->px_data, 1, i, f); X } X if(errno) X _outerr(); X px->px_runlen = 0; X px->px_state = 0; X } X } X X/* X * open a pxm file for writing X */ XPX_DEF * Xpx_wopen(filename, t, w, h, d, cm) X char *filename; X char t; X int w, h, d; X register rgb *cm; X { X FILE *f; X register PX_DEF *px; X register int m1, m2, i, n; X X /* Open file */ X if((filename == NULL) /* use standard output */ X || (strcmp(filename, "") == 0) X || (strcmp(filename, "-") == 0)) X { X f = stdout; X#ifdef dLibs X if((t & PXT_TXT) == 0) X f->_flag |= _IOBIN; /* force binary mode */ X#endif X } X else if((f = fopen(filename, PX_WRITEMODE)) == NULL) X { X fprintf(stderr, "Can't open pxm file '%s'\n", filename); X exit(1); X } X X /* Allocate pixmap definition block */ X px = NEW(PX_DEF); X px->px_file = f; X px->px_state = px->px_runlen = 0; X px->px_runval = 0; X px->px_data = NULL; X px->px_nbits = 0; X X /* Write magic number. */ X switch(t & PXT_STO) X { X case PXT_TXT: m1 = PXm1TXT; break; X case PXT_RLE: m1 = PXm1RLE; break; X case PXT_BIN: m1 = PXm1BIN; break; X default: X fprintf(stderr, "Bad picture type %02x\n", t); X exit(1); X } X switch(t & PXT_TYP) X { X case PXT_BIT: m2 = PXm2BIT; break; X case PXT_PIX: m2 = PXm2PIX; break; X case PXT_MAP: m2 = PXm2MAP; break; X case PXT_RGB: m2 = PXm2RGB; break; X default: X fprintf(stderr, "Bad picture type %02x\n", t); X exit(1); X } X DEBUG(fprintf(stderr, "[px_wopen: magic1=%c magic2=%c]\n", m1, m2)); X putc(m1, f); X putc(m2, f); X px->px_type = (t | PXT_WRT); X fprintf(f, " # %s\n", filename); X X /* write sizes */ X px->px_width = _putint(w, f); X px->px_height = _putint(h, f); X if(t & PXT_BIT) X { X fprintf(f, " # width height\n"); X px->px_depth = 1; X px->px_colors = 2; X px->px_psize = 1; X } X else if(t & PXT_PIX) X { X i = _putint(d, f); X fprintf(f, " # width height depth\n"); X px->px_depth = i; X px->px_colors = (1 << i); X px->px_psize = 1; X } X else if(t & PXT_MAP) X { X i = _putint(d, f); X fprintf(f, " # width height depth\n"); X px->px_depth = i; X n = (1 << i); X px->px_colors = n; X if(i <= 8) X px->px_psize = 1; X else if(i <= 16) X px->px_psize = 2; X /* write colormap */ X px->px_map = cm; X if(t & PXT_TXT) X { X fprintf(f, "## colormap\n"); X while(n--) X _putlhex(((long) *cm++), f); X } X else X { X if(fwrite(cm, sizeof(rgb), n, f) != n) X _outerr(); X } X } X else if(t & PXT_RGB) X { X fprintf(f, " # width height\n"); X px->px_depth = 24; X px->px_colors = (1 << 24); X px->px_psize = 3; X } X X if(t & PXT_TXT) X fprintf(f, "## pixel data\n"); X X if(t & PXT_RLE) X px->px_data = px_alloc(PX_L1); X X DEBUG(fprintf(stderr, "[px_wopen: done]\n")); X return(px); X } X Xlong Xpx_wpixel(px, pixel) X register PX_DEF *px; X long pixel; X { X register int i, size; X register long n; X register int t; X FILE *f; X PX_BYTE pixdata[4]; X X for(n = pixel, i = px->px_psize; i--; n >>= 8) X pixdata[i] = n & 0xFF; X n = pixel; X f = px->px_file; X t = px->px_type; X if(t & PXT_RLE) X _putnext(n, px); X else if(t & PXT_BIT) X { X if(px->px_state >= 64) X { X putc('\n', px->px_file); X px->px_state = 0; X } X _putbit(((int) n), f); X ++px->px_state; X } X else if(t & PXT_TXT) X { X if(px->px_state > 60) X { X putc('\n', px->px_file); X px->px_state = 0; X } X _putlhex(n, f); X px->px_state += 7; X } X else /* PXT_BIN */ X { X for(size = px->px_psize, i = 0; i < size; ++i) X putc(pixdata[i], f); X } X return(n); X } X XPX_BYTE * Xpx_wrow(px, pbuf) X register PX_DEF *px; X register PX_BYTE *pbuf; X { X register PX_BYTE *p; X register int k, step, cols; X register long n; X X step = px->px_psize; X cols = px->px_width; X if(px->px_type & (PXT_BIT | PXT_TXT | PXT_RLE)) X { XTRACE(printf("px_wrow: (BIT | TXT | RLE) loop\n")); X for(p = pbuf; cols--; p += step) X { X for(k = step, n = 0L; (k--); ) X n = (n << 8) | p[k]; X px_wpixel(px, n); X } X if(px->px_type & PXT_TXT) X { X putc('\n', px->px_file); X px->px_state = 0; X } X } X else X { X if(fwrite(pbuf, step, cols, px->px_file) != cols) X _outerr(); X } X return(pbuf); X } X XPX_BYTE ** Xpx_writepxm(px, pixels) X register PX_DEF *px; X register PX_BYTE **pixels; X { X register int n, m; X X /* Write image */ X for(n = 0, m = px->px_height; n < m; ++n) X px_wrow(px, pixels[n]); X return(pixels); X } @FOOBIE@BLETCH@ if test `wc -l < "libpxm3.c" | sed -e 's/^ *//'` != 420; then echo 'shar: "'libpxm3.c'" unpacked with wrong size!' >&2 fi fi if test -f "libpxm6.c"; then echo 'shar: will not overwrite "'libpxm6.c'"' else echo 'shar: extracting "'libpxm6.c'"' sed -e 's/^X//' << \@FOOBIE@BLETCH@ > "libpxm6.c" X/* libpxm6.c - pxm utility library part X** X** Copyright (C) 1988 by Dale Schumacher. X** X** Permission to use, copy, modify, and distribute this software and its X** documentation for any purpose and without fee is hereby granted, provided X** that the above copyright notice appear in all copies and that both that X** copyright notice and this permission notice appear in supporting X** documentation. This software is provided "as is" without express or X** implied warranty. X*/ X X#include X#include X#include "pxm.h" X X#define TRACE(x) if(0)/* x */ X#define DEBUG(x) if(0)/* x */ X X X/* X * normalize a [1..31]-bit value to N-bits X */ Xint Xpx_makeN(value, srcbits, dstbits) X register int value, srcbits, dstbits; X { X register int n; X X if(srcbits != dstbits) X { X if(srcbits > dstbits) X value >>= srcbits - dstbits; X else X { X n = ((long) value); X while(srcbits < dstbits) X { X n |= n << srcbits; X srcbits <<= 1; X } X n >>= (srcbits - dstbits); X value = ((int) n); X } X } X return(value); X } X X/* X * split a 24-bit RGB triplet into 8-bit components X */ Xvoid Xpx_splitrgb(color, R, G, B) X register rgb color; X int *R, *G, *B; X { X TRACE(fprintf(stderr, "[px_splitrgb: color=%06lx]\n", color)); X if(B) X *B = (color & 0xFF); X color >>= 8; X if(G) X *G = (color & 0xFF); X color >>= 8; X if(R) X *R = (color & 0xFF); X } X X/* X * merge 8-bit components into a 24-bit RGB triplet X */ Xrgb Xpx_mergergb(color, R, G, B) X register rgb *color; X int R, G, B; X { X register rgb n; X X n = (R << 16) | (G << 8) | B; X if(color) X *color = n; X TRACE(fprintf(stderr, "[px_mergergb: color=%06lx]\n", n)); X return(n); X } X X/* X * return the 24-bit RGB color value for a given pixel X */ Xrgb Xpx_rrgb(px, row, x) X register PX_DEF *px; X register PX_BYTE *row; X int x; X { X register int i; X register rgb n = 0L; X X i = px->px_psize; X row += (x * i); X while(i--) X n = (n << 8) | (*row++); X switch(px->px_type & PXT_TYP) X { X case PXT_BIT: X n = (n ? 0xFFFFFF : 0x000000); X break; X case PXT_PIX: X n = (rgb) px_makeN((int) n, px->px_depth, 8); X n |= (n << 16) | (n << 8); X break; X case PXT_MAP: X n = px->px_map[n]; X break; X case PXT_RGB: X /* already HAVE rgb */ X break; X default: X fprintf(stderr, "px: bad picture type\n"); X exit(1); X } X return(n); X } X X/* X * convert 24-bit RGB color value to [0..255] grey-scale value X */ Xint Xpx_rgb2grey(color) X rgb color; X { X int R, G, B; X register int grey; X X px_splitrgb(color, &R, &G, &B); X /* X * The following formula gives the following color weighting X * Red 30.1%, Green 58.6%, Blue 11.3% X * The optimal values are: X * Red 29.9%, Green 58.7%, Blue 11.4% X */ X grey = (((77 * R) + (150 * G) + (29 * B)) / 256) & 0xFF; X return(grey); X } X X/* X * return the [0..255] grey-scale value for a given pixel X */ Xint Xpx_rgrey(px, row, x) X register PX_DEF *px; X register PX_BYTE *row; X int x; X { X register int g = 0, i; X register rgb n = 0L; X X i = px->px_psize; X row += (x * i); X while(i--) X n = (n << 8) | (*row++); X TRACE(printf("[px_rgrey: n=0x%06lx]\n", n)); X switch(px->px_type & PXT_TYP) X { X case PXT_BIT: X g = (n ? 0xFF : 0x00); X break; X case PXT_PIX: X g = px_makeN((int) n, px->px_depth, 8); X break; X case PXT_MAP: X n = px->px_map[n]; X /* got RGB now, fall thru... */ X case PXT_RGB: X g = px_rgb2grey(n); X break; X default: X fprintf(stderr, "px: bad picture type\n"); X exit(1); X } X return(g); X } X X/* X * store a 24-bit RGB color value in a given pixel X */ Xrgb Xpx_wrgb(px, row, x, value) X register PX_DEF *px; X register PX_BYTE *row; X int x; X rgb value; X { X register int i; X register rgb *cm; X register long n; X X n = value; X row += (x * px->px_psize); X switch(px->px_type & PXT_TYP) X { X case PXT_BIT: X n = (n ? 1L : 0L); X break; X case PXT_PIX: X n = (rgb) px_rgb2grey(n); X break; X case PXT_MAP: X cm = px->px_map; X i = px->px_colors; X while(i--) X if(cm[i] == n) X break; X if(n < 0) X { X fprintf(stderr, X "color %06lx not in colormap\n", X n); X exit(1); X } X n = px->px_map[n]; X break; X case PXT_RGB: X /* already HAVE rgb */ X break; X default: X fprintf(stderr, "px: bad picture type\n"); X exit(1); X } X for(i = px->px_psize; i--; n >>= 8) X row[i] = ((PX_BYTE) (n & 0xFF)); X return(value); X } X X/* X * store a [0..255] grey-scale value in a given pixel X */ Xint Xpx_wgrey(px, row, x, value) X register PX_DEF *px; X register PX_BYTE *row; X int x; X int value; X { X register int g; X register int i; X register rgb n = 0L; X X g = value; X row += (x * px->px_psize); X switch(px->px_type & PXT_TYP) X { X case PXT_BIT: X n = (g ? 1L : 0L); X break; X case PXT_PIX: X n = ((rgb) (g >>= (8 - px->px_depth))); X break; X case PXT_MAP: X fprintf(stderr, X "use px_wrgb() for colormapped output\n", n); X exit(1); X case PXT_RGB: X n = ((rgb) g); X n |= (n << 16) | (n << 8); X break; X default: X fprintf(stderr, "px: bad picture type\n"); X exit(1); X } X for(i = px->px_psize; i--; n >>= 8) X row[i] = ((PX_BYTE) (n & 0xFF)); X return(value); X } X X/* X * close the file associated with a given pixmap X */ Xvoid Xpx_close(px) X register PX_DEF *px; X { X px_flush(px); X errno = 0; X fclose(px->px_file); X if(errno) X { X perror("Error closing pixmap"); X exit(1); X } X if(px->px_map) X free(px->px_map); X if(px->px_data) X free(px->px_data); X free(px); X } @FOOBIE@BLETCH@ if test `wc -l < "libpxm6.c" | sed -e 's/^ *//'` != 294; then echo 'shar: "'libpxm6.c'" unpacked with wrong size!' >&2 fi fi # End of shell archive.