Newsgroups: comp.sources.misc From: jef@well.sf.ca.us (Jef Poskanzer) Subject: REPOST: v23i059: pbmplus - Extended Portable Bitmap Toolkit, Part24/24 Message-ID: <1991Oct17.041650.15321@sparky.imd.sterling.com> X-Md4-Signature: 79730598ae9bb6a4ee65e2d820d7fbb2 Date: Thu, 17 Oct 1991 04:16:50 GMT Approved: kent@sparky.imd.sterling.com Submitted-by: jef@well.sf.ca.us (Jef Poskanzer) Posting-number: Volume 23, Issue 59 Archive-name: pbmplus/part24 Environment: UNIX #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # pnm/pnmrotate.c # pnm/pnmrotate.1 # pnm/pnmscale.c # pnm/pnmscale.1 # pnm/pnmshear.c # pnm/pnmshear.1 # pnm/pnmdepth.c # pnm/pnmdepth.1 # pnm/pnmtops.c # pnm/pnmtops.1 # This archive created: Fri Sep 27 17:50:58 1991 # By: Jef Poskanzer (Acme Software) export PATH; PATH=/bin:$PATH if test ! -d 'pnm' then echo shar: creating directory "'pnm'" mkdir 'pnm' fi echo shar: extracting "'pnm/pnmrotate.c'" '(9792 characters)' if test -f 'pnm/pnmrotate.c' then echo shar: will not over-write existing file "'pnm/pnmrotate.c'" else sed 's/^X//' << \SHAR_EOF > 'pnm/pnmrotate.c' X/* pnmrotate.c - read a portable anymap and rotate it by some angle X** X** Copyright (C) 1989, 1991 by Jef Poskanzer. 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 "pnm.h" X#include X#ifndef M_PI X#define M_PI 3.14159265358979323846 X#endif /*M_PI*/ X X#define SCALE 4096 X#define HALFSCALE 2048 X Xvoid Xmain( argc, argv ) X int argc; X char* argv[]; X { X FILE* ifp; X xel* xelrow; X xel** temp1xels; X xel** temp2xels; X xel* newxelrow; X register xel* xP; X register xel* nxP; X xel bgxel, prevxel, x; X int argn, rows, cols, format, newformat, newrows; X int tempcols, newcols, yshearjunk, x2shearjunk, row, col, new; X xelval maxval; X int antialias; X float fangle, xshearfac, yshearfac, new0; X int intnew0; X register long fracnew0, omfracnew0; X char* usage = "[-noantialias] [pnmfile]"; X X pnm_init( &argc, argv ); X X argn = 1; X antialias = 1; X X if ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' && X ( argv[argn][1] < '0' || argv[argn][1] > '9' ) ) X { X if ( pm_keymatch( argv[argn], "-antialias", 2 ) ) X antialias = 1; X else if ( pm_keymatch( argv[argn], "-noantialias", 2 ) ) X antialias = 0; X else X pm_usage( usage ); X ++argn; X } X X if ( argn == argc ) X pm_usage( usage ); X if ( sscanf( argv[argn], "%f", &fangle ) != 1 ) X pm_usage( usage ); X ++argn; X if ( fangle < -90.0 || fangle > 90.0 ) X pm_error( "angle must be between -90 and 90" ); X fangle = fangle * M_PI / 180.0; /* convert to radians */ X X xshearfac = tan( fangle / 2.0 ); X if ( xshearfac < 0.0 ) X xshearfac = -xshearfac; X yshearfac = sin( fangle ); X if ( yshearfac < 0.0 ) X yshearfac = -yshearfac; X X if ( argn != argc ) X { X ifp = pm_openr( argv[argn] ); X ++argn; X } X else X ifp = stdin; X X if ( argn != argc ) X pm_usage( usage ); X X pnm_pbmmaxval = PNM_MAXMAXVAL; /* use larger value for better results */ X pnm_readpnminit( ifp, &cols, &rows, &maxval, &format ); X xelrow = pnm_allocrow( cols ); X X /* Promote PBM files to PGM. */ X if ( antialias && PNM_FORMAT_TYPE(format) == PBM_TYPE ) X { X newformat = PGM_TYPE; X pm_message( "promoting from PBM to PGM - use -noantialias to avoid this" ); X } X else X newformat = format; X X tempcols = rows * xshearfac + cols + 0.999999; X yshearjunk = ( tempcols - cols ) * yshearfac; X newrows = tempcols * yshearfac + rows + 0.999999; X x2shearjunk = ( newrows - rows - yshearjunk ) * xshearfac; X newrows -= 2 * yshearjunk; X newcols = newrows * xshearfac + tempcols + 0.999999 - 2 * x2shearjunk; X X bgxel = pnm_backgroundxelrow( xelrow, cols, maxval, format ); X X /* First shear X into temp1xels. */ X temp1xels = pnm_allocarray( tempcols, rows ); X for ( row = 0; row < rows; ++row ) X { X pnm_readpnmrow( ifp, xelrow, cols, maxval, format ); X if ( fangle > 0 ) X new0 = row * xshearfac; X else X new0 = ( rows - row ) * xshearfac; X intnew0 = (int) new0; X X if ( antialias ) X { X fracnew0 = ( new0 - intnew0 ) * SCALE; X omfracnew0 = SCALE - fracnew0; X X for ( col = 0, nxP = temp1xels[row]; col < tempcols; ++col, ++nxP ) X *nxP = bgxel; X X prevxel = bgxel; X for ( col = 0, nxP = &(temp1xels[row][intnew0]), xP = xelrow; X col < cols; ++col, ++nxP, ++xP ) X { X switch ( PNM_FORMAT_TYPE(format) ) X { X case PPM_TYPE: X PPM_ASSIGN( *nxP, X ( fracnew0 * PPM_GETR(prevxel) + omfracnew0 * PPM_GETR(*xP) + HALFSCALE ) / SCALE, X ( fracnew0 * PPM_GETG(prevxel) + omfracnew0 * PPM_GETG(*xP) + HALFSCALE ) / SCALE, X ( fracnew0 * PPM_GETB(prevxel) + omfracnew0 * PPM_GETB(*xP) + HALFSCALE ) / SCALE ); X break; X X default: X PNM_ASSIGN1( *nxP, X ( fracnew0 * PNM_GET1(prevxel) + omfracnew0 * PNM_GET1(*xP) + HALFSCALE ) / SCALE ); X break; X } X prevxel = *xP; X } X if ( fracnew0 > 0 && intnew0 + cols < tempcols ) X { X switch ( PNM_FORMAT_TYPE(format) ) X { X case PPM_TYPE: X PPM_ASSIGN( *nxP, X ( fracnew0 * PPM_GETR(prevxel) + omfracnew0 * PPM_GETR(bgxel) + HALFSCALE ) / SCALE, X ( fracnew0 * PPM_GETG(prevxel) + omfracnew0 * PPM_GETG(bgxel) + HALFSCALE ) / SCALE, X ( fracnew0 * PPM_GETB(prevxel) + omfracnew0 * PPM_GETB(bgxel) + HALFSCALE ) / SCALE ); X break; X X default: X PNM_ASSIGN1( *nxP, X ( fracnew0 * PNM_GET1(prevxel) + omfracnew0 * PNM_GET1(bgxel) + HALFSCALE ) / SCALE ); X break; X } X } X } X else X { X for ( col = 0, nxP = temp1xels[row]; col < intnew0; ++col, ++nxP ) X *nxP = bgxel; X for ( col = 0, xP = xelrow; col < cols; ++col, ++nxP, ++xP ) X *nxP = *xP; X for ( col = intnew0 + cols; col < tempcols; ++col, ++nxP ) X *nxP = bgxel; X } X } X pm_close( ifp ); X pnm_freerow( xelrow ); X X /* Now inverse shear Y from temp1 into temp2. */ X temp2xels = pnm_allocarray( tempcols, newrows ); X for ( col = 0; col < tempcols; ++col ) X { X if ( fangle > 0 ) X new0 = ( tempcols - col ) * yshearfac; X else X new0 = col * yshearfac; X intnew0 = (int) new0; X fracnew0 = ( new0 - intnew0 ) * SCALE; X omfracnew0 = SCALE - fracnew0; X intnew0 -= yshearjunk; X X for ( row = 0; row < newrows; ++row ) X temp2xels[row][col] = bgxel; X X if ( antialias ) X { X prevxel = bgxel; X for ( row = 0; row < rows; ++row ) X { X new = row + intnew0; X if ( new >= 0 && new < newrows ) X { X nxP = &(temp2xels[new][col]); X x = temp1xels[row][col]; X switch ( PNM_FORMAT_TYPE(format) ) X { X case PPM_TYPE: X PPM_ASSIGN( *nxP, X ( fracnew0 * PPM_GETR(prevxel) + omfracnew0 * PPM_GETR(x) + HALFSCALE ) / SCALE, X ( fracnew0 * PPM_GETG(prevxel) + omfracnew0 * PPM_GETG(x) + HALFSCALE ) / SCALE, X ( fracnew0 * PPM_GETB(prevxel) + omfracnew0 * PPM_GETB(x) + HALFSCALE ) / SCALE ); X break; X X default: X PNM_ASSIGN1( *nxP, X ( fracnew0 * PNM_GET1(prevxel) + omfracnew0 * PNM_GET1(x) + HALFSCALE ) / SCALE ); X break; X } X prevxel = x; X } X } X if ( fracnew0 > 0 && intnew0 + rows < newrows ) X { X nxP = &(temp2xels[intnew0 + rows][col]); X switch ( PNM_FORMAT_TYPE(format) ) X { X case PPM_TYPE: X PPM_ASSIGN( *nxP, X ( fracnew0 * PPM_GETR(prevxel) + omfracnew0 * PPM_GETR(bgxel) + HALFSCALE ) / SCALE, X ( fracnew0 * PPM_GETG(prevxel) + omfracnew0 * PPM_GETG(bgxel) + HALFSCALE ) / SCALE, X ( fracnew0 * PPM_GETB(prevxel) + omfracnew0 * PPM_GETB(bgxel) + HALFSCALE ) / SCALE ); X break; X X default: X PNM_ASSIGN1( *nxP, X ( fracnew0 * PNM_GET1(prevxel) + omfracnew0 * PNM_GET1(bgxel) + HALFSCALE ) / SCALE ); X break; X } X } X } X else X { X for ( row = 0; row < rows; ++row ) X { X new = row + intnew0; X if ( new >= 0 && new < newrows ) X temp2xels[new][col] = temp1xels[row][col]; X } X } X } X pnm_freearray( temp1xels, rows ); X X /* Finally, shear X from temp2 into newxelrow. */ X pnm_writepnminit( stdout, newcols, newrows, maxval, newformat, 0 ); X newxelrow = pnm_allocrow( newcols ); X for ( row = 0; row < newrows; ++row ) X { X if ( fangle > 0 ) X new0 = row * xshearfac; X else X new0 = ( newrows - row ) * xshearfac; X intnew0 = (int) new0; X fracnew0 = ( new0 - intnew0 ) * SCALE; X omfracnew0 = SCALE - fracnew0; X intnew0 -= x2shearjunk; X X for ( col = 0, nxP = newxelrow; col < newcols; ++col, ++nxP ) X *nxP = bgxel; X X if ( antialias ) X { X prevxel = bgxel; X for ( col = 0, xP = temp2xels[row]; col < tempcols; ++col, ++xP ) X { X new = intnew0 + col; X if ( new >= 0 && new < newcols ) X { X nxP = &(newxelrow[new]); X switch ( PNM_FORMAT_TYPE(format) ) X { X case PPM_TYPE: X PPM_ASSIGN( *nxP, X ( fracnew0 * PPM_GETR(prevxel) + omfracnew0 * PPM_GETR(*xP) + HALFSCALE ) / SCALE, X ( fracnew0 * PPM_GETG(prevxel) + omfracnew0 * PPM_GETG(*xP) + HALFSCALE ) / SCALE, X ( fracnew0 * PPM_GETB(prevxel) + omfracnew0 * PPM_GETB(*xP) + HALFSCALE ) / SCALE ); X break; X X default: X PNM_ASSIGN1( *nxP, X ( fracnew0 * PNM_GET1(prevxel) + omfracnew0 * PNM_GET1(*xP) + HALFSCALE ) / SCALE ); X break; X } X prevxel = *xP; X } X } X if ( fracnew0 > 0 && intnew0 + tempcols < newcols ) X { X nxP = &(newxelrow[intnew0 + tempcols]); X switch ( PNM_FORMAT_TYPE(format) ) X { X case PPM_TYPE: X PPM_ASSIGN( *nxP, X ( fracnew0 * PPM_GETR(prevxel) + omfracnew0 * PPM_GETR(bgxel) + HALFSCALE ) / SCALE, X ( fracnew0 * PPM_GETG(prevxel) + omfracnew0 * PPM_GETG(bgxel) + HALFSCALE ) / SCALE, X ( fracnew0 * PPM_GETB(prevxel) + omfracnew0 * PPM_GETB(bgxel) + HALFSCALE ) / SCALE ); X break; X X default: X PNM_ASSIGN1( *nxP, X ( fracnew0 * PNM_GET1(prevxel) + omfracnew0 * PNM_GET1(bgxel) + HALFSCALE ) / SCALE ); X break; X } X } X } X else X { X for ( col = 0, xP = temp2xels[row]; col < tempcols; ++col, ++xP ) X { X new = intnew0 + col; X if ( new >= 0 && new < newcols ) X newxelrow[new] = *xP; X } X } X X pnm_writepnmrow( stdout, newxelrow, newcols, maxval, newformat, 0 ); X } X X exit( 0 ); X } SHAR_EOF if test 9792 -ne "`wc -c < 'pnm/pnmrotate.c'`" then echo shar: error transmitting "'pnm/pnmrotate.c'" '(should have been 9792 characters)' fi fi # end of overwriting check if test ! -d 'pnm' then echo shar: creating directory "'pnm'" mkdir 'pnm' fi echo shar: extracting "'pnm/pnmrotate.1'" '(2134 characters)' if test -f 'pnm/pnmrotate.1' then echo shar: will not over-write existing file "'pnm/pnmrotate.1'" else sed 's/^X//' << \SHAR_EOF > 'pnm/pnmrotate.1' X.TH pnmrotate 1 "12 January 1991" X.IX pnmrotate X.SH NAME Xpnmrotate - rotate a portable anymap by some angle X.SH SYNOPSIS X.B pnmrotate X.RB [ -noantialias ] X.I angle X.RI [ pnmfile ] X.SH DESCRIPTION XReads a portable anymap as input. XRotates it by the specified angle Xand produces a portable anymap as output. X.IX rotation XIf the input file is in color, the output will be too, Xotherwise it will be grayscale. XThe angle is in degrees (floating point), measured counter-clockwise. XIt can be negative, but it should be between -90 and 90. XAlso, for rotations greater than 45 degrees you may get better results Xif you first use X.I pnmflip X.IX pnmflip Xto do a 90 degree rotation and then X.I pnmrotate Xless than 45 degrees back the other direction X.PP XThe rotation algorithm is Alan Paeth's three-shear method. XEach shear is implemented by looping over the source pixels and distributing Xfractions to each of the destination pixels. XThis has an "anti-aliasing" effect - it avoids jagged edges and similar Xartifacts. X.IX anti-aliasing XHowever, it also means that the original colors or gray levels in the image Xare modified. XIf you need to keep precisely the same set of colors, you can use the X.B -noantialias Xflag. This does the shearing by moving pixels without changing their values. XIf you want anti-aliasing and don't care about the precise colors, but Xstill need a limited *number* of colors, you can run the result through X.IR ppmquant . X.IX ppmquant X.PP XAll flags can be abbreviated to their shortest unique prefix. X.SH REFERENCES X"A Fast Algorithm for General Raster Rotation" by Alan Paeth, XGraphics Interface '86, pp. 77-81. X.SH "SEE ALSO" Xpnmshear(1), pnmflip(1), pnm(5), ppmquant(1) X.SH AUTHOR XCopyright (C) 1989, 1991 by Jef Poskanzer. 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. SHAR_EOF if test 2134 -ne "`wc -c < 'pnm/pnmrotate.1'`" then echo shar: error transmitting "'pnm/pnmrotate.1'" '(should have been 2134 characters)' fi fi # end of overwriting check if test ! -d 'pnm' then echo shar: creating directory "'pnm'" mkdir 'pnm' fi echo shar: extracting "'pnm/pnmscale.c'" '(11340 characters)' if test -f 'pnm/pnmscale.c' then echo shar: will not over-write existing file "'pnm/pnmscale.c'" else sed 's/^X//' << \SHAR_EOF > 'pnm/pnmscale.c' X/* pnmscale.c - read a portable anymap and scale it X** X** Copyright (C) 1989, 1991 by Jef Poskanzer. 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 "pnm.h" X X#define SCALE 4096 X#define HALFSCALE 2048 X Xvoid Xmain( argc, argv ) X int argc; X char* argv[]; X { X FILE* ifp; X xel* xelrow; X xel* tempxelrow; X xel* newxelrow; X register xel* xP; X register xel* nxP; X int argn, specxscale, specyscale, specxsize, specysize, specxysize; X int rows, cols, format, newformat, rowsread, newrows, newcols; X register int row, col, needtoreadrow; X xelval maxval; X float xscale, yscale; X long sxscale, syscale; X register long fracrowtofill, fracrowleft; X long* rs; X long* gs; X long* bs; X char* usage = " [pnmfile]\n -xsize|width|-ysize|-height [pnmfile]\n -xscale|-yscale [pnmfile]\n -xscale|-xsize|-width -yscale|-ysize|-height [pnmfile]\n -xysize [pnmfile]"; X X pnm_init( &argc, argv ); X X argn = 1; X specxscale = specyscale = specxsize = specysize = specxysize = 0; X X while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) X { X if ( pm_keymatch( argv[argn], "-xscale", 4 ) ) X { X if ( specxscale ) X pm_error( "already specified an x scale" ); X if ( specxsize ) X pm_error( X "only one of -xsize/-width and -xscale may be specified" ); X ++argn; X if ( argn == argc || sscanf( argv[argn], "%f", &xscale ) != 1 ) X pm_usage( usage ); X if ( xscale <= 0.0 ) X pm_error( "x scale must be greater than 0" ); X specxscale = 1; X } X else if ( pm_keymatch( argv[argn], "-yscale", 4 ) ) X { X if ( specyscale ) X pm_error( "already specified a y scale" ); X if ( specysize ) X pm_error( X "only one of -ysize/-height and -yscale may be specified" ); X ++argn; X if ( argn == argc || sscanf( argv[argn], "%f", &yscale ) != 1 ) X pm_usage( usage ); X if ( yscale <= 0.0 ) X pm_error( "y scale must be greater than 0" ); X specyscale = 1; X } X else if ( pm_keymatch( argv[argn], "-xsize", 4 ) || X pm_keymatch( argv[argn], "-width", 2 ) ) X { X if ( specxsize ) X pm_error( "already specified a width" ); X if ( specxscale ) X pm_error( X "only one of -xscale and -xsize/-width may be specified" ); X ++argn; X if ( argn == argc || sscanf( argv[argn], "%d", &newcols ) != 1 ) X pm_usage( usage ); X if ( newcols <= 0 ) X pm_error( "new width must be greater than 0" ); X specxsize = 1; X } X else if ( pm_keymatch( argv[argn], "-ysize", 4 ) || X pm_keymatch( argv[argn], "-height", 2 ) ) X { X if ( specysize ) X pm_error( "already specified a height" ); X if ( specyscale ) X pm_error( X "only one of -yscale and -ysize/-height may be specified" ); X ++argn; X if ( argn == argc || sscanf( argv[argn], "%d", &newrows ) != 1 ) X pm_usage( usage ); X if ( newrows <= 0 ) X pm_error( "new height must be greater than 0" ); X specysize = 1; X } X else if ( pm_keymatch( argv[argn], "-xysize", 3 ) ) X { X if ( specxsize || specysize || specxscale || specyscale ) X pm_error( "can't use -xysize with any other specifiers" ); X ++argn; X if ( argn == argc || sscanf( argv[argn], "%d", &newcols ) != 1 ) X pm_usage( usage ); X ++argn; X if ( argn == argc || sscanf( argv[argn], "%d", &newrows ) != 1 ) X pm_usage( usage ); X if ( newcols <= 0 || newrows <= 0 ) X pm_error( "new width and height must be greater than 0" ); X specxsize = 1; X specysize = 1; X specxysize = 1; X } X else X pm_usage( usage ); X ++argn; X } X X if ( ! ( specxscale || specyscale || specxsize || specysize ) ) X { X /* No flags specified, so a single scale factor is required. */ X if ( argn == argc ) X pm_usage( usage ); X if ( sscanf( argv[argn], "%f", &xscale ) != 1 ) X pm_usage( usage ); X if ( xscale <= 0.0 ) X pm_error( "scale must be greater than 0" ); X ++argn; X yscale = xscale; X specxscale = specyscale = 1; X } X X /* Now get input file. */ X if ( argn != argc ) X { X ifp = pm_openr( argv[argn] ); X ++argn; X } X else X ifp = stdin; X X if ( argn != argc ) X pm_usage( usage ); X X pnm_pbmmaxval = PNM_MAXMAXVAL; /* use larger value for better results */ X pnm_readpnminit( ifp, &cols, &rows, &maxval, &format ); X X /* Promote PBM files to PGM. */ X if ( PNM_FORMAT_TYPE(format) == PBM_TYPE ) X { X newformat = PGM_TYPE; X pm_message( "promoting from PBM to PGM" ); X } X else X newformat = format; X X /* Compute all sizes and scales. */ X if ( specxysize ) X if ( (float) newcols / (float) newrows > (float) cols / (float) rows ) X specxsize = 0; X else X specysize = 0; X X if ( specxsize ) X xscale = (float) newcols / (float) cols; X else if ( specxscale ) X newcols = cols * xscale + 0.999; X X if ( specysize ) X yscale = (float) newrows / (float) rows; X else if ( specyscale ) X newrows = rows * yscale + 0.999; X else X if ( specxsize ) X { X yscale = xscale; X newrows = rows * yscale + 0.999; X } X else X { X yscale = 1.0; X newrows = rows; X } X X if ( ! ( specxsize || specxscale ) ) X if ( specysize ) X { X xscale = yscale; X newcols = cols * xscale + 0.999; X } X else X { X xscale = 1.0; X newcols = cols; X } X X sxscale = xscale * SCALE; X syscale = yscale * SCALE; X X xelrow = pnm_allocrow( cols ); X if ( newrows == rows ) /* shortcut Y scaling if possible */ X tempxelrow = xelrow; X else X tempxelrow = pnm_allocrow( cols ); X rs = (long*) pm_allocrow( cols, sizeof(long) ); X gs = (long*) pm_allocrow( cols, sizeof(long) ); X bs = (long*) pm_allocrow( cols, sizeof(long) ); X rowsread = 0; X fracrowleft = syscale; X needtoreadrow = 1; X for ( col = 0; col < cols; ++col ) X rs[col] = gs[col] = bs[col] = HALFSCALE; X fracrowtofill = SCALE; X X pnm_writepnminit( stdout, newcols, newrows, maxval, newformat, 0 ); X newxelrow = pnm_allocrow( newcols ); X X for ( row = 0; row < newrows; ++row ) X { X /* First scale Y from xelrow into tempxelrow. */ X if ( newrows == rows ) /* shortcut Y scaling if possible */ X { X pnm_readpnmrow( ifp, xelrow, cols, maxval, format ); X } X else X { X while ( fracrowleft < fracrowtofill ) X { X if ( needtoreadrow ) X if ( rowsread < rows ) X { X pnm_readpnmrow( ifp, xelrow, cols, maxval, format ); X ++rowsread; X /* needtoreadrow = 0; */ X } X switch ( PNM_FORMAT_TYPE(format) ) X { X case PPM_TYPE: X for ( col = 0, xP = xelrow; col < cols; ++col, ++xP ) X { X rs[col] += fracrowleft * PPM_GETR( *xP ); X gs[col] += fracrowleft * PPM_GETG( *xP ); X bs[col] += fracrowleft * PPM_GETB( *xP ); X } X break; X X default: X for ( col = 0, xP = xelrow; col < cols; ++col, ++xP ) X gs[col] += fracrowleft * PNM_GET1( *xP ); X break; X } X fracrowtofill -= fracrowleft; X fracrowleft = syscale; X needtoreadrow = 1; X } X /* Now fracrowleft is >= fracrowtofill, so we can produce a row. */ X if ( needtoreadrow ) X if ( rowsread < rows ) X { X pnm_readpnmrow( ifp, xelrow, cols, maxval, format ); X ++rowsread; X needtoreadrow = 0; X } X switch ( PNM_FORMAT_TYPE(format) ) X { X case PPM_TYPE: X for ( col = 0, xP = xelrow, nxP = tempxelrow; X col < cols; ++col, ++xP, ++nxP ) X { X register long r, g, b; X X r = rs[col] + fracrowtofill * PPM_GETR( *xP ); X g = gs[col] + fracrowtofill * PPM_GETG( *xP ); X b = bs[col] + fracrowtofill * PPM_GETB( *xP ); X r /= SCALE; X if ( r > maxval ) r = maxval; X g /= SCALE; X if ( g > maxval ) g = maxval; X b /= SCALE; X if ( b > maxval ) b = maxval; X PPM_ASSIGN( *nxP, r, g, b ); X rs[col] = gs[col] = bs[col] = HALFSCALE; X } X break; X X default: X for ( col = 0, xP = xelrow, nxP = tempxelrow; X col < cols; ++col, ++xP, ++nxP ) X { X register long g; X X g = gs[col] + fracrowtofill * PNM_GET1( *xP ); X g /= SCALE; X if ( g > maxval ) g = maxval; X PNM_ASSIGN1( *nxP, g ); X gs[col] = HALFSCALE; X } X break; X } X fracrowleft -= fracrowtofill; X if ( fracrowleft == 0 ) X { X fracrowleft = syscale; X needtoreadrow = 1; X } X fracrowtofill = SCALE; X } X X /* Now scale X from tempxelrow into newxelrow and write it out. */ X if ( newcols == cols ) /* shortcut X scaling if possible */ X pnm_writepnmrow( stdout, tempxelrow, newcols, maxval, newformat, 0 ); X else X { X register long r, g, b; X register long fraccoltofill, fraccolleft; X register int needcol; X X nxP = newxelrow; X fraccoltofill = SCALE; X r = g = b = HALFSCALE; X needcol = 0; X for ( col = 0, xP = tempxelrow; col < cols; ++col, ++xP ) X { X fraccolleft = sxscale; X while ( fraccolleft >= fraccoltofill ) X { X if ( needcol ) X { X ++nxP; X r = g = b = HALFSCALE; X } X switch ( PNM_FORMAT_TYPE(format) ) X { X case PPM_TYPE: X r += fraccoltofill * PPM_GETR( *xP ); X g += fraccoltofill * PPM_GETG( *xP ); X b += fraccoltofill * PPM_GETB( *xP ); X r /= SCALE; X if ( r > maxval ) r = maxval; X g /= SCALE; X if ( g > maxval ) g = maxval; X b /= SCALE; X if ( b > maxval ) b = maxval; X PPM_ASSIGN( *nxP, r, g, b ); X break; X X default: X g += fraccoltofill * PNM_GET1( *xP ); X g /= SCALE; X if ( g > maxval ) g = maxval; X PNM_ASSIGN1( *nxP, g ); X break; X } X fraccolleft -= fraccoltofill; X fraccoltofill = SCALE; X needcol = 1; X } X if ( fraccolleft > 0 ) X { X if ( needcol ) X { X ++nxP; X r = g = b = HALFSCALE; X needcol = 0; X } X switch ( PNM_FORMAT_TYPE(format) ) X { X case PPM_TYPE: X r += fraccolleft * PPM_GETR( *xP ); X g += fraccolleft * PPM_GETG( *xP ); X b += fraccolleft * PPM_GETB( *xP ); X break; X X default: X g += fraccolleft * PNM_GET1( *xP ); X break; X } X fraccoltofill -= fraccolleft; X } X } X if ( fraccoltofill > 0 ) X { X --xP; X switch ( PNM_FORMAT_TYPE(format) ) X { X case PPM_TYPE: X r += fraccoltofill * PPM_GETR( *xP ); X g += fraccoltofill * PPM_GETG( *xP ); X b += fraccoltofill * PPM_GETB( *xP ); X break; X X default: X g += fraccoltofill * PNM_GET1( *xP ); X break; X } X } X if ( ! needcol ) X { X switch ( PNM_FORMAT_TYPE(format) ) X { X case PPM_TYPE: X r /= SCALE; X if ( r > maxval ) r = maxval; X g /= SCALE; X if ( g > maxval ) g = maxval; X b /= SCALE; X if ( b > maxval ) b = maxval; X PPM_ASSIGN( *nxP, r, g, b ); X break; X X default: X g /= SCALE; X if ( g > maxval ) g = maxval; X PNM_ASSIGN1( *nxP, g ); X break; X } X } X pnm_writepnmrow( stdout, newxelrow, newcols, maxval, newformat, 0 ); X } X } X X pm_close( ifp ); X X exit( 0 ); X } SHAR_EOF if test 11340 -ne "`wc -c < 'pnm/pnmscale.c'`" then echo shar: error transmitting "'pnm/pnmscale.c'" '(should have been 11340 characters)' fi fi # end of overwriting check if test ! -d 'pnm' then echo shar: creating directory "'pnm'" mkdir 'pnm' fi echo shar: extracting "'pnm/pnmscale.1'" '(1883 characters)' if test -f 'pnm/pnmscale.1' then echo shar: will not over-write existing file "'pnm/pnmscale.1'" else sed 's/^X//' << \SHAR_EOF > 'pnm/pnmscale.1' X.TH pnmscale 1 "12 January 1991" X.IX pnmscale X.SH NAME Xpnmscale - scale a portable anymap X.SH SYNOPSIS X.B pnmscale X.I s X.RI [ pnmfile ] X.br X.B pnmscale X.BR -xsize | -width | -ysize | X.BR -height X.I s X.RI [ pnmfile ] X.br X.B pnmscale X.BR -xscale | -yscale X.I s X.RI [ pnmfile ] X.br X.B pnmscale X.BR -xscale | -xsize | -width X.I s X.BR -yscale | -ysize | -height X.I s X.RI [ pnmfile ] X.br X.B pnmscale -xysize X.I x y X.RI [ pnmfile ] X.SH DESCRIPTION XReads a portable anymap as input. XScales it by the specified factor or factors and produces a portable Xanymap as output. X.IX shrinking X.IX enlarging XIf the input file is in color, the output will be too, Xotherwise it will be grayscale. XYou can both enlarge (scale factor > 1) and reduce (scale factor < 1). X.PP XYou can specify one dimension as a pixel size, and the other dimension Xwill be scaled correspondingly. X.PP XYou can specify one dimension as a scale, and the other dimension Xwill not be scaled. X.PP XYou can specify different sizes or scales for each axis. X.PP XOr, you can use the special X.B -xysize Xflag, which fits the image into Xthe specified size without changing the aspect ratio. X.PP XAll flags can be abbreviated to their shortest unique prefix. X.PP XIf you enlarge by a factor of 3 or more, you should probably add a X.I pnmsmooth X.IX pnmsmooth Xstep; otherwise, you can see the original pixels in the resulting image. X.SH "SEE ALSO" Xpbmreduce(1), pnmenlarge(1), pnmsmooth(1), pnm(5) X.SH AUTHOR XCopyright (C) 1989, 1991 by Jef Poskanzer. 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. SHAR_EOF if test 1883 -ne "`wc -c < 'pnm/pnmscale.1'`" then echo shar: error transmitting "'pnm/pnmscale.1'" '(should have been 1883 characters)' fi fi # end of overwriting check if test ! -d 'pnm' then echo shar: creating directory "'pnm'" mkdir 'pnm' fi echo shar: extracting "'pnm/pnmshear.c'" '(4714 characters)' if test -f 'pnm/pnmshear.c' then echo shar: will not over-write existing file "'pnm/pnmshear.c'" else sed 's/^X//' << \SHAR_EOF > 'pnm/pnmshear.c' X/* pnmshear.c - read a portable anymap and shear it by some angle X** X** Copyright (C) 1989, 1991 by Jef Poskanzer. 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 "pnm.h" X#include X#ifndef M_PI X#define M_PI 3.14159265358979323846 X#endif /*M_PI*/ X X#define SCALE 4096 X#define HALFSCALE 2048 X Xvoid Xmain( argc, argv ) X int argc; X char* argv[]; X { X FILE* ifp; X xel* xelrow; X register xel* newxelrow; X register xel* xP; X register xel* nxP; X xel bgxel, prevxel; X int argn, rows, cols, format, newformat, newcols, row, col; X xelval maxval; X int antialias; X float fangle, shearfac, new0; X int intnew0; X register long fracnew0, omfracnew0; X char* usage = "[-noantialias] [pnmfile]"; X X pnm_init( &argc, argv ); X X argn = 1; X antialias = 1; X X if ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' && X ( argv[argn][1] < '0' || argv[argn][1] > '9' ) ) X { X if ( pm_keymatch( argv[argn], "-antialias", 2 ) ) X antialias = 1; X else if ( pm_keymatch( argv[argn], "-noantialias", 2 ) ) X antialias = 0; X else X pm_usage( usage ); X ++argn; X } X X if ( argn == argc ) X pm_usage( usage ); X if ( sscanf( argv[argn], "%f", &fangle ) != 1 ) X pm_usage( usage ); X ++argn; X if ( fangle <= -90.0 || fangle >= 90.0 ) X pm_error( "angle must be between -90 and 90" ); X fangle = fangle * M_PI / 180.0; /* convert to radians */ X shearfac = tan( fangle ); X if ( shearfac < 0.0 ) X shearfac = -shearfac; X X if ( argn != argc ) X { X ifp = pm_openr( argv[argn] ); X ++argn; X } X else X ifp = stdin; X X if ( argn != argc ) X pm_usage( usage ); X X pnm_pbmmaxval = PNM_MAXMAXVAL; /* use larger value for better results */ X pnm_readpnminit( ifp, &cols, &rows, &maxval, &format ); X xelrow = pnm_allocrow( cols ); X X /* Promote PBM files to PGM. */ X if ( antialias && PNM_FORMAT_TYPE(format) == PBM_TYPE ) X { X newformat = PGM_TYPE; X pm_message( "promoting from PBM to PGM - use -noantialias to avoid this" ); X } X else X newformat = format; X X newcols = rows * shearfac + cols + 0.999999; X X pnm_writepnminit( stdout, newcols, rows, maxval, newformat, 0 ); X newxelrow = pnm_allocrow( newcols ); X X bgxel = pnm_backgroundxelrow( xelrow, cols, maxval, format ); X X for ( row = 0; row < rows; ++row ) X { X pnm_readpnmrow( ifp, xelrow, cols, maxval, format ); X X if ( fangle > 0.0 ) X new0 = row * shearfac; X else X new0 = ( rows - row ) * shearfac; X intnew0 = (int) new0; X X if ( antialias ) X { X fracnew0 = ( new0 - intnew0 ) * SCALE; X omfracnew0 = SCALE - fracnew0; X X for ( col = 0, nxP = newxelrow; col < newcols; ++col, ++nxP ) X *nxP = bgxel; X X prevxel = bgxel; X for ( col = 0, nxP = &(newxelrow[intnew0]), xP = xelrow; col < cols; ++col, ++nxP, ++xP ) X { X switch ( PNM_FORMAT_TYPE(format) ) X { X case PPM_TYPE: X PPM_ASSIGN( *nxP, X ( fracnew0 * PPM_GETR(prevxel) + omfracnew0 * PPM_GETR(*xP) + HALFSCALE ) / SCALE, X ( fracnew0 * PPM_GETG(prevxel) + omfracnew0 * PPM_GETG(*xP) + HALFSCALE ) / SCALE, X ( fracnew0 * PPM_GETB(prevxel) + omfracnew0 * PPM_GETB(*xP) + HALFSCALE ) / SCALE ); X break; X X default: X PNM_ASSIGN1( *nxP, X ( fracnew0 * PNM_GET1(prevxel) + omfracnew0 * PNM_GET1(*xP) + HALFSCALE ) / SCALE ); X break; X } X prevxel = *xP; X } X if ( fracnew0 > 0 ) X { X nxP = &(newxelrow[intnew0 + cols]); X switch ( PNM_FORMAT_TYPE(format) ) X { X case PPM_TYPE: X PPM_ASSIGN( *nxP, X ( fracnew0 * PPM_GETR(prevxel) + omfracnew0 * PPM_GETR(bgxel) + HALFSCALE ) / SCALE, X ( fracnew0 * PPM_GETG(prevxel) + omfracnew0 * PPM_GETG(bgxel) + HALFSCALE ) / SCALE, X ( fracnew0 * PPM_GETB(prevxel) + omfracnew0 * PPM_GETB(bgxel) + HALFSCALE ) / SCALE ); X break; X X default: X PNM_ASSIGN1( *nxP, X ( fracnew0 * PNM_GET1(prevxel) + omfracnew0 * PNM_GET1(bgxel) + HALFSCALE ) / SCALE ); X break; X } X } X } X else X { X for ( col = 0, nxP = newxelrow; col < intnew0; ++col, ++nxP ) X *nxP = bgxel; X for ( col = 0, xP = xelrow; col < cols; ++col, ++nxP, ++xP ) X *nxP = *xP; X for ( col = intnew0 + cols; col < newcols; ++col, ++nxP ) X *nxP = bgxel; X } X X pnm_writepnmrow( stdout, newxelrow, newcols, maxval, newformat, 0 ); X } X X pm_close( ifp ); X X exit( 0 ); X } SHAR_EOF if test 4714 -ne "`wc -c < 'pnm/pnmshear.c'`" then echo shar: error transmitting "'pnm/pnmshear.c'" '(should have been 4714 characters)' fi fi # end of overwriting check if test ! -d 'pnm' then echo shar: creating directory "'pnm'" mkdir 'pnm' fi echo shar: extracting "'pnm/pnmshear.1'" '(2131 characters)' if test -f 'pnm/pnmshear.1' then echo shar: will not over-write existing file "'pnm/pnmshear.1'" else sed 's/^X//' << \SHAR_EOF > 'pnm/pnmshear.1' X.TH pnmshear 1 "12 January 1991" X.IX pnmshear X.SH NAME Xpnmshear - shear a portable anymap by some angle X.SH SYNOPSIS X.B pnmshear X.RB [ -noantialias ] X.I angle X.RI [ pnmfile ] X.SH DESCRIPTION XReads a portable anymap as input. XShears it by the specified angle and produces a portable Xanymap as output. X.IX shearing XIf the input file is in color, the output will be too, Xotherwise it will be grayscale. XThe angle is in degrees (floating point), and measures this: X.nf X +-------+ +-------+ X | | |\\ \\ X | OLD | | \\ NEW \\ X | | |an\\ \\ X +-------+ |gle+-------+ X.fi XIf the angle is negative, it shears the other way: X.nf X +-------+ |-an+-------+ X | | |gl/ / X | OLD | |e/ NEW / X | | |/ / X +-------+ +-------+ X.fi XThe angle should not get too close to 90 or -90, or the resulting Xanymap will be unreasonably wide. X.PP XThe shearing is implemented by looping over the source pixels and distributing Xfractions to each of the destination pixels. XThis has an "anti-aliasing" effect - it avoids jagged edges and similar Xartifacts. X.IX anti-aliasing XHowever, it also means that the original colors or gray levels in the image Xare modified. XIf you need to keep precisely the same set of colors, you can use Xthe X.B -noantialias Xflag. This does the shearing by moving pixels without changing their values. XIf you want anti-aliasing and don't care about the precise colors, but Xstill need a limited *number* of colors, you can run the result through X.IR ppmquant . X.IX ppmquant X.PP XAll flags can be abbreviated to their shortest unique prefix. X.SH "SEE ALSO" Xpnmrotate(1), pnmflip(1), pnm(5), ppmquant(1) X.SH AUTHOR XCopyright (C) 1989, 1991 by Jef Poskanzer. 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. SHAR_EOF if test 2131 -ne "`wc -c < 'pnm/pnmshear.1'`" then echo shar: error transmitting "'pnm/pnmshear.1'" '(should have been 2131 characters)' fi fi # end of overwriting check if test ! -d 'pnm' then echo shar: creating directory "'pnm'" mkdir 'pnm' fi echo shar: extracting "'pnm/pnmdepth.c'" '(2249 characters)' if test -f 'pnm/pnmdepth.c' then echo shar: will not over-write existing file "'pnm/pnmdepth.c'" else sed 's/^X//' << \SHAR_EOF > 'pnm/pnmdepth.c' X/* pnmdepth.c - change the maxval in a portable pixmap X** X** Copyright (C) 1989, 1991 by Jef Poskanzer. 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 "pnm.h" X Xstatic xelval newvals[PNM_MAXMAXVAL+1]; X Xvoid Xmain( argc, argv ) X int argc; X char* argv[]; X { X FILE* ifp; X xel* xelrow; X register xel* xP; X int argn, rows, cols, format, newformat, row; X register int col; X xelval maxval, newmaxval; X int i; X char* usage = "newmaxval [pnmfile]"; X X pnm_init( &argc, argv ); X X argn = 1; X X if ( argn == argc ) X pm_usage( usage ); X if ( sscanf( argv[argn], "%d", &i ) != 1 ) X pm_usage( usage ); X newmaxval = i; X ++argn; X if ( newmaxval < 1 ) X pm_error( "newmaxval must be > 1" ); X X if ( argn != argc ) X { X ifp = pm_openr( argv[argn] ); X ++argn; X } X else X ifp = stdin; X X if ( argn != argc ) X pm_usage( usage ); X X pnm_readpnminit( ifp, &cols, &rows, &maxval, &format ); X xelrow = pnm_allocrow( cols ); X X /* Promote PBM files to PGM. */ X if ( PNM_FORMAT_TYPE(format) == PBM_TYPE ) X { X newformat = PGM_TYPE; X pm_message( "promoting from PBM to PGM" ); X } X else X newformat = format; X X for ( i = 0; i <= maxval; ++i ) X newvals[i] = i * newmaxval / maxval; X X pnm_writepnminit( stdout, cols, rows, newmaxval, newformat, 0 ); X X for ( row = 0; row < rows; ++row ) X { X pnm_readpnmrow( ifp, xelrow, cols, maxval, format ); X X switch ( PNM_FORMAT_TYPE(format) ) X { X case PPM_TYPE: X for ( col = 0, xP = xelrow; col < cols; ++col, ++xP ) X PPM_ASSIGN( X *xP, newvals[PPM_GETR(*xP)], newvals[PPM_GETG(*xP)], X newvals[PPM_GETB(*xP)] ); X break; X X default: X for ( col = 0, xP = xelrow; col < cols; ++col, ++xP ) X PNM_ASSIGN1( *xP, newvals[PNM_GET1(*xP)] ); X break; X } X X pnm_writepnmrow( stdout, xelrow, cols, newmaxval, newformat, 0 ); X } X X pm_close( ifp ); X X exit( 0 ); X } SHAR_EOF if test 2249 -ne "`wc -c < 'pnm/pnmdepth.c'`" then echo shar: error transmitting "'pnm/pnmdepth.c'" '(should have been 2249 characters)' fi fi # end of overwriting check if test ! -d 'pnm' then echo shar: creating directory "'pnm'" mkdir 'pnm' fi echo shar: extracting "'pnm/pnmdepth.1'" '(1023 characters)' if test -f 'pnm/pnmdepth.1' then echo shar: will not over-write existing file "'pnm/pnmdepth.1'" else sed 's/^X//' << \SHAR_EOF > 'pnm/pnmdepth.1' X.TH pnmdepth 1 "12 January 1991" X.IX pnmdepth X.SH NAME Xpnmdepth - change the maxval in a portable anymap X.SH SYNOPSIS X.B pnmdepth X.I newmaxval X.RI [ pnmfile ] X.SH DESCRIPTION XReads a portable anymap as input. XScales all the pixel values, and writes out the image with the new maxval. XScaling the colors down to a smaller maxval will result in some loss Xof information. X.PP XBe careful of off-by-one errors when choosing the new maxval. XFor instance, if you want the color values to be five bits wide, Xuse a maxval of 31, not 32. X.SH "SEE ALSO" Xpnm(5), ppmquant(1), ppmdither(1) X.SH AUTHOR XCopyright (C) 1989, 1991 by Jef Poskanzer. 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. SHAR_EOF if test 1023 -ne "`wc -c < 'pnm/pnmdepth.1'`" then echo shar: error transmitting "'pnm/pnmdepth.1'" '(should have been 1023 characters)' fi fi # end of overwriting check if test ! -d 'pnm' then echo shar: creating directory "'pnm'" mkdir 'pnm' fi echo shar: extracting "'pnm/pnmtops.c'" '(13203 characters)' if test -f 'pnm/pnmtops.c' then echo shar: will not over-write existing file "'pnm/pnmtops.c'" else sed 's/^X//' << \SHAR_EOF > 'pnm/pnmtops.c' X/* pnmtops.c - read a portable anymap and produce a PostScript file X** X** Copyright (C) 1989 by Jef Poskanzer. 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 "pnm.h" X X#define MARGIN 0.95 X Xstatic void putinit ARGS(( char* name, int cols, int rows, int padright, int bps, float scale, int dpi, int pagewid, int pagehgt, int format, int rleflag )); Xstatic void putitem ARGS(( void )); Xstatic void putxelval ARGS(( xelval xv )); Xstatic void putrest ARGS(( void )); Xstatic void rleputbuffer ARGS(( void )); Xstatic void rleputitem ARGS(( void )); Xstatic void rleputxelval ARGS(( xelval xv )); Xstatic void rleflush ARGS(( void )); Xstatic void rleputrest ARGS(( void )); X Xvoid Xmain( argc, argv ) X int argc; X char* argv[]; X { X FILE* ifp; X xel* xelrow; X register xel* xP; X int argn, rleflag, rows, cols, format, bps, padright, row, col; X xelval maxval, nmaxval; X float scale, f; X int dpi, pagewid, pagehgt; X char name[100]; X char* cp; X char* usage = "[-rle|-runlength] [-scale ] [-dpi ] [-width ] [-height ] [pnmfile]"; X X pnm_init( &argc, argv ); X X argn = 1; X rleflag = 0; X scale = 1.0; X /* LaserWriter defaults. */ X dpi = 300; X pagewid = 612; X pagehgt = 762; X X /* Check for flags. */ X while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) X { X if ( pm_keymatch( argv[argn], "-rle", 2 ) || X pm_keymatch( argv[argn], "-runlength", 2 ) ) X rleflag = 1; X else if ( pm_keymatch( argv[argn], "-norle", 2 ) || X pm_keymatch( argv[argn], "-norunlength", 2 ) ) X rleflag = 0; X else if ( pm_keymatch( argv[argn], "-scale", 2 ) ) X { X ++argn; X if ( argn == argc || sscanf( argv[argn], "%f", &scale ) != 1 ) X pm_usage( usage ); X } X else if ( pm_keymatch( argv[argn], "-dpi", 2 ) ) X { X ++argn; X if ( argn == argc || sscanf( argv[argn], "%d", &dpi ) != 1 ) X pm_usage( usage ); X } X else if ( pm_keymatch( argv[argn], "-width", 2 ) ) X { X ++argn; X if ( argn == argc || sscanf( argv[argn], "%f", &f ) != 1 ) X pm_usage( usage ); X pagewid = f * 72.0; X } X else if ( pm_keymatch( argv[argn], "-height", 2 ) ) X { X ++argn; X if ( argn == argc || sscanf( argv[argn], "%f", &f ) != 1 ) X pm_usage( usage ); X pagehgt = f * 72.0; X } X else X pm_usage( usage ); X ++argn; X } X X if ( argn < argc ) X { X ifp = pm_openr( argv[argn] ); X strcpy( name, argv[argn] ); X if ( strcmp( name, "-" ) == 0 ) X strcpy( name, "noname" ); X X if ( ( cp = index( name, '.' ) ) != 0 ) X *cp = '\0'; X ++argn; X } X else X { X ifp = stdin; X strcpy( name, "noname" ); X } X X if ( argn != argc ) X pm_usage( usage ); X X pnm_readpnminit( ifp, &cols, &rows, &maxval, &format ); X xelrow = pnm_allocrow( cols ); X X /* Figure out bps. */ X bps = pm_maxvaltobits( (int) maxval ); X if ( bps > 2 && bps < 4 ) X bps = 4; X else if ( bps > 4 && bps < 8 ) X bps = 8; X else if ( bps > 8 ) X pm_error( "maxval of %d is too large for PostScript", maxval ); X nmaxval = pm_bitstomaxval( bps ); X X /* Compute padding to round cols * bps up to the nearest multiple of 8. */ X padright = ( ( ( cols * bps + 7 ) / 8 ) * 8 - cols * bps ) / bps; X X putinit( X name, cols, rows, padright, bps, scale, dpi, pagewid, pagehgt, format, X rleflag ); X for ( row = 0; row < rows; ++row ) X { X pnm_readpnmrow( ifp, xelrow, cols, maxval, format ); X switch ( PNM_FORMAT_TYPE( format ) ) X { X case PPM_TYPE: X /* Color. */ X for ( col = 0, xP = xelrow; col < cols; ++col, ++xP ) X if ( maxval != nmaxval ) X PPM_DEPTH( *xP, *xP, maxval, nmaxval ); X /* First red. */ X for ( col = 0, xP = xelrow; col < cols; ++col, ++xP ) X if ( rleflag ) X rleputxelval( PPM_GETR( *xP ) ); X else X putxelval( PPM_GETR( *xP ) ); X for ( col = 0; col < padright; ++col ) X if ( rleflag ) X rleputxelval( 0 ); X else X putxelval( 0 ); X /* Then green. */ X for ( col = 0, xP = xelrow; col < cols; ++col, ++xP ) X if ( rleflag ) X rleputxelval( PPM_GETG( *xP ) ); X else X putxelval( PPM_GETG( *xP ) ); X for ( col = 0; col < padright; ++col ) X if ( rleflag ) X rleputxelval( 0 ); X else X putxelval( 0 ); X /* And blue. */ X for ( col = 0, xP = xelrow; col < cols; ++col, ++xP ) X if ( rleflag ) X rleputxelval( PPM_GETB( *xP ) ); X else X putxelval( PPM_GETB( *xP ) ); X for ( col = 0; col < padright; ++col ) X if ( rleflag ) X rleputxelval( 0 ); X else X putxelval( 0 ); X if ( rleflag ) X rleflush(); X break; X default: X /* Grayscale. */ X for ( col = 0, xP = xelrow; col < cols; ++col, ++xP ) X { X if ( maxval != nmaxval ) X PNM_ASSIGN1( *xP, (int) PNM_GET1(*xP) * nmaxval / maxval ); X if ( rleflag ) X rleputxelval( PNM_GET1( *xP ) ); X else X putxelval( PNM_GET1( *xP ) ); X } X for ( col = 0; col < padright; ++col ) X if ( rleflag ) X rleputxelval( 0 ); X else X putxelval( 0 ); X if ( rleflag ) X rleflush(); X break; X } X } X X pm_close( ifp ); X X if ( rleflag ) X rleputrest(); X else X putrest(); X X exit( 0 ); X } X Xstatic int bitspersample, item, bitsperitem, bitshift, itemsperline, items; Xstatic int rleitem, rlebitsperitem, rlebitshift; Xstatic int repeat, itembuf[128], count, repeatitem, repeatcount; X X#if __STDC__ Xstatic void Xputinit( char* name, int cols, int rows, int padright, int bps, float scale, int dpi, int pagewid, int pagehgt, int format, int rleflag ) X#else /*__STDC__*/ Xstatic void Xputinit( name, cols, rows, padright, bps, scale, dpi, pagewid, pagehgt, format, rleflag ) X char* name; X int cols, rows, padright, bps; X float scale; X int dpi, pagewid, pagehgt, format, rleflag; X#endif /*__STDC__*/ X { X int devpix; X float pixfac, scols, srows, llx, lly; X X devpix = dpi / 72.0 + 0.5; /* device pixels per unit, approx. */ X pixfac = 72.0 / dpi * devpix; /* 1, approx. */ X scols = scale * cols * pixfac; X srows = scale * rows * pixfac; X if ( scols > pagewid * MARGIN || srows > pagehgt * MARGIN ) X { X if ( scols > pagewid * MARGIN ) X { X scale *= pagewid / scols * MARGIN; X scols = scale * cols * pixfac; X srows = scale * rows * pixfac; X } X if ( srows > pagehgt * MARGIN ) X { X scale *= pagehgt / srows * MARGIN; X scols = scale * cols * pixfac; X srows = scale * rows * pixfac; X } X pm_message( X "warning, image too large for page, rescaling to %g", scale ); X } X llx = ( pagewid - scols ) / 2; X lly = ( pagehgt - srows ) / 2; X X printf( "%%!PS-Adobe-2.0 EPSF-2.0\n" ); X printf( "%%%%Creator: pnmtops\n" ); X printf( "%%%%Title: %s.ps\n", name ); X printf( "%%%%Pages: 1\n" ); X printf( X "%%%%BoundingBox: %d %d %d %d\n", X (int) llx, (int) lly, X (int) ( llx + scols + 0.5 ), (int) ( lly + srows + 0.5 ) ); X printf( "%%%%EndComments\n" ); X if ( rleflag ) X { X printf( "/rlestr1 1 string def\n" ); X printf( "/readrlestring {\n" ); /* s -- nr */ X printf( " /rlestr exch def\n" ); /* - */ X printf( " currentfile rlestr1 readhexstring pop\n" ); /* s1 */ X printf( " 0 get\n" ); /* c */ X printf( " dup 127 le {\n" ); /* c */ X printf( " currentfile rlestr 0\n" ); /* c f s 0 */ X printf( " 4 3 roll\n" ); /* f s 0 c */ X printf( " 1 add getinterval\n" ); /* f s */ X printf( " readhexstring pop\n" ); /* s */ X printf( " length\n" ); /* nr */ X printf( " } {\n" ); /* c */ X printf( " 256 exch sub dup\n" ); /* n n */ X printf( " currentfile rlestr1 readhexstring pop\n" );/* n n s1 */ X printf( " 0 get\n" ); /* n n c */ X printf( " exch 0 exch 1 exch 1 sub {\n" ); /* n c 0 1 n-1*/ X printf( " rlestr exch 2 index put\n" ); X printf( " } for\n" ); /* n c */ X printf( " pop\n" ); /* nr */ X printf( " } ifelse\n" ); /* nr */ X printf( "} bind def\n" ); X printf( "/readstring {\n" ); /* s -- s */ X printf( " dup length 0 {\n" ); /* s l 0 */ X printf( " 3 copy exch\n" ); /* s l n s n l*/ X printf( " 1 index sub\n" ); /* s l n s n r*/ X printf( " getinterval\n" ); /* s l n ss */ X printf( " readrlestring\n" ); /* s l n nr */ X printf( " add\n" ); /* s l n */ X printf( " 2 copy le { exit } if\n" ); /* s l n */ X printf( " } loop\n" ); /* s l l */ X printf( " pop pop\n" ); /* s */ X printf( "} bind def\n" ); X } X else X { X printf( "/readstring {\n" ); /* s -- s */ X printf( " currentfile exch readhexstring pop\n" ); X printf( "} bind def\n" ); X } X if ( PNM_FORMAT_TYPE( format ) == PPM_TYPE ) X { X printf( "/rpicstr %d string def\n", ( cols + padright ) * bps / 8 ); X printf( "/gpicstr %d string def\n", ( cols + padright ) * bps / 8 ); X printf( "/bpicstr %d string def\n", ( cols + padright ) * bps / 8 ); X } X else X printf( "/picstr %d string def\n", ( cols + padright ) * bps / 8 ); X printf( "%%%%EndProlog\n" ); X printf( "%%%%Page: 1 1\n" ); X printf( "gsave\n" ); X printf( "%g %g translate\n", llx, lly ); X printf( "%g %g scale\n", scols, srows ); X printf( "%d %d %d\n", cols, rows, bps ); X printf( "[ %d 0 0 -%d 0 %d ]\n", cols, rows, rows ); X if ( PNM_FORMAT_TYPE( format ) == PPM_TYPE ) X { X printf( "{ rpicstr readstring }\n" ); X printf( "{ gpicstr readstring }\n" ); X printf( "{ bpicstr readstring }\n" ); X printf( "true 3\n" ); X printf( "colorimage\n" ); X pm_message( "writing color PostScript..." ); X } X else X { X printf( "{ picstr readstring }\n" ); X printf( "image\n" ); X } X X bitspersample = bps; X itemsperline = items = 0; X if ( rleflag ) X { X rleitem = 0; X rlebitsperitem = 0; X rlebitshift = 8 - bitspersample; X repeat = 1; X count = 0; X } X else X { X item = 0; X bitsperitem = 0; X bitshift = 8 - bitspersample; X } X } X Xstatic void Xputitem() X { X char* hexits = "0123456789abcdef"; X X if ( itemsperline == 30 ) X { X putchar( '\n' ); X itemsperline = 0; X } X putchar( hexits[item >> 4] ); X putchar( hexits[item & 15] ); X ++itemsperline; X ++items; X item = 0; X bitsperitem = 0; X bitshift = 8 - bitspersample; X } X X#if __STDC__ Xstatic void putxelval( xelval xv ) X#else /*__STDC__*/ Xstatic void Xputxelval( xv ) X xelval xv; X#endif /*__STDC__*/ X { X if ( bitsperitem == 8 ) X putitem(); X item += xv << bitshift; X bitsperitem += bitspersample; X bitshift -= bitspersample; X } X Xstatic void Xputrest() X { X if ( bitsperitem > 0 ) X putitem(); X printf( "\n" ); X printf( "grestore\n" ); X printf( "showpage\n" ); X printf( "%%%%Trailer\n" ); X } X Xstatic void Xrleputbuffer() X { X int i; X X if ( repeat ) X { X item = 256 - count; X putitem(); X item = repeatitem; X putitem(); X } X else X { X item = count - 1; X putitem(); X for ( i = 0; i < count; ++i ) X { X item = itembuf[i]; X putitem(); X } X } X repeat = 1; X count = 0; X } X Xstatic void Xrleputitem() X { X int i; X X if ( count == 128 ) X rleputbuffer(); X X if ( repeat && count == 0 ) X { /* Still initializing a repeat buf. */ X itembuf[count] = repeatitem = rleitem; X ++count; X } X else if ( repeat ) X { /* Repeating - watch for end of run. */ X if ( rleitem == repeatitem ) X { /* Run continues. */ X itembuf[count] = rleitem; X ++count; X } X else X { /* Run ended - is it long enough to dump? */ X if ( count > 2 ) X { /* Yes, dump a repeat-mode buffer and start a new one. */ X rleputbuffer(); X itembuf[count] = repeatitem = rleitem; X ++count; X } X else X { /* Not long enough - convert to non-repeat mode. */ X repeat = 0; X itembuf[count] = repeatitem = rleitem; X ++count; X repeatcount = 1; X } X } X } X else X { /* Not repeating - watch for a run worth repeating. */ X if ( rleitem == repeatitem ) X { /* Possible run continues. */ X ++repeatcount; X if ( repeatcount > 3 ) X { /* Long enough - dump non-repeat part and start repeat. */ X count = count - ( repeatcount - 1 ); X rleputbuffer(); X count = repeatcount; X for ( i = 0; i < count; ++i ) X itembuf[i] = rleitem; X } X else X { /* Not long enough yet - continue as non-repeat buf. */ X itembuf[count] = rleitem; X ++count; X } X } X else X { /* Broken run. */ X itembuf[count] = repeatitem = rleitem; X ++count; X repeatcount = 1; X } X } X X rleitem = 0; X rlebitsperitem = 0; X rlebitshift = 8 - bitspersample; X } X X#if __STDC__ Xstatic void rleputxelval( xelval xv ) X#else /*__STDC__*/ Xstatic void Xrleputxelval( xv ) X xelval xv; X#endif /*__STDC__*/ X { X if ( rlebitsperitem == 8 ) X rleputitem(); X rleitem += xv << rlebitshift; X rlebitsperitem += bitspersample; X rlebitshift -= bitspersample; X } X Xstatic void Xrleflush() X { X if ( rlebitsperitem > 0 ) X rleputitem(); X if ( count > 0 ) X rleputbuffer(); X } X Xstatic void Xrleputrest() X { X rleflush(); X printf( "\n" ); X printf( "grestore\n" ); X printf( "showpage\n" ); X printf( "%%%%Trailer\n" ); X } SHAR_EOF if test 13203 -ne "`wc -c < 'pnm/pnmtops.c'`" then echo shar: error transmitting "'pnm/pnmtops.c'" '(should have been 13203 characters)' fi fi # end of overwriting check if test ! -d 'pnm' then echo shar: creating directory "'pnm'" mkdir 'pnm' fi echo shar: extracting "'pnm/pnmtops.1'" '(2583 characters)' if test -f 'pnm/pnmtops.1' then echo shar: will not over-write existing file "'pnm/pnmtops.1'" else sed 's/^X//' << \SHAR_EOF > 'pnm/pnmtops.1' X.TH pnmtops 1 "26 September 1991" X.IX pnmtops X.SH NAME Xpnmtops - convert portable anymap to PostScript X.SH SYNOPSIS X.B pnmtops X.RB [ -rle | -runlength ] X.RB [ -scale X.IR s ] X.RB [ -dpi X.IR n ] X.RB [ -width X.IR n ] X.RB [ -height X.IR n ] X.RI [ pnmfile ] X.SH DESCRIPTION XReads a portable anymap as input. XProduces Encapsulated PostScript as output. X.IX PostScript X.PP XIf the input file is in color (PPM), a color PostScript file gets Xwritten. XSome PostScript interpreters can't handle color PostScript. XIf you have one of these you will need to run your image through X.I ppmtopgm Xfirst. X.PP XNote that there is no pstopnm Xtool - this transformation is one-way, because a pstopnm tool would Xbe a full-fledged PostScript interpreter, which is beyond the scope Xof this package. XHowever, see the X.I psidtopgm Xtool, which can read grayscale non-runlength PostScript image data. XAlso, if you're willing to install the fairly large GhostScript package, Xit comes with a pstoppm script. X.SH OPTIONS X.PP XThe X.B -scale Xflag controls the scale of the result. The default scale is 1, Xwhich on a 300 dpi printer such as the Apple LaserWriter makes Xthe output look about the same size as the input would if it was displayed Xon a typical 72 dpi screen. XTo get one PNM pixel per 300 dpi printer pixel, use "-scale 0.25". X.PP XThe X.B -rle Xor X.B -runlength Xflag specifies run-length compression. This may save Xtime if the host-to-printer link is slow; but normally the printer's processing Xtime dominates, so X.B -rle Xmakes things slower. X.PP XThe X.B -dpi Xflag lets you specify the dots per inch of your output device. XThe default is 300 dpi. XIn theory PostScript is device-independent and you don't have to Xworry about this, but in practice its raster rendering can have Xunsightly bands if the device pixels and the image pixels aren't Xin sync. X.PP XThe X.B -width Xand X.B -height Xflags let you specify the size of the page. XThe default is 8.5 inches by 11 inches. X.PP XAll flags can be abbreviated to their shortest unique prefix. X.SH "SEE ALSO" Xpnm(5), psidtopgm(1) X.SH BUGS XIt ought to automatically rotate to landscape mode if that would fit Xthe image better. X.SH AUTHOR XCopyright (C) 1989, 1991 by Jef Poskanzer. 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. SHAR_EOF if test 2583 -ne "`wc -c < 'pnm/pnmtops.1'`" then echo shar: error transmitting "'pnm/pnmtops.1'" '(should have been 2583 characters)' fi fi # end of overwriting check # End of shell archive exit 0 exit 0 # Just in case... -- Kent Landfield INTERNET: kent@sparky.IMD.Sterling.COM Sterling Software, IMD UUCP: uunet!sparky!kent Phone: (402) 291-8300 FAX: (402) 291-4362 Please send comp.sources.misc-related mail to kent@uunet.uu.net.