From decwrl!lll-winken!uunet!allbery Sun Mar 25 18:44:09 PST 1990
Article 1459 of comp.sources.misc:
Path: decwrl!lll-winken!uunet!allbery
From: bturner@hpcvxbt.cv.hp.com (Bill Turner)
Newsgroups: comp.sources.misc
Subject: v11i084: Four new PPM utilities
Message-ID: <82380@uunet.UU.NET>
Date: 26 Mar 90 00:17:01 GMT
Sender: allbery@uunet.UU.NET
Lines: 986
Approved: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)

Posting-number: Volume 11, Issue 84
Submitted-by: bturner@hpcvxbt.cv.hp.com (Bill Turner)
Archive-name: ppm-utils/part01

After getting the PBMPLUS stuff, I found there were some things I'd still like
to be able to do -- in particular, the pbm programs seemed weak at combining
images together.  Part of that is because I didn't read the documentation
(yes, RTFM), but I didn't see a good way of "concatenating" images together.
Also, since I enjoy tinkering with code, I wanted to see how the PBM code
worked.  Anyway, from this was born the following four programs:  ppmfill,
ppmborder, ppmmerge, and ppmoverlay.

ppmfill is basically a subset of pnmtile (since it only works with ppm's).
ppmborder writes a border around a ppmfile (could be done with pnmtile and
   pnmpaste, but I like the cleanliness of a single program).
ppmmerge concatenates a number of ppm files together, either side by side or
   stacked vertically.
ppmoverlay is similar to pnmpaste, with a different interface (specify border
    size and corner [i.e., top left] rather than (x, y) offset).

Even if nobody finds these useful, I wrote 'em, so I'm submitting 'em!

--Bill Turner (bturner@hp-pcd.cv.hp.com)
Hewlett-Packard Information Technology Operation

---------------------------------cut here-------------------------------------
#! /bin/sh
#
# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by Bill Turner <bturner@hp-pcd.cv.hp.com> on Mon Mar 19 14:11:26 1990
#
# This archive contains:
#	ppmfill.1	ppmborder.1	ppmmerge.1	ppmoverlay.1	
#	ppmfill.c	ppmborder.c	ppmmerge.c	ppmoverlay.c	
#

LANG=""; export LANG
PATH=/bin:/usr/bin:$PATH; export PATH

echo x - ppmfill.1
cat >ppmfill.1 <<'@EOF'
.TH ppmfill 1 "19 March 1990"
.SH NAME
ppmfill - fill an area with a tiled ppm
.SH SYNOPSIS
pbmfill <width> <height> [ppmfile]
.SH DESCRIPTION
Produces a portable pixmap of the specified width and height,
with a pattern in it.  The specified ppmfile (or stdin, if no
file is specified) is tiled to create a new ppmfile of the specified
size.
.SH "SEE ALSO"
pnmtile(1), ppmborder(1), ppm(5)

This was written without reading the ppm documentation, and is functionally a
subset of pnmtile (since ppmfill only handles ppm's).  But since I spent the
time doing it, I'm damn well going to send it out!
.SH AUTHOR
Bill Turner, Hewlett-Packard Company.  Since the work is heavily leveraged
from the original PBM source, below is the original copyright notice.

Copyright (C) 1989 by Jef Poskanzer.

Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted, provided
that the above copyright notice appear in all copies and that both that
copyright notice and this permission notice appear in supporting
documentation.  This software is provided "as is" without express or
implied warranty.
@EOF

chmod 644 ppmfill.1

echo x - ppmborder.1
cat >ppmborder.1 <<'@EOF'
.TH ppmborder 1 "19 March 1990"
.SH NAME
ppmborder - add a border around a ppm file
.SH SYNOPSIS
ppmborder <width> <borderfile> [ppmfile]
.SH DESCRIPTION
Uses a tile of
.I borderfile
as a border around a ppmfile.  The ppmfile produced is larger than the
original.
.I width
specifies the width of the border to produce.
.SH "SEE ALSO"
pnmtile(1), ppmfill(1), ppm(5)
.SH AUTHOR
Bill Turner, Hewlett-Packard Company.  Since the work is heavily leveraged
from the original PBM source, below is the original copyright notice.

Copyright (C) 1989 by Jef Poskanzer.

Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted, provided
that the above copyright notice appear in all copies and that both that
copyright notice and this permission notice appear in supporting
documentation.  This software is provided "as is" without express or
implied warranty.
@EOF

chmod 644 ppmborder.1

echo x - ppmmerge.1
cat >ppmmerge.1 <<'@EOF'
.TH ppmmerge 1 "19 March 1990"
.SH NAME
ppmmerge - merge ppmfiles together
.SH SYNOPSIS
ppmmerge [-v | -h] ppmfile...
.SH DESCRIPTION
Concatenates the ppmfiles either side-by-side (
.I -h
, the default) or one on
top of the other (
.I -v
).  Any number of ppm files may be specified, but it doesn't make much sense
to have less than two.
.PP
This is useful for producing a "collection" image, where a number of images
are merged into a single file.
.SH "SEE ALSO"
ppmoverlay(1), ppm(5)
.SH AUTHOR
Bill Turner, Hewlett-Packard Company.  Since the work is heavily leveraged
from the original PBM source, below is the original copyright notice.

Copyright (C) 1989 by Jef Poskanzer.

Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted, provided
that the above copyright notice appear in all copies and that both that
copyright notice and this permission notice appear in supporting
documentation.  This software is provided "as is" without express or
implied warranty.
@EOF

chmod 644 ppmmerge.1

echo x - ppmoverlay.1
cat >ppmoverlay.1 <<'@EOF'
.TH ppmoverlay 1 "19 March 1990"
.SH NAME
ppmoverlay - overlay one ppm over the top of another
.SH SYNOPSIS
ppmoverlay [-top|-vcenter|-bottom] [-left|-hcenter|-right] [-border #]
ppmfile [ppmbackground]
.SH DESCRIPTION
Overlays a ppmfile over the specified background (or stdin, if no background
file is specified).  The default is to center the image over the background,
but this may be overridden with the flags.
.IP -top 10
The image is placed along the top border.
.IP -vcenter 10
(Default) The image is centered vertically.
.IP -bottom 10
The image is placed along the bottom border.
.IP -left 10
The image is placed along the left border.
.IP -hcenter 10
(Default) The image is centered horizontally.
.IP -right 10
The image is placed along the right border.
.IP -border 10
Specifies the border width to use (default = 0).
.PP
If the source image is too small to fit on the background with the specified
border width, an error message is generated.
.PP
This is useful for generating "collection" images.
.SH "KNOWN PROBLEMS"
The border width is used for both the vertical and horizontal borders.  There
is no way to specify separate border sizes (although this is an easy
modification to make, and it should be done).
.SH "SEE ALSO"
pnmtile(1), ppmfill(1), ppm(5)
.SH AUTHOR
Bill Turner, Hewlett-Packard Company.  Since the work is heavily leveraged
from the original PBM source, below is the original copyright notice.

Copyright (C) 1989 by Jef Poskanzer.

Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted, provided
that the above copyright notice appear in all copies and that both that
copyright notice and this permission notice appear in supporting
documentation.  This software is provided "as is" without express or
implied warranty.
@EOF

chmod 644 ppmoverlay.1

echo x - ppmfill.c
cat >ppmfill.c <<'@EOF'
/* ppmfill - fill a rectangle with a tiling of a ppm file
**
** Written 3/90 by Bill Turner, heavily leveraged from code by Jef Poskanzer,
** hence the copyright below.
**
** Copyright (C) 1989 by Jef Poskanzer.
**
** Permission to use, copy, modify, and distribute this software and its
** documentation for any purpose and without fee is hereby granted, provided
** that the above copyright notice appear in all copies and that both that
** copyright notice and this permission notice appear in supporting
** documentation.  This software is provided "as is" without express or
** implied warranty.
*/

#include <stdio.h>
#include "ppm.h"

main( argc, argv )
int argc;
char *argv[];
    {
    FILE *ifd;
    pixel **pixels, *newpixelrow;
    register pixel *sP, *dP;
    int argn, rows, cols, newrows, newcols, row, col, irow, icol;
    pixval maxval;
    char *usage = "width height [ppmfile]";

    pm_progname = argv[0];

    argn = 1;

    if ( argc < 3 )
	pm_usage( usage );

    if ( sscanf( argv[argn++], "%d", &newcols) != 1 )
	pm_usage( usage );

    if ( sscanf( argv[argn++], "%d", &newrows) != 1)
	pm_usage( usage );

    if ( argn != argc )
	{
	ifd = pm_openr( argv[argn] );
	argn++;
	}
    else
	ifd = stdin;

    if ( argn != argc )
	pm_usage( usage );

    ppm_pbmmaxval = 255;	/* use larger value for better results */
    pixels = ppm_readppm( ifd, &cols, &rows, &maxval );

    pm_close( ifd );

    ppm_writeppminit( stdout, newcols, newrows, maxval );
    newpixelrow = ppm_allocrow( newcols );

    for ( row = 0, irow = 0; row < newrows; row++ )
	{

/* Each destination row consinsts of a repatition of input rows.  The source
 * pointer is reset to the starting point every cols pixels.  This could also
 * have been done using moduls, i.e. *dP++ = pixels[irow][col % cols], or
 * ultimately *dP++ = pixels[row % rows][col % cols].  I'm not exactly sure
 * which produces the most efficient code.
 */

	for ( col = 0, icol = 0, sP = pixels[irow], dP = newpixelrow;
	      col < newcols;
	      col++ )
	    {
	    *dP++ = *sP++;
	    if (++icol >= cols)	    /* End of input, reset to start of row */
		{
		icol = 0;
		sP = pixels[irow];
		}
	    }

	ppm_writeppmrow( stdout, newpixelrow, newcols, maxval );

/* Similar with columns, need to repeat ever "rows" row.  */

	if (++irow >= rows)
	    irow = 0;
	}

    exit(0);
    }
@EOF

chmod 644 ppmfill.c

echo x - ppmborder.c
cat >ppmborder.c <<'@EOF'
/* ppmborder - create a border with a tile of a ppm file.
**
** Written 3/90 by Bill Turner, heavily leveraged from code by Jef Poskanzer,
** hence the copyright below.
**
** Copyright (C) 1989 by Jef Poskanzer.
**
** Permission to use, copy, modify, and distribute this software and its
** documentation for any purpose and without fee is hereby granted, provided
** that the above copyright notice appear in all copies and that both that
** copyright notice and this permission notice appear in supporting
** documentation.  This software is provided "as is" without express or
** implied warranty.
*/

#include <stdio.h>
#include "ppm.h"

main( argc, argv )
int argc;
char *argv[];
    {
    FILE *ifd, *borderfd;
    pixel **pixels, **borderpixels, *newpixelrow;
    register pixel *sP, *dP, *bP;
    int argn, rows, cols, row, col;
    int brows, bcols, brow, bcol, border, newcols;
    pixval maxval;
    char *usage = "width ppmfile [ppmfile]";

    pm_progname = argv[0];

    argn = 1;

    if ( argc < 3 )
	pm_usage( usage );

    if ( sscanf( argv[argn++], "%d", &border) != 1 )
	pm_usage( usage );


    if ( argn != argc )
	{
	borderfd = pm_openr( argv[argn] );
	argn++;
	}
    else
	pm_usage( usage );

    if ( argn != argc )
	{
	ifd = pm_openr( argv[argn] );
	argn++;
	}
    else
	ifd = stdin;

    if ( argn != argc )
	pm_usage( usage );

    ppm_pbmmaxval = 255;	/* use larger value for better results */
    borderpixels = ppm_readppm( borderfd, &brows, &bcols, &maxval);
    pm_close( borderfd );

    pixels = ppm_readppm( ifd, &cols, &rows, &maxval );
    pm_close( ifd );
    newcols = cols + border * 2;  /* New width includes left and right border */

    ppm_writeppminit( stdout, newcols, rows + border * 2, maxval );
    newpixelrow = ppm_allocrow( newcols );

/* For the topborder rows, simply tile from the border ppm. */
/* (See the ppmfill code for a description of the tiling and possible
 * changes.)
 */

    for ( row = 0, brow = 0; row < border; row++ )
	{
	for ( col = 0, bcol = 0, dP = newpixelrow, bP = borderpixels[brow];
	      col < newcols;
	      col++)
	    {
	    *dP++ = *bP++;
	    if ( ++bcol >= bcols )
		{
		bcol = 0;
		bP = borderpixels[brow];
		}
	    }

	ppm_writeppmrow( stdout, newpixelrow, newcols, maxval );

	if ( ++brow >= brows )
	    brow = 0;
	}

/* For the "middle" rows, first copy the left border bits from the tile, then
 * copy the image row, then the right border bits from the tile.
 */

    for ( row = 0; row < rows; row++ )
	{

/* Left border */
	for ( col = 0, bcol = 0, dP = newpixelrow, bP = borderpixels[brow];
	      col < border;
	      col++ )
	    {
	    *dP++ = *bP++;
	    if ( ++bcol >= bcols )
		{
		bcol = 0;
		bP = borderpixels[brow];
		}
	    }

/* Image bits */
	for ( col = 0, sP = pixels[row];
	      col < cols;
	      col++ )
	    {
	    *dP++ = *sP++;
	    }

/* Right border */
	bcol = (cols + border) % bcols;
	for ( col = 0, bP = &borderpixels[brow][bcol];
	      col < border;
	      col++ )
	    {
	    *dP++ = *bP++;
	    if ( ++bcol >= bcols )
		{
		bcol = 0;
		bP = borderpixels[brow];
		}
	    }

	ppm_writeppmrow( stdout, newpixelrow, newcols, maxval );
	if (++brow >= brows)
	    brow = 0;
	}

/* As with the top border, so with the bottom border. */

    for ( row = 0; row < border; row++ )
	{
	for ( col = 0, bcol = 0, dP = newpixelrow, bP = borderpixels[brow];
	      col < cols + border * 2;
	      col++)
	    {
	    *dP++ = *bP++;
	    if ( ++bcol >= bcols )
		{
		bcol = 0;
		bP = borderpixels[brow];
		}
	    }

	ppm_writeppmrow( stdout, newpixelrow, newcols, maxval );

	if ( ++brow >= brows )
	    brow = 0;
	}
    
    exit(0);
    }
@EOF

chmod 644 ppmborder.c

echo x - ppmmerge.c
cat >ppmmerge.c <<'@EOF'
/* ppmmerge.c - merge two or more portable pixmaps
**
** Written 3/90 by Bill Turner, but leveraged heavily from code by Jef
** Poskanzer (extensive use of the PBM code), so the copyright notice is
** attached below.
**
** Copyright (C) 1989 by Jef Poskanzer.
**
** Permission to use, copy, modify, and distribute this software and its
** documentation for any purpose and without fee is hereby granted, provided
** that the above copyright notice appear in all copies and that both that
** copyright notice and this permission notice appear in supporting
** documentation.  This software is provided "as is" without express or
** implied warranty.
*/

#include <stdio.h>
#include "ppm.h"

void WriteStack();
void WriteSide();

main( argc, argv )
int argc;
char *argv[];
    {
    FILE *ifd;
    pixel **pixels, *newpixelrow;
    pixel ***pixel_list;
    register pixel *pP, *npP;
    pixel bgpixel, prevpixel, p;
    int argn, rows, cols, newrows, newcols, row, col, new;
    pixval maxval;
    int *cols_list, *rows_list, *pad_list;
    pixval *maxval_list;
    int num_files;
    char *usage = "[-v | -h] ppmfile...";
    int stack = 0;
    int i;

    pm_progname = argv[0];

    argn = 1;

/* Create lists for file data (dynamic allocation, since there can be an
 * indeterminate number of files)
 */

    pixel_list = (pixel ***) malloc(sizeof(pixel **));
    rows_list = (int *) malloc(sizeof(int));
    cols_list = (int *) malloc(sizeof(int));
    maxval_list = (pixval *) malloc(sizeof(pixval));

    if ( argn == argc )
	pm_usage( usage );

    if ( strcmp(argv[argn], "-h") == 0 ) {
	stack = 0;
	argn++;
    }
    else if ( strcmp(argv[argn], "-v") == 0) {
	stack = 1;
	argn++;
    }

    if ( argn == argc )
	pm_usage( usage );

/* Read all files */
    num_files = 0;
    while ( argn != argc )
	{
	ifd = pm_openr( argv[argn] );
	num_files++;
	argn++;

        ppm_pbmmaxval = 255;	/* use larger value for better results */
        pixels = ppm_readppm( ifd, &cols, &rows, &maxval );

        pm_close( ifd );

/* Copy data to information arrays (realloc to add new record) */

	pixel_list = (pixel ***) realloc(pixel_list,
					 sizeof(pixel **) * num_files);
	rows_list = (int *) realloc(rows_list, sizeof(int) * num_files);
	cols_list = (int *) realloc(cols_list, sizeof(int) * num_files);
	maxval_list = (pixval *) realloc(maxval_list,
					 sizeof(pixval) * num_files);

	pixel_list[num_files - 1] = pixels;
	rows_list[num_files - 1] = rows;
	cols_list[num_files - 1] = cols;
	maxval_list[num_files - 1] = maxval;
	}

/* After reading in all the files, find the new width and height.  If stack
 * is true, then the images are being stacked on top of each other -- width
 * is the maximum of all widths, height is the sum of the heights.  If stack
 * is false, then put images beside each other -- width is the sum of the
 * widths, and height is the sum of the heights.
 */

    newcols = newrows = 0;
    for (i = 0; i < num_files; i++)
	{
	if (stack)
	    {
	    if (newcols < cols_list[i])
		newcols = cols_list[i];
	    newrows += rows_list[i];
	    }
	else
	    {
	    if (newrows < rows_list[i])
		newrows = rows_list[i];
	    newcols += cols_list[i];
	    }
	if (maxval < maxval_list[i])
	    maxval = maxval_list[i];
	}

/* Call the appropriate Write routine -- WriteStack, or WriteSide -- to write
 * the merged PPM file.
 */

    if (stack)
	{

/* Find the left-side padding for each file first */

	pad_list = (int *) malloc(sizeof(int) * num_files);
	for (i = 0; i < num_files; i++)
	    if (cols_list[i] < newcols)
		pad_list[i] = (newcols + 1 - cols_list[i]) / 2;
	    else
		pad_list[i] = 0;

	WriteStack(pixel_list, cols_list, rows_list, pad_list,
			       newcols, newrows, maxval, num_files);
	}
    else
	{

/* Find the top-side padding for each file first */

	pad_list = (int *) malloc(sizeof(int) * num_files);
	for (i = 0; i < num_files; i++)
	    if (rows_list[i] < newrows)
		pad_list[i] = (newrows + 1 - rows_list[i]) / 2;
	    else
		pad_list[i] = 0;
	WriteSide(pixel_list, cols_list, rows_list, pad_list,
			      newcols, newrows, maxval, num_files);
	}

    exit(0);
    }


/* WriteStack writes each image, one on top of each other.  Simply write out
 * each image sequentially, with padding as required to get a consistent
 * width.
 */

void WriteStack(pix_list, cols_list, rows_list, pad_list,
		newcols, newrows, maxval, count)
pixel ***pix_list;
int *cols_list;
int *rows_list;
int *pad_list;
int newcols;
int newrows;
pixval maxval;
int count;
    {
    int file, col, row;
    pixel *newrow, *srcP, *destP, bgpixel;

    ppm_writeppminit( stdout, newcols, newrows, maxval );
    newrow = ppm_allocrow(newcols);
    
    for (file = 0; file < count; file++)
	{

/* Calculate the background pixel to use for filling (if pad is non-zero) */

	bgpixel = ppm_backgroundpixel(pix_list[file],
				      cols_list[file],
				      rows_list[file]);
	for (row = 0; row < rows_list[file]; row++)
	    {
	    destP = newrow;
	    srcP = pix_list[file][row];
	    for( col = 0; col < pad_list[file]; col++ )	    /* Add left pad */
		*destP++ = bgpixel;

	    for(col = 0; col < cols_list[file]; col++)
		*destP++ = *srcP++;

	    for(col = cols_list[file]; col < newcols - pad_list[file]; col++)
		*destP++ = bgpixel;			    /* Add right pad */

	    ppm_writeppmrow( stdout, newrow, newcols, maxval );
	    }
	}
    }


/* WriteSide writes the images side-by-side.  This requires appending scan
 * lines from each file together to produce an output scanline.  Also requires
 * adding a blank scanline for top and bottom padding to get a consistent
 * height.
 */

void WriteSide(pix_list, cols_list, rows_list, pad_list,
	       newcols, newrows, maxval, count)
pixel ***pix_list;
int *cols_list;
int *rows_list;
int *pad_list;
int newcols;
int newrows;
pixval maxval;
int count;
    {
    int file, col, row;
    pixel *newrow, *srcP, *destP, bgpixel;

    ppm_writeppminit( stdout, newcols, newrows, maxval );
    newrow = ppm_allocrow(newcols);

    for (row = 0; row < newrows; row++)
	{
	destP = newrow;
	for (file = 0; file < count; file++)
	    {

/* Check to see if we are in the pad region, either top or bottom. */

	    if ((row < pad_list[file]) ||
		(row >= rows_list[file] + pad_list[file]))
		{

/* Fill with the background pixel for a pad. */

		bgpixel = ppm_backgroundpixel( pix_list[file],
					       cols_list[file],
					       rows_list[file] );
		for (col = 0; col < cols_list[file]; col++)
		    *destP++ = bgpixel;
		}
	    else
		{

/* Copy the appropriate source row (absolute row number minus the number of
 * padding rows required).
 */

		srcP = pix_list[file][row - pad_list[file]];
		for (col = 0; col < cols_list[file]; col++)
		    *destP++ = *srcP++;
		}
	    }

	ppm_writeppmrow( stdout, newrow, newcols, maxval );
	}
    }
@EOF

chmod 644 ppmmerge.c

echo x - ppmoverlay.c
cat >ppmoverlay.c <<'@EOF'
/* ppmoverlay - overlay one ppm file over the top of another.
**
** Written 3/90 by Bill Turner, heavily leveraged from code by Jef Poskanzer,
** hence the copyright below.
**
** Copyright (C) 1989 by Jef Poskanzer.
**
** Permission to use, copy, modify, and distribute this software and its
** documentation for any purpose and without fee is hereby granted, provided
** that the above copyright notice appear in all copies and that both that
** copyright notice and this permission notice appear in supporting
** documentation.  This software is provided "as is" without express or
** implied warranty.
*/

#include <stdio.h>
#include "ppm.h"

#define UNSPECIFIED 0
#define LEFT 1
#define CENTER 2
#define RIGHT 3

#define TOP 1
#define BOTTOM 3

main( argc, argv )
int argc;
char *argv[];
    {
    FILE *ifd, *bfd;
    pixel **pixels, **backpixels, *newpixelrow;
    register pixel *sP, *bP, *dP;
    int argn, rows, cols, backrows, backcols, row, col;
    int topborder, bottomborder, leftborder, rightborder, minborder;
    int brow, bcol;
    int valign, halign;
    pixval maxval, backmax;
    char *usage = "[-top | -vcenter | -bottom] [-left | -hcenter |
-right] [-border #] ppmfile [ppmbackground]";

    pm_progname = argv[0];

    argn = 1;

    if ( argc < 2 )
	pm_usage( usage );

    valign = halign = 0;
    topborder = bottomborder = leftborder = rightborder = minborder = 0;

    while ( argn + 1 < argc && argv[argn][0] == '-' )
	{
	if (strcmp(argv[argn], "-top")  == 0)
	    {
	    if ( valign )
		pm_error("only one of -top/-vcenter/-bottom may be specified",
			0,0,0,0,0);
		valign = TOP;
	    }
	else if (strcmp(argv[argn], "-vcenter") == 0)
	    {
	    if ( valign )
		pm_error("only one of -top/-vcenter/-bottom may be specified",
			0,0,0,0,0);
		valign = CENTER;
	    }
	else if (strcmp(argv[argn], "-bottom") == 0)
	    {
	    if ( valign )
		pm_error("only one of -top/-vcenter/-bottom may be specified",
			0,0,0,0,0);
		valign = BOTTOM; 
	    }
	else if (strcmp(argv[argn], "-left") == 0)
	    {
	    if ( halign )
		pm_error("only one of -left/-hcenter/-right may be specified",
			0,0,0,0,0);
		halign = LEFT;
	    }
	else if (strcmp(argv[argn], "-hcenter") == 0)
	    {
	    if ( halign )
		pm_error("only one of -left/-hcenter/-right may be specified",
			0,0,0,0,0);
		halign = CENTER;
	    }
	else if (strcmp(argv[argn], "-right") == 0)
	    {
	    if ( halign )
		pm_error("only one of -left/-hcenter/-right may be specified",
			0,0,0,0,0);
		halign = RIGHT;
	    }
	else if (strcmp(argv[argn], "-border") == 0)
	    {
	    if ( sscanf( argv[argn+1], "%d", &minborder) != 1)
		pm_usage( usage );
	    if ( minborder < 0)
		pm_error( "border width must be greater than 0", 0,0,0,0,0 );
	    argn++;
	    }
	else
	    pm_usage( usage );
	argn++;
	}

    if (argn == argc)
	pm_usage( usage );

    ifd = pm_openr( argv[argn] );
    argn++;

    if ( argn != argc )
	{
	bfd = pm_openr( argv[argn] );
	argn++;
	}
    else
	bfd = stdin;

    if ( argn != argc )
	pm_usage( usage );

    ppm_pbmmaxval = 255;	/* use larger value for better results */
    pixels = ppm_readppm( ifd, &cols, &rows, &maxval );

    pm_close( ifd );

    backpixels = ppm_readppm( bfd, &backcols, &backrows, &backmax );

/* Calculate the borders based on valign, halign, and minborder.  Also make
 * sure that the overlayed image will fit on the background with the 
 * constraints specified.
 */

    switch (halign)
	{
	case LEFT:
	    leftborder = minborder;
	    rightborder = backcols - cols - leftborder;
	    break;

	case UNSPECIFIED:
	case CENTER:
	    leftborder = (backcols - cols + 1) / 2;
	    rightborder = backcols - cols - leftborder;
	    break;

	case RIGHT:
	    rightborder = minborder;
	    leftborder = backcols - cols - rightborder;
	    break;
	}

    if ((leftborder < minborder) || (rightborder < minborder))
	pm_error( "picture is too large to overlay.  Try larger
background or smaller border", 0,0,0,0,0);

    switch (valign)
	{
	case TOP:
	    topborder = minborder;
	    bottomborder = backrows - rows - topborder;
	    break;

	case UNSPECIFIED:
	case CENTER:
	    topborder = (backrows - rows + 1) / 2;
	    bottomborder = backrows - rows - topborder;
	    break;

	case BOTTOM:
	    bottomborder = minborder;
	    topborder = backrows - rows - bottomborder;
	    break;
	}

    if ((topborder < minborder) || (bottomborder < minborder))
	pm_error( "picture is too large to overlay.  Try larger
background or smaller border", 0,0,0,0,0);


    ppm_writeppminit( stdout, backcols, backrows, maxval );
    newpixelrow = ppm_allocrow( backcols );

/* For topborder, simply copy the background row to the output. */

    for ( row = 0, brow = 0; row < topborder; row++, brow++ )
	{
	for ( col = 0, bP = backpixels[brow], dP = newpixelrow;
	      col < backcols;
	      col++ )
	    *dP++ = *bP++;
		
	ppm_writeppmrow( stdout, newpixelrow, backcols, maxval );
	}

/* For the rows that overlay, copy the left border colmuns from the background,
 * followed by the overlay row, followed by the right border columns from the
 * background.
 */

    for ( row = 0; row < rows; row++, brow++ )
	{
	for ( col = 0, bP = backpixels[brow], dP = newpixelrow;
	      col < leftborder;
	      col++ )
	    *dP++ = *bP++;

	for ( col = 0, sP = pixels[row];
	      col < cols;
	      col++, bP++ )
	    *dP++ = *sP++;

	for ( col = 0; col < rightborder; col++ )
	    *dP++ = *bP++;

	ppm_writeppmrow( stdout, newpixelrow, backcols, maxval );
	}

/* And, for the bottom border rows, simply copy from the background. */

    for ( row = 0; row < bottomborder; row++, brow++ )
	{
	for ( col = 0, bP = backpixels[brow], dP = newpixelrow;
	      col < backcols;
	      col++ )
	    *dP++ = *bP++;
		
	ppm_writeppmrow( stdout, newpixelrow, backcols, maxval );
	}

    exit(0);
    }
@EOF

chmod 644 ppmoverlay.c

exit 0


