Newsgroups: comp.sources.misc From: jef@well.sf.ca.us (Jef Poskanzer) Subject: REPOST: v23i058: pbmplus - Extended Portable Bitmap Toolkit, Part23/24 Message-ID: <1991Oct17.041617.15253@sparky.imd.sterling.com> X-Md4-Signature: 14e29e91e0b9e3f6c7af33773a10d67b Date: Thu, 17 Oct 1991 04:16:17 GMT Approved: kent@sparky.imd.sterling.com Submitted-by: jef@well.sf.ca.us (Jef Poskanzer) Posting-number: Volume 23, Issue 58 Archive-name: pbmplus/part23 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/x10wd.h # pnm/pnmcrop.c # pnm/pnmcrop.1 # pnm/pnmgamma.c # pnm/pnmgamma.1 # pnm/pnmarith.c # pnm/pnmarith.1 # pnm/pnmconvol.c # pnm/pnmconvol.1 # pnm/pnmsmooth # pnm/pnmsmooth.1 # pnm/tifftopnm.c # pnm/tifftopnm.1 # pnm/pnmtotiff.c # pnm/pnmtotiff.1 # This archive created: Fri Sep 27 17:50:55 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/x10wd.h'" '(1011 characters)' if test -f 'pnm/x10wd.h' then echo shar: will not over-write existing file "'pnm/x10wd.h'" else sed 's/^X//' << \SHAR_EOF > 'pnm/x10wd.h' X/* x10wd.h - the following defs are taken from various X10 header files X*/ X X#ifndef _X10WD_H_ X#define _X10WD_H_ X X#define XYFormat 0 X#define ZFormat 1 X X#define X10WD_FILE_VERSION 6 Xtypedef struct { X int header_size; /* Size of the entire file header (bytes). */ X int file_version; /* X10WD_FILE_VERSION */ X int display_type; /* Display type. */ X int display_planes; /* Number of display planes. */ X int pixmap_format; /* Pixmap format. */ X int pixmap_width; /* Pixmap width. */ X int pixmap_height; /* Pixmap height. */ X short window_width; /* Window width. */ X short window_height; /* Window height. */ X short window_x; /* Window upper left X coordinate. */ X short window_y; /* Window upper left Y coordinate. */ X short window_bdrwidth; /* Window border width. */ X short window_ncolors; /* number of Color entries in this window */ X } X10WDFileHeader; X Xtypedef struct { X int pixel; X unsigned short red, green, blue; X } X10Color; X X#endif /*_X10WD_H_*/ SHAR_EOF if test 1011 -ne "`wc -c < 'pnm/x10wd.h'`" then echo shar: error transmitting "'pnm/x10wd.h'" '(should have been 1011 characters)' fi fi # end of overwriting check if test ! -d 'pnm' then echo shar: creating directory "'pnm'" mkdir 'pnm' fi echo shar: extracting "'pnm/pnmcrop.c'" '(3592 characters)' if test -f 'pnm/pnmcrop.c' then echo shar: will not over-write existing file "'pnm/pnmcrop.c'" else sed 's/^X//' << \SHAR_EOF > 'pnm/pnmcrop.c' X/* pnmcrop.c - crop a portable anymap X** X** Copyright (C) 1988 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 Xvoid Xmain( argc, argv ) X int argc; X char* argv[]; X { X FILE* ifp; X xel** xels; X register xel* xP; X xel background; X xelval maxval; X int argn, format, backdefault, backblack; X int rows, cols, row, col, newrows, newcols; X int top, bottom, left, right; X char* usage = "[-white|-black] [pnmfile]"; X X pnm_init( &argc, argv ); X X argn = 1; X backdefault = 1; X X /* Check for flags. */ X if ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) X { X if ( pm_keymatch( argv[argn], "-white", 2 ) ) X { X backdefault = 0; X backblack = 0; X } X else if ( pm_keymatch( argv[argn], "-black", 2 ) ) X { X backdefault = 0; X backblack = 1; X } X else X pm_usage( usage ); X ++argn; X } 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 xels = pnm_readpnm( ifp, &cols, &rows, &maxval, &format ); X pm_close( ifp ); X X if ( backdefault ) X background = pnm_backgroundxel( xels, cols, rows, maxval, format ); X else X if ( backblack ) X background = pnm_blackxel( maxval, format ); X else X background = pnm_whitexel( maxval, format ); X X /* Find first non-background line. */ X for ( top = 0; top < rows; top++ ) X for ( col = 0, xP = xels[top]; col < cols; col++, xP++ ) X if ( ! PNM_EQUAL( *xP, background ) ) X goto gottop; Xgottop: X X /* Find last non-background line. */ X for ( bottom = rows - 1; bottom >= top; bottom-- ) X for ( col = 0, xP = xels[bottom]; col < cols; col++, xP++ ) X if ( ! PNM_EQUAL( *xP, background ) ) X goto gotbottom; Xgotbottom: X X /* Find first non-background column. To avoid massive paging on X ** large anymaps, we use a different loop than the above two cases. */ X left = cols - 1; X for ( row = top; row <= bottom; row++ ) X { X int thisleft; X X for ( thisleft = 0; thisleft < left; thisleft++ ) X if ( ! PNM_EQUAL( xels[row][thisleft], background ) ) X { X left = thisleft; X break; X } X } X X /* Find last non-background column. Again, use row-major loop. */ X right = left + 1; X for ( row = top; row <= bottom; row++ ) X { X int thisright; X X for ( thisright = cols - 1; thisright > right; thisright-- ) X if ( ! PNM_EQUAL( xels[row][thisright], background ) ) X { X right = thisright; X break; X } X } X X#define ending(n) (((n) > 1) ? "s" : "") X if ( top > 0 ) X pm_message( "cropping %d row%s off the top", top, ending(top) ); X if ( bottom < rows - 1 ) X pm_message( "cropping %d row%s off the bottom", rows-1-bottom, ending(rows-1-bottom) ); X if ( left > 0 ) X pm_message( "cropping %d col%s off the left", left, ending(left) ); X if ( right < cols - 1 ) X pm_message( "cropping %d col%s off the right", cols-1-right, ending(cols-1-right) ); X X /* Now write out the new anymap. */ X newcols = right - left + 1; X newrows = bottom - top + 1; X pnm_writepnminit( stdout, newcols, newrows, maxval, format, 0 ); X for ( row = top; row <= bottom; row++ ) X pnm_writepnmrow( stdout, &(xels[row][left]), newcols, maxval, format, 0 ); X X exit( 0 ); X } SHAR_EOF if test 3592 -ne "`wc -c < 'pnm/pnmcrop.c'`" then echo shar: error transmitting "'pnm/pnmcrop.c'" '(should have been 3592 characters)' fi fi # end of overwriting check if test ! -d 'pnm' then echo shar: creating directory "'pnm'" mkdir 'pnm' fi echo shar: extracting "'pnm/pnmcrop.1'" '(990 characters)' if test -f 'pnm/pnmcrop.1' then echo shar: will not over-write existing file "'pnm/pnmcrop.1'" else sed 's/^X//' << \SHAR_EOF > 'pnm/pnmcrop.1' X.TH pnmcrop 1 "25 February 1989" X.IX pnmcrop X.SH NAME Xpnmcrop - crop a portable anymap X.SH SYNOPSIS X.B pnmcrop X.RB [ -white | -black ] X.RI [ pnmfile ] X.SH DESCRIPTION XReads a portable anymap as input. XRemoves edges that are the background color, Xand produces a portable anymap as output. X.IX cropping X.SH OPTIONS X.PP XBy default, it makes a guess as to what the background color is. XYou can override the default with the X.B -white Xand X.B -black Xflags. X.PP XAll flags can be abbreviated to their shortest unique prefix. X.SH "SEE ALSO" Xpnmcut(1), pnm(5) X.SH AUTHOR XCopyright (C) 1989 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 990 -ne "`wc -c < 'pnm/pnmcrop.1'`" then echo shar: error transmitting "'pnm/pnmcrop.1'" '(should have been 990 characters)' fi fi # end of overwriting check if test ! -d 'pnm' then echo shar: creating directory "'pnm'" mkdir 'pnm' fi echo shar: extracting "'pnm/pnmgamma.c'" '(4686 characters)' if test -f 'pnm/pnmgamma.c' then echo shar: will not over-write existing file "'pnm/pnmgamma.c'" else sed 's/^X//' << \SHAR_EOF > 'pnm/pnmgamma.c' X/* pnmgamma.c - perform gamma correction on a portable pixmap X** X** Copyright (C) 1991 by Bill Davidson and 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#include X Xstatic void buildgamma ARGS(( xelval table[], xelval maxval, double gamma )); X Xvoid Xmain( argc, argv ) X int argc; X char* argv[]; X { X FILE* ifp; X xel* xelrow; X register xel* xP; X xelval maxval; X int argn, rows, cols, format, newformat, row; X register int col; X double rgamma, ggamma, bgamma; X xelval* rtable; X xelval* gtable; X xelval* btable; X char *usage = " [pnmfile]\n\t\t [pnmfile]"; X X pnm_init( &argc, argv ); X X argn = 1; X X /* Parse gamma args. */ X if ( argc == 2 || argc == 3 ) X { X rgamma = ggamma = bgamma = atof( argv[argn] ); X ++argn; X } X else if ( argc == 4 || argc == 5 ) X { X rgamma = atof( argv[argn] ); X ++argn; X ggamma = atof( argv[argn] ); X ++argn; X bgamma = atof( argv[argn] ); X ++argn; X } X else X pm_usage( usage ); X X if ( rgamma <= 0.0 || ggamma <= 0.0 || bgamma <= 0.0 ) X pm_usage( usage ); 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. Not that it makes much sense to X ** gamma-correct PBM files. */ X if ( PNM_FORMAT_TYPE(format) == PBM_TYPE ) X { X newformat = PGM_TYPE; X pm_message( "promoting to PGM" ); X } X else X newformat = format; X X if ( rgamma != ggamma || ggamma != bgamma ) X if ( PNM_FORMAT_TYPE(newformat) == PGM_TYPE ) X { X newformat = PPM_TYPE; X pm_message( "promoting to PPM" ); X } X X /* Allocate space for the tables. */ X rtable = (xelval*) malloc( (maxval+1) * sizeof(xelval) ); X gtable = (xelval*) malloc( (maxval+1) * sizeof(xelval) ); X btable = (xelval*) malloc( (maxval+1) * sizeof(xelval) ); X if ( rtable == 0 || gtable == 0 || btable == 0 ) X pm_error( "out of memory" ); X X /* Build the gamma corection tables. */ X buildgamma( rtable, maxval, rgamma ); X buildgamma( gtable, maxval, ggamma ); X buildgamma( btable, maxval, bgamma ); X X pnm_writepnminit( stdout, cols, rows, maxval, newformat, 0 ); X for ( row = 0; row < rows; ++row ) X { X pnm_readpnmrow( ifp, xelrow, cols, maxval, format ); X X /* Promote to PPM if differing gammas were specified. */ X if ( rgamma != ggamma || ggamma != bgamma ) X if ( PNM_FORMAT_TYPE(format) != PPM_TYPE && X PNM_FORMAT_TYPE(newformat) == PPM_TYPE ) X pnm_promoteformatrow( X xelrow, cols, maxval, format, maxval, newformat ); X X switch ( PNM_FORMAT_TYPE(newformat) ) X { X case PPM_TYPE: X for ( col = 0, xP = xelrow; col < cols; ++col, ++xP ) X { X register xelval r, g, b; X X r = PPM_GETR( *xP ); X g = PPM_GETG( *xP ); X b = PPM_GETB( *xP ); X r = rtable[r]; X g = gtable[g]; X b = btable[b]; X PPM_ASSIGN( *xP, r, g, b ); X } X break; X X default: X for ( col = 0, xP = xelrow; col < cols; ++col, ++xP ) X { X register xelval g; X X g = PNM_GET1( *xP ); X g = gtable[g]; X PNM_ASSIGN1( *xP, g ); X } X break; X } X X pnm_writepnmrow( stdout, xelrow, cols, maxval, newformat, 0 ); X } X X pm_close( ifp ); X X exit( 0 ); X } X X/* X** Builds a gamma table of size maxval+1 for the given gamma value. X** X** This function depends on pow(3m). If you don't have it, you can X** simulate it with '#define pow(x,y) exp((y)*log(x))' provided that X** you have the exponential function exp(3m) and the natural logarithm X** function log(3m). I can't believe I actually remembered my log X** identities. X*/ X X#if __STDC__ Xstatic void Xbuildgamma( xelval table[], xelval maxval, double gamma ) X#else /*__STDC__*/ Xstatic void Xbuildgamma( table, maxval, gamma ) X xelval table[], maxval; X double gamma; X#endif /*__STDC__*/ X { X register int i, v; X double one_over_gamma, ind, q; X X one_over_gamma = 1.0 / gamma; X q = (double) maxval; X for ( i = 0 ; i <= (int) maxval; ++i ) X { X ind = ( (double) i ) / q; X v = ( q * pow( ind, one_over_gamma ) ) + 0.5; X if ( v > (int) maxval ) X v = maxval; X table[i] = v; X } X } SHAR_EOF if test 4686 -ne "`wc -c < 'pnm/pnmgamma.c'`" then echo shar: error transmitting "'pnm/pnmgamma.c'" '(should have been 4686 characters)' fi fi # end of overwriting check if test ! -d 'pnm' then echo shar: creating directory "'pnm'" mkdir 'pnm' fi echo shar: extracting "'pnm/pnmgamma.1'" '(1069 characters)' if test -f 'pnm/pnmgamma.1' then echo shar: will not over-write existing file "'pnm/pnmgamma.1'" else sed 's/^X//' << \SHAR_EOF > 'pnm/pnmgamma.1' X.TH pnmgamma 1 "12 January 1991" X.IX pnmgamma X.SH NAME Xpnmgamma - perform gamma correction on a portable anymap X.SH SYNOPSIS X.B pnmgamma X.I value X.RI [ pnmfile ] X.br X.B pnmgamma X.I redvalue greenvalue bluevalue X.RI [ pnmfile ] X.SH DESCRIPTION XReads a portable anymap as input. XPerforms gamma correction, Xand produces a portable anymap as output. X.IX "gamma correction" X.PP XThe arguments specify what gamma value(s) to use. XA value of 1.0 leaves the image alone, less than one darkens it, Xand greater than one lightens it. X.PP XAll flags can be abbreviated to their shortest unique prefix. X.SH "SEE ALSO" Xpnm(5) X.SH AUTHOR XCopyright (C) 1991 by Bill Davidson and 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 1069 -ne "`wc -c < 'pnm/pnmgamma.1'`" then echo shar: error transmitting "'pnm/pnmgamma.1'" '(should have been 1069 characters)' fi fi # end of overwriting check if test ! -d 'pnm' then echo shar: creating directory "'pnm'" mkdir 'pnm' fi echo shar: extracting "'pnm/pnmarith.c'" '(4696 characters)' if test -f 'pnm/pnmarith.c' then echo shar: will not over-write existing file "'pnm/pnmarith.c'" else sed 's/^X//' << \SHAR_EOF > 'pnm/pnmarith.c' X/* pnmarith.c - perform arithmetic on two portable anymaps 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 Xvoid Xmain( argc, argv ) X int argc; X char* argv[]; X { X FILE* ifp1; X FILE* ifp2; X register xel* xelrow1; X register xel* xelrow2; X register xel* x1P; X register xel* x2P; X xelval maxval1, maxval2, maxval3; X int argn, rows1, cols1, format1, rows2, cols2, format2, format3, row, col; X char function; X char* usage = "-add|-subtract|-multiply pnmfile1 pnmfile2"; X X pnm_init( &argc, argv ); X X argn = 1; X function = ' '; X X /* Check for flags. */ X if ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) X { X if ( pm_keymatch( argv[argn], "-add", 2 ) ) X function = '+'; X else if ( pm_keymatch( argv[argn], "-subtract", 2 ) ) X function = '-'; X else if ( pm_keymatch( argv[argn], "-multiply", 2 ) ) X function = '*'; X else X pm_usage( usage ); X ++argn; X } X X if ( function == ' ' ) X pm_usage( usage ); X X if ( argn == argc ) X pm_usage( usage ); X ifp1 = pm_openr( argv[argn] ); X ++argn; X X if ( argn == argc ) X pm_usage( usage ); X ifp2 = pm_openr( argv[argn] ); X ++argn; X X if ( argn != argc ) X pm_usage( usage ); X X pnm_readpnminit( ifp1, &cols1, &rows1, &maxval1, &format1 ); X xelrow1 = pnm_allocrow( cols1 ); X pnm_readpnminit( ifp2, &cols2, &rows2, &maxval2, &format2 ); X if ( cols2 != cols1 || rows2 != rows1 ) X pm_error( X "the two anymaps must be the same width and height" ); X xelrow2 = pnm_allocrow( cols1 ); X X maxval3 = max( maxval1, maxval2 ); X format3 = max( PNM_FORMAT_TYPE(format1), PNM_FORMAT_TYPE(format2) ); X if ( PNM_FORMAT_TYPE(format1) != format3 || X PNM_FORMAT_TYPE(format2) != format3 ) X { X switch ( PNM_FORMAT_TYPE(format3) ) X { X case PPM_TYPE: X if ( PNM_FORMAT_TYPE(format1) != format3 ) X pm_message( "promoting first file to PPM" ); X if ( PNM_FORMAT_TYPE(format2) != format3 ) X pm_message( "promoting second file to PPM" ); X break; X case PGM_TYPE: X if ( PNM_FORMAT_TYPE(format1) != format3 ) X pm_message( "promoting first file to PGM" ); X if ( PNM_FORMAT_TYPE(format2) != format3 ) X pm_message( "promoting second file to PGM" ); X break; X } X } X X pnm_writepnminit( stdout, cols1, rows1, maxval3, format3, 0 ); X for ( row = 0; row < rows1; ++row ) X { X pnm_readpnmrow( ifp1, xelrow1, cols1, maxval1, format1 ); X if ( maxval1 != maxval3 || PNM_FORMAT_TYPE(format1) != format3 ) X pnm_promoteformatrow( X xelrow1, cols1, maxval1, format1, maxval3, format3 ); X X pnm_readpnmrow( ifp2, xelrow2, cols1, maxval2, format2 ); X if ( maxval2 != maxval3 || PNM_FORMAT_TYPE(format2) != format3 ) X pnm_promoteformatrow( X xelrow2, cols1, maxval2, format2, maxval3, format3 ); X X for ( col = 0, x1P = xelrow1, x2P = xelrow2; X col < cols1; ++col, ++x1P, ++x2P ) X { X switch ( PNM_FORMAT_TYPE(format3) ) X { X case PPM_TYPE: X { X int r1, g1, b1, r2, g2, b2; X X r1 = PPM_GETR( *x1P ); X g1 = PPM_GETG( *x1P ); X b1 = PPM_GETB( *x1P ); X r2 = PPM_GETR( *x2P ); X g2 = PPM_GETG( *x2P ); X b2 = PPM_GETB( *x2P ); X switch ( function ) X { X case '+': X r1 += r2; X g1 += g2; X b1 += b2; X break; X X case '-': X r1 -= r2; X g1 -= g2; X b1 -= b2; X break; X X case '*': X r1 = r1 * r2 / maxval3; X g1 = g1 * g2 / maxval3; X b1 = b1 * b2 / maxval3; X break; X X default: X pm_error( "can't happen" ); X } X if ( r1 < 0 ) r1 = 0; X else if ( r1 > maxval3 ) r1 = maxval3; X if ( g1 < 0 ) g1 = 0; X else if ( g1 > maxval3 ) g1 = maxval3; X if ( b1 < 0 ) b1 = 0; X else if ( b1 > maxval3 ) b1 = maxval3; X PPM_ASSIGN( *x1P, r1, g1, b1 ); X } X break; X X default: X { X int g1, g2; X X g1 = PNM_GET1( *x1P ); X g2 = PNM_GET1( *x2P ); X switch ( function ) X { X case '+': X g1 += g2; X break; X X case '-': X g1 -= g2; X break; X X case '*': X g1 = g1 * g2 / maxval3; X break; X X default: X pm_error( "can't happen" ); X } X if ( g1 < 0 ) g1 = 0; X else if ( g1 > maxval3 ) g1 = maxval3; X PNM_ASSIGN1( *x1P, g1 ); X } X break; X } X } X pnm_writepnmrow( stdout, xelrow1, cols1, maxval3, format3, 0 ); X } X X pm_close( ifp1 ); X pm_close( ifp2 ); X X exit( 0 ); X } SHAR_EOF if test 4696 -ne "`wc -c < 'pnm/pnmarith.c'`" then echo shar: error transmitting "'pnm/pnmarith.c'" '(should have been 4696 characters)' fi fi # end of overwriting check if test ! -d 'pnm' then echo shar: creating directory "'pnm'" mkdir 'pnm' fi echo shar: extracting "'pnm/pnmarith.1'" '(1158 characters)' if test -f 'pnm/pnmarith.1' then echo shar: will not over-write existing file "'pnm/pnmarith.1'" else sed 's/^X//' << \SHAR_EOF > 'pnm/pnmarith.1' X.TH pnmarith 1 "13 January 1991" X.IX pnmarith X.SH NAME Xpnmarith - perform arithmetic on two portable anymaps X.SH SYNOPSIS X.B pnmarith X.BR -add | -subtract | -multiply X.I pnmfile1 pnmfile2 X.SH DESCRIPTION XReads two portable anymaps as input. XPerforms the specified arithmetic operation, Xand produces a portable anymap as output. XThe two input anymaps must be the same width and height. X.PP XThe arithmetic is performed between corresponding pixels in the two Xanymaps, as if maxval was 1.0, black was 0.0, and a linear scale in between. XResults that fall outside of [0..1) are truncated. X.PP XAll flags can be abbreviated to their shortest unique prefix. X.SH "SEE ALSO" Xpbmmask(1), pnmpaste(1), pnminvert(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 1158 -ne "`wc -c < 'pnm/pnmarith.1'`" then echo shar: error transmitting "'pnm/pnmarith.1'" '(should have been 1158 characters)' fi fi # end of overwriting check if test ! -d 'pnm' then echo shar: creating directory "'pnm'" mkdir 'pnm' fi echo shar: extracting "'pnm/pnmconvol.c'" '(6600 characters)' if test -f 'pnm/pnmconvol.c' then echo shar: will not over-write existing file "'pnm/pnmconvol.c'" else sed 's/^X//' << \SHAR_EOF > 'pnm/pnmconvol.c' X/* pnmconvol.c - general MxN convolution on a portable anymap 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 Xvoid Xmain( argc, argv ) X int argc; X char* argv[]; X { X FILE* cifp; X FILE* ifp; X xel** cxels; X xel** xelbuf; X xel* outputrow; X xel x; X int argn, crows, ccols, cformat, ccolso2, crowso2; X int rows, cols, format, newformat, crow, row; X register int ccol, col; X xelval cmaxval, maxval; X xelval g; X float** gweights; X float gsum; X xelval r, b; X float** rweights; X float** bweights; X float rsum, bsum; X char* usage = " [pnmfile]"; X X pnm_init( &argc, argv ); X X argn = 1; X X if ( argn == argc ) X pm_usage( usage ); X cifp = pm_openr( argv[argn] ); X ++argn; 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 X /* Read in the convolution matrix. */ X cxels = pnm_readpnm( cifp, &ccols, &crows, &cmaxval, &cformat ); X pm_close( cifp ); X if ( ccols % 2 != 1 || crows % 2 != 1 ) X pm_error( X "the convolution matrix must have an odd number of rows and columns" ); X ccolso2 = ccols / 2; X crowso2 = crows / 2; X X pnm_readpnminit( ifp, &cols, &rows, &maxval, &format ); X if ( cols < ccols || rows < crows ) X pm_error( X "the image is smaller than the convolution matrix" ); X X newformat = max( PNM_FORMAT_TYPE(cformat), PNM_FORMAT_TYPE(format) ); X if ( PNM_FORMAT_TYPE(cformat) != newformat ) X pnm_promoteformat( cxels, ccols, crows, cmaxval, cformat, cmaxval, newformat ); X if ( PNM_FORMAT_TYPE(format) != newformat ) X { X switch ( PNM_FORMAT_TYPE(newformat) ) X { X case PPM_TYPE: X if ( PNM_FORMAT_TYPE(format) != newformat ) X pm_message( "promoting to PPM" ); X break; X case PGM_TYPE: X if ( PNM_FORMAT_TYPE(format) != newformat ) X pm_message( "promoting to PGM" ); X break; X } X } X X /* Set up the normalized weights. */ X rweights = (float**) pm_allocarray( ccols, crows, sizeof(float) ); X gweights = (float**) pm_allocarray( ccols, crows, sizeof(float) ); X bweights = (float**) pm_allocarray( ccols, crows, sizeof(float) ); X rsum = gsum = bsum = 0; X for ( crow = 0; crow < crows; ++crow ) X for ( ccol = 0; ccol < ccols; ++ccol ) X { X switch ( PNM_FORMAT_TYPE(format) ) X { X case PPM_TYPE: X rsum += rweights[crow][ccol] = X ( PPM_GETR(cxels[crow][ccol]) * 2.0 / cmaxval - 1.0 ); X gsum += gweights[crow][ccol] = X ( PPM_GETG(cxels[crow][ccol]) * 2.0 / cmaxval - 1.0 ); X bsum += bweights[crow][ccol] = X ( PPM_GETB(cxels[crow][ccol]) * 2.0 / cmaxval - 1.0 ); X break; X X default: X gsum += gweights[crow][ccol] = X ( PNM_GET1(cxels[crow][ccol]) * 2.0 / cmaxval - 1.0 ); X break; X } X } X switch ( PNM_FORMAT_TYPE(format) ) X { X case PPM_TYPE: X if ( rsum < 0.9 || rsum > 1.1 || gsum < 0.9 || gsum > 1.1 || X bsum < 0.9 || bsum > 1.1 ) X pm_message( X "WARNING - this convolution matrix is biased" ); X break; X X default: X if ( gsum < 0.9 || gsum > 1.1 ) X pm_message( X "WARNING - this convolution matrix is biased" ); X break; X } X X /* Allocate space for one convolution-matrix's worth of rows, plus X ** a row output buffer. */ X xelbuf = pnm_allocarray( cols, crows ); X outputrow = pnm_allocrow( cols ); X X pnm_writepnminit( stdout, cols, rows, maxval, newformat, 0 ); X X /* Read in one convolution-matrix's worth of image, less one row. */ X for ( row = 0; row < crows - 1; ++row ) X { X pnm_readpnmrow( ifp, xelbuf[row], cols, maxval, format ); X if ( PNM_FORMAT_TYPE(format) != newformat ) X pnm_promoteformatrow( X xelbuf[row], cols, maxval, format, maxval, newformat ); X /* Write out just the part we're not going to convolve. */ X if ( row < crowso2 ) X pnm_writepnmrow( stdout, xelbuf[row], cols, maxval, newformat, 0 ); X } X X /* Now the rest of the image - read in the row at the end of X ** xelbuf, and convolve and write out the row in the middle. X */ X for ( ; row < rows; ++row ) X { X pnm_readpnmrow( ifp, xelbuf[row % crows], cols, maxval, format ); X if ( PNM_FORMAT_TYPE(format) != newformat ) X pnm_promoteformatrow( X xelbuf[row % crows], cols, maxval, format, maxval, newformat ); X X for ( col = 0; col < cols; ++col ) X if ( col < ccolso2 || col >= cols - ccolso2 ) X outputrow[col] = xelbuf[(row - crowso2) % crows][col]; X else X { X switch ( PNM_FORMAT_TYPE(format) ) X { X case PPM_TYPE: X rsum = gsum = bsum = 0.0; X for ( crow = 0; crow < crows; ++crow ) X for ( ccol = 0; ccol < ccols; ++ccol ) X { X x = xelbuf[(row+1+crow) % crows][col-ccolso2+ccol]; X rsum += PPM_GETR( x ) * rweights[crow][ccol]; X gsum += PPM_GETG( x ) * gweights[crow][ccol]; X bsum += PPM_GETB( x ) * bweights[crow][ccol]; X } X if ( rsum < 0.0 ) r = 0; X else if ( rsum > maxval ) r = maxval; X else r = rsum + 0.5; X if ( gsum < 0.0 ) g = 0; X else if ( gsum > maxval ) g = maxval; X else g = gsum + 0.5; X if ( bsum < 0.0 ) b = 0; X else if ( bsum > maxval ) b = maxval; X else b = bsum + 0.5; X PPM_ASSIGN( outputrow[col], r, g, b ); X break; X X default: X gsum = 0.0; X for ( crow = 0; crow < crows; ++crow ) X for ( ccol = 0; ccol < ccols; ++ccol ) X { X x = xelbuf[(row+1+crow) % crows][col-ccolso2+ccol]; X gsum += PNM_GET1( x ) * gweights[crow][ccol]; X } X if ( gsum < 0.0 ) g = 0; X else if ( gsum > maxval ) g = maxval; X else g = gsum + 0.5; X PNM_ASSIGN1( outputrow[col], g ); X break; X } X } X X pnm_writepnmrow( stdout, outputrow, cols, maxval, newformat, 0 ); X } X pm_close( ifp ); X X /* Now write out the remaining unconvolved rows in xelbuf. */ X for ( ; row < rows + crowso2; ++row ) X pnm_writepnmrow( X stdout, xelbuf[(row-crowso2) % crows], cols, maxval, newformat, 0 ); X X exit( 0 ); X } SHAR_EOF if test 6600 -ne "`wc -c < 'pnm/pnmconvol.c'`" then echo shar: error transmitting "'pnm/pnmconvol.c'" '(should have been 6600 characters)' fi fi # end of overwriting check if test ! -d 'pnm' then echo shar: creating directory "'pnm'" mkdir 'pnm' fi echo shar: extracting "'pnm/pnmconvol.1'" '(1593 characters)' if test -f 'pnm/pnmconvol.1' then echo shar: will not over-write existing file "'pnm/pnmconvol.1'" else sed 's/^X//' << \SHAR_EOF > 'pnm/pnmconvol.1' X.TH pnmconvol 1 "13 January 1991" X.IX pnmconvol X.SH NAME Xpnmconvol - general MxN convolution on a portable anymap X.SH SYNOPSIS X.B pnmconvol X.I convolutionfile X.RI [ pnmfile ] X.SH DESCRIPTION XReads two portable anymaps as input. XConvolves the second using the first, Xand writes a portable anymap as output. X.IX convolution X.PP XConvolution means replacing each pixel with a weighted average of the Xnearby pixels. The weights and the area to average are determined by Xthe convolution matrix. XThe unsigned numbers in the convolution file are offset by -maxval/2 to Xmake signed numbers, and then normalized, so the actual values in the Xconvolution file are only relative. X.PP XHere is a sample convolution file; Xit does a simple average of the immediate neighbors, resulting Xin a smoothed image: X.nf X P2 X 3 3 X 18 X 10 10 10 X 10 10 10 X 10 10 10 X.fi X.PP XThe convolution file will usually be a bitmap or graymap instead of a pixmap, Xso that the same convolution gets applied to each color component. XHowever, if you want to use a pixmap and do a different convolution to Xdifferent colors, you can certainly do that. X.SH "SEE ALSO" Xpnm(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 1593 -ne "`wc -c < 'pnm/pnmconvol.1'`" then echo shar: error transmitting "'pnm/pnmconvol.1'" '(should have been 1593 characters)' fi fi # end of overwriting check if test ! -d 'pnm' then echo shar: creating directory "'pnm'" mkdir 'pnm' fi echo shar: extracting "'pnm/pnmsmooth'" '(257 characters)' if test -f 'pnm/pnmsmooth' then echo shar: will not over-write existing file "'pnm/pnmsmooth'" else sed 's/^X//' << \SHAR_EOF > 'pnm/pnmsmooth' X#!/bin/sh X# X# pnmsmooth - smooth out an image by replacing each xel with the X# average of its nine immediate neighbors X Xtmp=/tmp/psm.$$ Xrm -f $tmp X Xcat > $tmp << MOO XP2 X3 3 X18 X10 10 10 X10 10 10 X10 10 10 XMOO X Xpnmconvol $tmp ${1+"$@"} X Xrm -f $tmp SHAR_EOF if test 257 -ne "`wc -c < 'pnm/pnmsmooth'`" then echo shar: error transmitting "'pnm/pnmsmooth'" '(should have been 257 characters)' fi fi # end of overwriting check if test ! -d 'pnm' then echo shar: creating directory "'pnm'" mkdir 'pnm' fi echo shar: extracting "'pnm/pnmsmooth.1'" '(904 characters)' if test -f 'pnm/pnmsmooth.1' then echo shar: will not over-write existing file "'pnm/pnmsmooth.1'" else sed 's/^X//' << \SHAR_EOF > 'pnm/pnmsmooth.1' X.TH pnmsmooth 1 "13 January 1991" X.IX pnmsmooth X.SH NAME Xpnmsmooth - smooth out an image X.SH SYNOPSIS X.B pnmsmooth X.RI [ pnmfile ] X.SH DESCRIPTION XSmooths out an image by replacing each pixel with the Xaverage of its nine immediate neighbors. X.IX smoothing X.IX anti-aliasing XIt is implemented as a simple script using X.IR pnmconvol . X.IX pnmconvol X.SH "SEE ALSO" Xpnmconvol(1), pnm(5) X.SH BUGS XIt's a script. XScripts are not portable to non-Unix environments. 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 904 -ne "`wc -c < 'pnm/pnmsmooth.1'`" then echo shar: error transmitting "'pnm/pnmsmooth.1'" '(should have been 904 characters)' fi fi # end of overwriting check if test ! -d 'pnm' then echo shar: creating directory "'pnm'" mkdir 'pnm' fi echo shar: extracting "'pnm/tifftopnm.c'" '(6427 characters)' if test -f 'pnm/tifftopnm.c' then echo shar: will not over-write existing file "'pnm/tifftopnm.c'" else sed 's/^X//' << \SHAR_EOF > 'pnm/tifftopnm.c' X/* X** tifftopnm.c - converts a Tagged Image File to a portable anymap X** X** Derived by Jef Poskanzer from tif2ras.c, which is: X** X** Copyright (c) 1990 by Sun Microsystems, Inc. X** X** Author: Patrick J. Naughton X** naughton@wind.sun.com X** X** Permission to use, copy, modify, and distribute this software and its X** documentation for any purpose and without fee is hereby granted, X** provided that the above copyright notice appear in all copies and that X** both that copyright notice and this permission notice appear in X** supporting documentation. X** X** This file is provided AS IS with no warranties of any kind. The author X** shall have no liability with respect to the infringement of copyrights, X** trade secrets or any patents by this file or any part thereof. In no X** event will the author be liable for any lost revenue or profits or X** other special, indirect and consequential damages. X*/ X X#include "pnm.h" X#include X X#define MAXCOLORS 1024 X Xvoid Xmain( argc, argv ) X int argc; X char* argv[]; X { X int argn, cols, rows, grayscale, format; X int numcolors; X register TIFF* tif; X int row, i; X register int col; X u_char* buf; X register u_char* inP; X int maxval; X xel* xelrow; X register xel* xP; X xel colormap[MAXCOLORS]; X int headerdump; X register u_char sample; X register int bitsleft; X int bps, spp, photomet; X unsigned short** redcolormap; X unsigned short** greencolormap; X unsigned short** bluecolormap; X char* usage = "[-headerdump] [tifffile]"; X X pnm_init( &argc, argv ); X X argn = 1; X headerdump = 0; X X if ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) X { X if ( pm_keymatch( argv[argn], "-headerdump", 2 ) ) X headerdump = 1; X else X pm_usage( usage ); X ++argn; X } X X if ( argn != argc ) X { X tif = TIFFOpen( argv[argn], "r" ); X if ( tif == NULL ) X pm_error( "error opening TIFF file %s", argv[argn] ); X ++argn; X } X else X { X tif = TIFFFdOpen( 0, "Standard Input", "r" ); X if ( tif == NULL ) X pm_error( "error opening standard input as TIFF file" ); X } X X if ( argn != argc ) X pm_usage( usage ); X X if ( headerdump ) X TIFFPrintDirectory( tif, stderr, TIFFPRINT_NONE ); X X if ( ! TIFFGetField( tif, TIFFTAG_BITSPERSAMPLE, &bps ) ) X pm_error( "error getting bits per sample" ); X if ( ! TIFFGetField( tif, TIFFTAG_SAMPLESPERPIXEL, &spp ) ) X pm_error( "error getting samples per pixel" ); X if ( ! TIFFGetField( tif, TIFFTAG_PHOTOMETRIC, &photomet ) ) X pm_error( "error getting photometric" ); X X switch ( spp ) X { X case 1: X case 3: X case 4: X break; X X default: X pm_error( X "can only handle 1-channel gray scale or 1- or 3-channel color" ); X } X X (void) TIFFGetField( tif, TIFFTAG_IMAGEWIDTH, &cols ); X (void) TIFFGetField( tif, TIFFTAG_IMAGELENGTH, &rows ); X X if ( headerdump ) X { X pm_message( "%dx%dx%d image", cols, rows, bps * spp ); X pm_message( "%d bits/sample, %d samples/pixel", bps, spp ); X } X X maxval = ( 1 << bps ) - 1; X if ( maxval == 1 && spp == 1 ) X { X if ( headerdump ) X pm_message("monochrome" ); X grayscale = 1; X } X else X { X switch ( photomet ) X { X case PHOTOMETRIC_MINISBLACK: X if ( headerdump ) X pm_message( "%d graylevels (min=black)", maxval + 1 ); X grayscale = 1; X break; X X case PHOTOMETRIC_MINISWHITE: X if ( headerdump ) X pm_message( "%d graylevels (min=white)", maxval + 1 ); X grayscale = 1; X break; X X case PHOTOMETRIC_PALETTE: X if ( headerdump ) X pm_message( "colormapped" ); X if ( ! TIFFGetField( tif, TIFFTAG_COLORMAP, &redcolormap, &greencolormap, &bluecolormap ) ) X pm_error( "error getting colormaps" ); X numcolors = maxval + 1; X if ( numcolors > MAXCOLORS ) X pm_error( "too many colors" ); X maxval = PNM_MAXMAXVAL; X grayscale = 0; X for ( i = 0; i < numcolors; ++i ) X { X register xelval r, g, b; X r = (long) redcolormap[i] * PNM_MAXMAXVAL / 65535L; X g = (long) greencolormap[i] * PNM_MAXMAXVAL / 65535L; X b = (long) bluecolormap[i] * PNM_MAXMAXVAL / 65535L; X PPM_ASSIGN( colormap[i], r, g, b ); X } X break; X X case PHOTOMETRIC_RGB: X if ( headerdump ) X pm_message( "truecolor" ); X grayscale = 0; X break; X X case PHOTOMETRIC_MASK: X pm_error( "don't know how to handle PHOTOMETRIC_MASK" ); X X case PHOTOMETRIC_DEPTH: X pm_error( "don't know how to handle PHOTOMETRIC_DEPTH" ); X X default: X pm_error( "unknown photometric: %d", photomet ); X } X } X if ( maxval > PNM_MAXMAXVAL ) X pm_error( X"bits/sample is too large - try reconfiguring with PGM_BIGGRAYS\n or without PPM_PACKCOLORS" ); X X X if ( grayscale ) X { X if ( maxval == 1 ) X { X format = PBM_TYPE; X pm_message( "writing PBM file" ); X } X else X { X format = PGM_TYPE; X pm_message( "writing PGM file" ); X } X } X else X { X format = PPM_TYPE; X pm_message( "writing PPM file" ); X } X X buf = (u_char*) malloc(TIFFScanlineSize(tif)); X if ( buf == NULL ) X pm_error( "can't allocate memory for scanline buffer" ); X pnm_writepnminit( stdout, cols, rows, (xelval) maxval, format, 0 ); X xelrow = pnm_allocrow( cols ); X X#define NEXTSAMPLE \ X { \ X if ( bitsleft == 0 ) \ X { \ X ++inP; \ X bitsleft = 8; \ X } \ X bitsleft -= bps; \ X sample = ( *inP >> bitsleft ) & maxval; \ X } X X for ( row = 0; row < rows; ++row ) X { X if ( TIFFReadScanline( tif, buf, row, 0 ) < 0 ) X pm_error( "bad data read on line %d", row ); X inP = buf; X bitsleft = 8; X xP = xelrow; X X switch ( photomet ) X { X case PHOTOMETRIC_MINISBLACK: X for ( col = 0; col < cols; ++col, ++xP ) X { X NEXTSAMPLE X PNM_ASSIGN1( *xP, sample ); X } X break; X X case PHOTOMETRIC_MINISWHITE: X for ( col = 0; col < cols; ++col, ++xP ) X { X NEXTSAMPLE X sample = maxval - sample; X PNM_ASSIGN1( *xP, sample ); X } X break; X X case PHOTOMETRIC_PALETTE: X for ( col = 0; col < cols; ++col, ++xP ) X { X NEXTSAMPLE X *xP = colormap[sample]; X } X break; X X case PHOTOMETRIC_RGB: X for ( col = 0; col < cols; ++col, ++xP ) X { X register xelval r, g, b; X X NEXTSAMPLE X r = sample; X NEXTSAMPLE X g = sample; X NEXTSAMPLE X b = sample; X if ( spp == 4 ) X NEXTSAMPLE /* skip alpha channel */ X PPM_ASSIGN( *xP, r, g, b ); X } X break; X X default: X pm_error( "unknown photometric: %d", photomet ); X } X pnm_writepnmrow( stdout, xelrow, cols, (xelval) maxval, format, 0 ); X } X X exit( 0 ); X } SHAR_EOF if test 6427 -ne "`wc -c < 'pnm/tifftopnm.c'`" then echo shar: error transmitting "'pnm/tifftopnm.c'" '(should have been 6427 characters)' fi fi # end of overwriting check if test ! -d 'pnm' then echo shar: creating directory "'pnm'" mkdir 'pnm' fi echo shar: extracting "'pnm/tifftopnm.1'" '(1787 characters)' if test -f 'pnm/tifftopnm.1' then echo shar: will not over-write existing file "'pnm/tifftopnm.1'" else sed 's/^X//' << \SHAR_EOF > 'pnm/tifftopnm.1' X.TH tifftopnm 1 "13 January 1991" X.IX tifftopnm X.SH NAME Xtifftopnm - convert a TIFF file into a portable anymap X.SH SYNOPSIS X.B tifftopnm X.RB [ -headerdump ] X.RI [ tifffile ] X.SH DESCRIPTION XReads a TIFF file as input. X.IX TIFF XProduces a portable anymap as output. XThe type of the output file depends on the input file - if it's Xblack & white, a X.I pbm Xfile is written, else if it's grayscale a X.I pgm Xfile, else a X.I ppm Xfile. The program tells you which type it is writing. X.SH OPTIONS X.TP X.B -headerdump XDump TIFF file information to stderr. This information may be useful Xin debugging TIFF file conversion problems. X.PP XAll flags can be abbreviated to their shortest unique prefix. X.SH "SEE ALSO" Xpnmtotiff(1), pnm(5) X.SH BUGS XThis program is not self-contained. To use it you must fetch the XTIFF Software package listed in the OTHER.SYSTEMS file and configure XPBMPLUS to use libtiff. See PBMPLUS's Makefile for details on this Xconfiguration. X.SH AUTHOR XDerived by Jef Poskanzer from tif2ras.c, which is XCopyright (c) 1990 by Sun Microsystems, Inc. XAuthor: Patrick J. Naughton (naughton@wind.sun.com). X.\" Permission to use, copy, modify, and distribute this software and its X.\" documentation for any purpose and without fee is hereby granted, X.\" provided that the above copyright notice appear in all copies and that X.\" both that copyright notice and this permission notice appear in X.\" supporting documentation. X.\" X.\" This file is provided AS IS with no warranties of any kind. The author X.\" shall have no liability with respect to the infringement of copyrights, X.\" trade secrets or any patents by this file or any part thereof. In no X.\" event will the author be liable for any lost revenue or profits or X.\" other special, indirect and consequential damages. SHAR_EOF if test 1787 -ne "`wc -c < 'pnm/tifftopnm.1'`" then echo shar: error transmitting "'pnm/tifftopnm.1'" '(should have been 1787 characters)' fi fi # end of overwriting check if test ! -d 'pnm' then echo shar: creating directory "'pnm'" mkdir 'pnm' fi echo shar: extracting "'pnm/pnmtotiff.c'" '(9201 characters)' if test -f 'pnm/pnmtotiff.c' then echo shar: will not over-write existing file "'pnm/pnmtotiff.c'" else sed 's/^X//' << \SHAR_EOF > 'pnm/pnmtotiff.c' X/* X** pnmtotiff.c - converts a portable anymap to a Tagged Image File X** X** Derived by Jef Poskanzer from ras2tif.c, which is: X** X** Copyright (c) 1990 by Sun Microsystems, Inc. X** X** Author: Patrick J. Naughton X** naughton@wind.sun.com X** X** Permission to use, copy, modify, and distribute this software and its X** documentation for any purpose and without fee is hereby granted, X** provided that the above copyright notice appear in all copies and that X** both that copyright notice and this permission notice appear in X** supporting documentation. X** X** This file is provided AS IS with no warranties of any kind. The author X** shall have no liability with respect to the infringement of copyrights, X** trade secrets or any patents by this file or any part thereof. In no X** event will the author be liable for any lost revenue or profits or X** other special, indirect and consequential damages. X*/ X X#include "pnm.h" X#include X X#include "ppmcmap.h" X#define MAXCOLORS 256 X Xvoid Xmain( argc, argv ) X int argc; X char* argv[]; X { X int argn; X char* inf = NULL; X FILE* ifp; X xel** xels; X register xel* xP; X colorhist_vector chv; X colorhash_table cht; X unsigned short red[MAXCOLORS], grn[MAXCOLORS], blu[MAXCOLORS]; X int cols, rows, format, row, colors, i; X register int col; X xelval maxval; X int grayscale; X TIFF* tif; X long g3options; X long rowsperstrip; X unsigned short compression; X unsigned short fillorder; X unsigned short predictor; X short photometric; X short samplesperpixel; X short bitspersample; X int bytesperrow; X unsigned char* buf; X unsigned char* tP; X char* usage = "[-none|-packbits|-lzw|-g3|-g4] [-msb2lsb|-lsb2msb] [-2d] [-fill] [-predictor n] [-rowsperstrip n] [pnmfile]"; X X pnm_init( &argc, argv ); X X argn = 1; X compression = COMPRESSION_LZW; X g3options = 0; X fillorder = FILLORDER_MSB2LSB; X predictor = 0; X rowsperstrip = 0; X X while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) X { X if ( pm_keymatch( argv[argn], "-none", 2 ) ) X compression = COMPRESSION_NONE; X else if ( pm_keymatch( argv[argn], "-packbits", 3 ) ) X compression = COMPRESSION_PACKBITS; X else if ( pm_keymatch( argv[argn], "-lzw", 3 ) ) X compression = COMPRESSION_LZW; X else if ( pm_keymatch( argv[argn], "-g3", 3 ) ) X compression = COMPRESSION_CCITTFAX3; X else if ( pm_keymatch( argv[argn], "-g4", 3 ) ) X compression = COMPRESSION_CCITTFAX4; X else if ( pm_keymatch( argv[argn], "-msb2lsb", 3 ) ) X fillorder = FILLORDER_MSB2LSB; X else if ( pm_keymatch( argv[argn], "-lsb2msb", 3 ) ) X fillorder = FILLORDER_LSB2MSB; X else if ( pm_keymatch( argv[argn], "-2d", 2 ) ) X g3options |= GROUP3OPT_2DENCODING; X else if ( pm_keymatch( argv[argn], "-fill", 2 ) ) X g3options |= GROUP3OPT_FILLBITS; X else if ( pm_keymatch( argv[argn], "-predictor", 3) ) X { X ++argn; X if ( argn == argc || sscanf( argv[argn], "%hu", &predictor ) != 1 ) X pm_usage( usage ); X if ( predictor != 1 && predictor != 2 ) X pm_usage( usage ); X } X else if ( pm_keymatch( argv[argn], "-rowsperstrip", 2 ) ) X { X ++argn; X if ( argn == argc || X sscanf( argv[argn], "%ld", &rowsperstrip ) != 1 ) X pm_usage( usage ); X if ( rowsperstrip < 1 ) X pm_usage( usage ); X } X else X pm_usage( usage ); X ++argn; X } X X if ( argn != argc ) X { X inf = argv[argn]; X ifp = pm_openr( inf ); X ++argn; X } X else X { X inf = "Standard Input"; X ifp = stdin; X } X X if ( argn != argc ) X pm_usage( usage ); X X xels = pnm_readpnm( ifp, &cols, &rows, &maxval, &format ); X pm_close( ifp ); X X /* Check for grayscale. */ X switch ( PNM_FORMAT_TYPE(format) ) X { X case PPM_TYPE: X pm_message( "computing colormap..." ); X chv = ppm_computecolorhist( xels, cols, rows, MAXCOLORS, &colors ); X if ( chv == (colorhist_vector) 0 ) X { X pm_message( X "Too many colors - proceeding to write a 24-bit RGB file." ); X pm_message( X "If you want an 8-bit palette file, try doing a 'ppmquant %d'.", X MAXCOLORS ); X } X else X { X pm_message( "%d colors found", colors ); X grayscale = 1; X for ( i = 0; i < colors; ++i ) X { X register xelval r, g, b; X X r = PPM_GETR( chv[i].color ); X g = PPM_GETG( chv[i].color ); X b = PPM_GETB( chv[i].color ); X if ( r != g || g != b ) X { X grayscale = 0; X break; X } X } X } X break; X X default: X grayscale = 1; X break; X } X X /* Open output file. */ X tif = TIFFFdOpen( 1, "Standard Output", "w" ); X if ( tif == NULL ) X pm_error( "error opening standard output as TIFF file" ); X X /* Figure out TIFF parameters. */ X switch ( PNM_FORMAT_TYPE(format) ) X { X case PPM_TYPE: X if ( chv == (colorhist_vector) 0 ) X { X samplesperpixel = 3; X bitspersample = 8; X photometric = PHOTOMETRIC_RGB; X bytesperrow = cols * 3; X } X else if ( grayscale ) X { X samplesperpixel = 1; X bitspersample = pm_maxvaltobits( maxval ); X photometric = PHOTOMETRIC_MINISBLACK; X bytesperrow = ( cols + i - 1 ) / i; X } X else X { X samplesperpixel = 1; X bitspersample = 8; X photometric = PHOTOMETRIC_PALETTE; X bytesperrow = cols; X } X break; X X case PGM_TYPE: X samplesperpixel = 1; X bitspersample = pm_maxvaltobits( maxval ); X photometric = PHOTOMETRIC_MINISBLACK; X i = 8 / bitspersample; X bytesperrow = ( cols + i - 1 ) / i; X break; X X default: X samplesperpixel = 1; X bitspersample = 1; X photometric = PHOTOMETRIC_MINISBLACK; X bytesperrow = ( cols + 7 ) / 8; X break; X } X X if ( rowsperstrip == 0 ) X rowsperstrip = ( 8 * 1024 ) / bytesperrow; X buf = (unsigned char*) malloc( bytesperrow ); X if ( buf == (unsigned char*) 0 ) X pm_error( "can't allocate memory for row buffer" ); X X /* Set TIFF parameters. */ X TIFFSetField( tif, TIFFTAG_IMAGEWIDTH, cols ); X TIFFSetField( tif, TIFFTAG_IMAGELENGTH, rows ); X TIFFSetField( tif, TIFFTAG_BITSPERSAMPLE, bitspersample ); X TIFFSetField( tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT ); X TIFFSetField( tif, TIFFTAG_COMPRESSION, compression ); X if ( compression == COMPRESSION_CCITTFAX3 && g3options != 0 ) X TIFFSetField( tif, TIFFTAG_GROUP3OPTIONS, g3options ); X if ( compression == COMPRESSION_LZW && predictor != 0 ) X TIFFSetField( tif, TIFFTAG_PREDICTOR, predictor ); X TIFFSetField( tif, TIFFTAG_PHOTOMETRIC, photometric ); X TIFFSetField( tif, TIFFTAG_FILLORDER, fillorder ); X TIFFSetField( tif, TIFFTAG_DOCUMENTNAME, inf ); X TIFFSetField( tif, TIFFTAG_IMAGEDESCRIPTION, "converted PNM file" ); X TIFFSetField( tif, TIFFTAG_SAMPLESPERPIXEL, samplesperpixel ); X TIFFSetField( tif, TIFFTAG_ROWSPERSTRIP, rowsperstrip ); X /* TIFFSetField( tif, TIFFTAG_STRIPBYTECOUNTS, rows / rowsperstrip ); */ X TIFFSetField( tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG ); X X if ( chv == (colorhist_vector) 0 ) X cht = (colorhash_table) 0; X else X { X /* Make TIFF colormap. */ X for ( i = 0; i < colors; ++i ) X { X red[i] = (long) PPM_GETR( chv[i].color ) * 65535L / maxval; X grn[i] = (long) PPM_GETG( chv[i].color ) * 65535L / maxval; X blu[i] = (long) PPM_GETB( chv[i].color ) * 65535L / maxval; X } X TIFFSetField( tif, TIFFTAG_COLORMAP, red, grn, blu ); X X /* Convert color vector to color hash table, for fast lookup. */ X cht = ppm_colorhisttocolorhash( chv, colors ); X ppm_freecolorhist( chv ); X } X X /* Now write the TIFF data. */ X for ( row = 0; row < rows; ++row ) X { X if ( PNM_FORMAT_TYPE(format) == PPM_TYPE && ! grayscale ) X { X if ( cht == (colorhash_table) 0 ) X { X for ( col = 0, xP = xels[row], tP = buf; X col < cols; ++col, ++xP ) X { X register unsigned char s; X X s = PPM_GETR( *xP ); X if ( maxval != 255 ) X s = (long) s * 255 / maxval; X *tP++ = s; X s = PPM_GETG( *xP ); X if ( maxval != 255 ) X s = (long) s * 255 / maxval; X *tP++ = s; X s = PPM_GETB( *xP ); X if ( maxval != 255 ) X s = (long) s * 255 / maxval; X *tP++ = s; X } X } X else X { X for ( col = 0, xP = xels[row], tP = buf; X col < cols; ++col, ++xP ) X { X register int s; X X s = ppm_lookupcolor( cht, xP ); X if ( s == -1 ) X pm_error( X "color not found?!? row=%d col=%d r=%d g=%d b=%d", X row, col, PPM_GETR( *xP ), PPM_GETG( *xP ), X PPM_GETB( *xP ) ); X *tP++ = (unsigned char) s; X } X } X } X else X { X register xelval bigger_maxval; X register int bitshift; X register unsigned char byte; X register xelval s; X X bigger_maxval = pm_bitstomaxval( bitspersample ); X bitshift = 8 - bitspersample; X byte = 0; X for ( col = 0, xP = xels[row], tP = buf; col < cols; ++col, ++xP ) X { X s = PNM_GET1( *xP ); X if ( maxval != bigger_maxval ) X s = (long) s * bigger_maxval / maxval; X byte |= s << bitshift; X bitshift -= bitspersample; X if ( bitshift < 0 ) X { X *tP++ = byte; X bitshift = 8 - bitspersample; X byte = 0; X } X } X if ( bitshift != 8 - bitspersample ) X *tP++ = byte; X } X X if ( TIFFWriteScanline( tif, buf, row, 0 ) < 0 ) X pm_error( "failed a scanline write on row %d", row ); X } X TIFFFlushData( tif ); X TIFFClose( tif ); X X exit( 0 ); X } SHAR_EOF if test 9201 -ne "`wc -c < 'pnm/pnmtotiff.c'`" then echo shar: error transmitting "'pnm/pnmtotiff.c'" '(should have been 9201 characters)' fi fi # end of overwriting check if test ! -d 'pnm' then echo shar: creating directory "'pnm'" mkdir 'pnm' fi echo shar: extracting "'pnm/pnmtotiff.1'" '(3005 characters)' if test -f 'pnm/pnmtotiff.1' then echo shar: will not over-write existing file "'pnm/pnmtotiff.1'" else sed 's/^X//' << \SHAR_EOF > 'pnm/pnmtotiff.1' X.TH pnmtotiff 1 "13 January 1991" X.IX pnmtotiff X.SH NAME Xpnmtotiff - convert a a portable anymap into a TIFF file X.SH SYNOPSIS X.B pnmtotiff X.RB [ -none | -packbits | X.BR -lzw | -g3 | -g4 ] X.RB [ -2d ] X.RB [ -fill ] X.RB [ -predictor X.IR n ] X.RB [ -msb2lsb | -lsb2msb ] X.RB [ -rowsperstrip X.IR n ] X.RI [ pnmfile ] X.SH DESCRIPTION XReads a portable anymap as input. XProduces a TIFF file as output. X.IX TIFF X.SH OPTIONS X.PP XBy default, X.I pnmtotiff Xcreates a TIFF file with LZW compression. XThis is your best bet most of the time. XHowever, some TIFF readers can't deal with it. XIf you want to try another compression scheme or tweak some of the Xother even more obscure output options, there are a number of Xflags to play with. X.PP XThe X.BR -none , X.BR -packbits , X.BR -lzw , X.BR -g3 , Xand X.BR -g4 Xoptions are used to override the default and set the compression Xscheme used in creating the output file. The CCITT Group 3 and Group X4 compression algorithms can only be used with bilevel data. The X.B -2d Xand X.B -fill Xoptions are meaningful only with Group 3 compression: X.B -2d Xrequests 2-dimensional encoding, while X.B -fill Xrequests that each encoded scanline be zero-filled to a byte boundry. XThe X.B -predictor Xoption is only meaningful with LZW compression: a predictor value of 2 Xcauses each scanline of the output image to undergo horizontal Xdifferencing before it is encoded; a value of 1 forces each scanline Xto be encoded without differencing. X.P XBy default, X.I pnmtotiff Xcreates a TIFF file with msb-to-lsb fill order. XThe X.B -msb2lsb Xand X.B -lsb2msb Xoptions are used to override the default and set the fill order used Xin creating the file. X.P XThe X.B -rowsperstrip Xoption can be used to set the number of rows (scanlines) in each Xstrip of data in the output file. By default, the output file has Xthe number of rows per strip set to a value that will ensure each Xstrip is no more than 8 kilobytes long. X.SH BUGS XThis program is not self-contained. To use it you must fetch the XTIFF Software package listed in the OTHER.SYSTEMS file and configure XPBMPLUS to use libtiff. See PBMPLUS's Makefile for details on this Xconfiguration. X.SH "SEE ALSO" Xtifftopnm(1), pnm(5) X.SH AUTHOR XDerived by Jef Poskanzer from ras2tiff.c, which is XCopyright (c) 1990 by Sun Microsystems, Inc. XAuthor: Patrick J. Naughton (naughton@wind.sun.com). X.\" Permission to use, copy, modify, and distribute this software and its X.\" documentation for any purpose and without fee is hereby granted, X.\" provided that the above copyright notice appear in all copies and that X.\" both that copyright notice and this permission notice appear in X.\" supporting documentation. X.\" X.\" This file is provided AS IS with no warranties of any kind. The author X.\" shall have no liability with respect to the infringement of copyrights, X.\" trade secrets or any patents by this file or any part thereof. In no X.\" event will the author be liable for any lost revenue or profits or X.\" other special, indirect and consequential damages. SHAR_EOF if test 3005 -ne "`wc -c < 'pnm/pnmtotiff.1'`" then echo shar: error transmitting "'pnm/pnmtotiff.1'" '(should have been 3005 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.