[comp.graphics] Extending PBM to handle Greyscale and Color images

dal@midgard.Midgard.MN.ORG (Dale Schumacher) (01/18/89)

In article <10354@well.UUCP> Jef Poskanzer <jef@rtsg.ee.lbl.gov> writes:
|I get a lot of mail about my portable bitmap toolkit.  I mean a *lot*
|of mail - I'm approaching 1000 messages.  A certain percentage of the
|mail has always asked how come the package barfs when fed a color
|image.  Now, I named the package specifically to avoid this class of
|questions.  I thought *everyone* knew that a bitmap is one bit deep.
|Apparently not.
[...rest of article deleted...]

I took a good look at the PBM (Portable Bitmap) toolkit code that was
posted recently in comp.source.misc (I think) by Mr. Poskanzer.  There
is quite a bit of useful code in that package.  However, my first reaction
was "This is great, and very portable, but it only handles 1-bit deep
images (also know as bitmaps)".  Being of the hacker mentality, I set
out to rectify this situation, and in the process located several problems
with portability in the original routines.  At this point I have an
entirely rewritten set of routines that handles an image file format
that I'm calling PXM (Portable Pixmap), which is a superset of PBMs.

PXM format stores images in one of 4 types, Monochrome Bitmaps (1 bpp),
Greyscale Pixmaps (2-8 bpp), Colormapped Images (1-16 bpp, w/ 24-bit
RGB colormap), or Full Color Images (24-bit RGB).  Each of these image
types can be stored using one of 3 storage methods, ASCII (an ASCII 1-bit
image is the same as an ASCII PBM), Binary (8-bit data stream), or
Binary Run-Length Encoded (8-bit data stream with RLE compression).
I should mention that my RLE is *NOT* compatible with compressed PBMs.

There are 4 classes of code that will be included in the PXM package.
First, there is the library, a collection of C functions and a header file
for routines which read/write/manage images in PXM format.  The source
for this part of the package is quite small (~25K) and could easily be
posted to this newsgroup.  Secondly, there are import/export programs
which convert between PXM format and other image file formats.  Third,
there are system independent image processing utilities that work on
PXM files, and finally, utilities (such as histograms and PXM display
programs) which must be written specifically for each machine.

Only the RLE code remains to be done for the library to be ready.  Would
it be appropriate to post it here?  Only a few of the import/export
programs are ready (the ones I needed, some of which were not in the
PBM package), though it should be fairly easy to convert the PBM code
to use the PXM library.  Most of my effort is going into the generic
image processing programs, many of which were not in the PBM package.
There is Floyd-Steinberg dithering, generalized convolution, input/output
function transformation (which can do gamma correction, positive/negative
inversion, contrast enhancements, quantization, and more), and I'm
hoping to have 2-d FFT processing soon.  The system dependent programs
are a bit of a problem.  A good histogram display is needed to be able
to use input/output transformation effectively, as well as an interactive
graphical curve creation program, but such programs are difficult, or
impossible, to write machine independently.  Should machine dependent
versions be posted as a basis for porting?

At this point my plan is to post just the library routines here, and
later to post the entire package to comp.sources.misc.  Hopefully
all you other graphics hackers will take the PXM routines and use
them to implement your latest and greatest image processing algorithms
so we can all see how well they work.

PS. Jef, I tried to send you mail but it bounced, please try to reach me
<dal@syntel.UUCP>, <bungia!midgard!syntel!dal> or <umn-cs!cctb!syntel!dal>

pokey@well.UUCP (Jef Poskanzer) (01/19/89)

In the referenced message, dal@syntel.UUCP (Dale Schumacher) wrote:
}    "This is great, and very portable, but it only handles 1-bit deep
}images (also know as bitmaps)".  Being of the hacker mentality, I set
}out to rectify this situation, and in the process located several problems
}with portability in the original routines.  At this point I have an
}entirely rewritten set of routines that handles an image file format
}that I'm calling PXM (Portable Pixmap), which is a superset of PBMs.

Actually, I mentioned a while back that I was considering doing this
very thing.  (Article <6377@well.UUCP> of 26 Jun 88, in this newsgroup,
titled "Upgrade PBM to PGM or PPM: opinions wanted.")  I got a few
responses, mostly pointing out that the Utah and IM Raster Toolkits
already did what I was proposing to do.  This I already knew (but
needed to be reminded of), and is the main reason that PBM restricts
itself to black and white: the operations you typically perform on
black and white images are somewhat different from those for grayscale
or color images.  There was a niche unfilled, and I filled it.

So, my opinion then and now is that extending PBM to gray and color is
not a particularly great idea.  Even so, I must admit that I have done
it too, because like Dale I am of the hacker mentality.  I just
couldn't resist.  There was some color hacking I wanted to do, so
rather than bringing up and learning Utah or IM I just rolled my own.
It was only a few days work, and in the process I learned more about
what I really wanted to do with the color images.

I don't feel like releasing this new stuff (yet), but if Dale releases
his I'm sure I'll steal code from it!  And the portability enhancements
mentioned are, of course, welcome.

}PS. Jef, I tried to send you mail but it bounced, please try to reach me
}<dal@syntel.UUCP>, <bungia!midgard!syntel!dal> or <umn-cs!cctb!syntel!dal>

I have no idea how to get to any of those addresses, sorry.
---
Jef

             Jef Poskanzer   jef@rtsg.ee.lbl.gov   ...well!pokey
                         Yow! Are we interfacing yet?

dal@midgard.Midgard.MN.ORG (Dale Schumacher) (01/26/89)

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: <dal@syntel.UUCP> or <bungia.mn.org!midgard!syntel!dal>

#----------------------------------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 <stdio.h>
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 <stdio.h>
X#include <ctype.h>
X#include <errno.h>
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 <stdio.h>
X#include <errno.h>
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 <stdio.h>
X#include <errno.h>
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.

barad@bourbon.ee.tulane.edu (Herb Barad) (01/27/89)

In article <10403@well.UUCP> Jef Poskanzer <jef@rtsg.ee.lbl.gov> writes:
>I don't feel like releasing this new stuff (yet), but if Dale releases
>his I'm sure I'll steal code from it!  And the portability enhancements
>mentioned are, of course, welcome.

Well, I hope that one of you releases it.  I think that people would
be very interested in this stuff.  Please consider it.


-- 
Herb Barad	[Signal & Image Processing Laboratory]
		[Electrical Engineering Dept. - Tulane Univ.]
INTERNET:	barad@ee.tulane.edu
USENET:		barad@bourbon.uucp