[comp.sources.misc] v09i025: PBMPLUS part 9 of 19: pgm.shar2 of 2

allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc) (11/27/89)

Posting-number: Volume 9, Issue 25
Submitted-by: jef@helios.ee.lbl.gov (Jef Poskanzer)
Archive-name: pbmplus/part09

#! /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:
#	pgm/pgmtopbm.c
#	pgm/pgmtopbm.1
#	pgm/dithers.h
#	pgm/tiff.h
#	pgm/pgmtops.c
#	pgm/pgmtops.1
#	pgm/psidtopgm.c
#	pgm/psidtopgm.1
#	pgm/fitstopgm.c
#	pgm/fitstopgm.1
# This archive created: Wed Nov 22 21:13:49 1989
# By:	Jef Poskanzer (Paratheo-Anametamystikhood Of Eris Esoteric, Ada Lovelace Cabal)
export PATH; PATH=/bin:$PATH
if test ! -d 'pgm'
then
	echo shar: creating directory "'pgm'"
	mkdir 'pgm'
fi
echo shar: extracting "'pgm/pgmtopbm.c'" '(7022 characters)'
if test -f 'pgm/pgmtopbm.c'
then
	echo shar: will not over-write existing file "'pgm/pgmtopbm.c'"
else
sed 's/^X//' << \SHAR_EOF > 'pgm/pgmtopbm.c'
X/* pgmtopbm.c - read a portable graymap and write a portable bitmap
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 <stdio.h>
X#include "pgm.h"
X#include "pbm.h"
X#include "dithers.h"
X#ifdef SYSV
X#include <string.h>
X#define srandom srand
X#define random rand
X#else /*SYSV*/
X#include <strings.h>
X#endif /*SYSV*/
X
X#define max(a,b) ((a) > (b) ? (a) : (b))
X
Xmain( argc, argv )
Xint argc;
Xchar *argv[];
X    {
X    FILE *ifd;
X    register gray *grayrow, *gP;
X    register bit *bitrow, *bP;
X    int argn, rows, cols, format, row, col, limitcol;
X    float fthreshval;
X    gray maxval;
X    char *usage = "[-floyd|-fs | -threshold | -dither8|-d8 |\n     -cluster3|-c3|-cluster4|-c4|-cluster8|-c8] [-value <val>] [pgmfile]";
X    int halftone;
X#define QT_FS 1
X#define QT_THRESH 2
X#define QT_DITHER8 3
X#define QT_CLUSTER3 4
X#define QT_CLUSTER4 5
X#define QT_CLUSTER8 6
X    long threshval, sum, *thiserr, *nexterr, *temperr;
X#define FS_SCALE 1024
X#define HALF_FS_SCALE 512
X    int fs_direction;
X
X    pm_progname = argv[0];
X
X    argn = 1;
X    halftone = QT_FS;	/* default quantization is Floyd-Steinberg */
X    fthreshval = 0.5;
X
X    while ( argn < argc && argv[argn][0] == '-' )
X	{
X	if ( strncmp(argv[argn],"-fs",max(strlen(argv[argn]),2)) == 0 ||
X	     strncmp(argv[argn],"-floyd",max(strlen(argv[argn]),2)) == 0 )
X	    halftone = QT_FS;
X	else if ( strncmp(argv[argn],"-threshold",max(strlen(argv[argn]),2)) == 0 )
X	    halftone = QT_THRESH;
X	else if ( strncmp(argv[argn],"-dither8",max(strlen(argv[argn]),2)) == 0 ||
X	          strncmp(argv[argn],"-d8",max(strlen(argv[argn]),3)) == 0 )
X	    halftone = QT_DITHER8;
X	else if ( strncmp(argv[argn],"-cluster3",max(strlen(argv[argn]),9)) == 0 ||
X	          strncmp(argv[argn],"-c3",max(strlen(argv[argn]),3)) == 0 )
X	    halftone = QT_CLUSTER3;
X	else if ( strncmp(argv[argn],"-cluster4",max(strlen(argv[argn]),9)) == 0 ||
X	          strncmp(argv[argn],"-c4",max(strlen(argv[argn]),3)) == 0 )
X	    halftone = QT_CLUSTER4;
X	else if ( strncmp(argv[argn],"-cluster8",max(strlen(argv[argn]),9)) == 0 ||
X	          strncmp(argv[argn],"-c8",max(strlen(argv[argn]),3)) == 0 )
X	    halftone = QT_CLUSTER8;
X	else if ( strncmp(argv[argn],"-value",max(strlen(argv[argn]),2)) == 0 )
X	    {
X	    argn++;
X	    if ( argn == argc || sscanf( argv[argn], "%g", &fthreshval ) != 1 ||
X		 fthreshval < 0.0 || fthreshval > 1.0 )
X		pm_usage( usage );
X	    }
X	else
X	    pm_usage( usage );
X	argn++;
X	}
X
X    if ( argn != argc )
X	{
X	ifd = pm_openr( argv[argn] );
X	argn++;
X	}
X    else
X	ifd = stdin;
X
X    if ( argn != argc )
X	pm_usage( usage );
X
X    pgm_readpgminit( ifd, &cols, &rows, &maxval, &format );
X    grayrow = pgm_allocrow( cols );
X
X    pbm_writepbminit( stdout, cols, rows );
X    bitrow = pbm_allocrow( cols );
X
X    /* Initialize. */
X    switch ( halftone )
X	{
X	case QT_FS:
X	/* Initialize Floyd-Steinberg error vectors. */
X	thiserr = (long *) pm_allocrow( cols + 2, sizeof(long) );
X	nexterr = (long *) pm_allocrow( cols + 2, sizeof(long) );
X	srandom( (int) time( 0 ) );
X	for ( col = 0; col < cols + 2; col++ )
X	    thiserr[col] = ( random( ) % FS_SCALE - HALF_FS_SCALE ) / 4;
X	    /* (random errors in [-FS_SCALE/8 .. FS_SCALE/8]) */
X	fs_direction = 1;
X	threshval = fthreshval * FS_SCALE;
X	break;
X
X	case QT_THRESH:
X	threshval = fthreshval * maxval;
X	break;
X
X	case QT_DITHER8:
X	/* Scale dither matrix. */
X	for ( row = 0; row < 16; row++ )
X	    for ( col = 0; col < 16; col++ )
X		dither8[row][col] = dither8[row][col] * ( maxval + 1 ) / 256;
X	break;
X
X	case QT_CLUSTER3:
X	/* Scale order-3 clustered dither matrix. */
X	for ( row = 0; row < 6; row++ )
X	    for ( col = 0; col < 6; col++ )
X		cluster3[row][col] = cluster3[row][col] * ( maxval + 1 ) / 18;
X	break;
X
X	case QT_CLUSTER4:
X	/* Scale order-4 clustered dither matrix. */
X	for ( row = 0; row < 8; row++ )
X	    for ( col = 0; col < 8; col++ )
X		cluster4[row][col] = cluster4[row][col] * ( maxval + 1 ) / 32;
X	break;
X
X	case QT_CLUSTER8:
X	/* Scale order-8 clustered dither matrix. */
X	for ( row = 0; row < 16; row++ )
X	    for ( col = 0; col < 16; col++ )
X		cluster8[row][col] = cluster8[row][col] * ( maxval + 1 ) / 128;
X	break;
X
X	default:
X	pm_error( "can't happen", 0,0,0,0,0 );
X	exit( 1 );
X	}
X
X    for ( row = 0; row < rows; row++ )
X	{
X	pgm_readpgmrow( ifd, grayrow, cols, maxval, format );
X
X	switch ( halftone )
X	    {
X	    case QT_FS:
X	    for ( col = 0; col < cols + 2; col++ )
X		nexterr[col] = 0;
X	    if ( fs_direction )
X		{
X		col = 0;
X		limitcol = cols;
X		gP = grayrow;
X		bP = bitrow;
X		}
X	    else
X		{
X		col = cols - 1;
X		limitcol = -1;
X		gP = &(grayrow[col]);
X		bP = &(bitrow[col]);
X		}
X	    do
X		{
X		sum = ( (long) *gP * FS_SCALE ) / maxval + thiserr[col + 1];
X		if ( sum >= threshval )
X		    {
X		    *bP = PBM_WHITE;
X		    sum = sum - threshval - HALF_FS_SCALE;
X		    }
X		else
X		    *bP = PBM_BLACK;
X
X		if ( fs_direction )
X		    {
X		    thiserr[col + 2] += ( sum * 7 ) / 16;
X		    nexterr[col    ] += ( sum * 3 ) / 16;
X		    nexterr[col + 1] += ( sum * 5 ) / 16;
X		    nexterr[col + 2] += ( sum     ) / 16;
X
X		    col++;
X		    gP++;
X		    bP++;
X		    }
X		else
X		    {
X		    thiserr[col    ] += ( sum * 7 ) / 16;
X		    nexterr[col + 2] += ( sum * 3 ) / 16;
X		    nexterr[col + 1] += ( sum * 5 ) / 16;
X		    nexterr[col    ] += ( sum     ) / 16;
X
X		    col--;
X		    gP--;
X		    bP--;
X		    }
X		}
X	    while ( col != limitcol );
X	    temperr = thiserr;
X	    thiserr = nexterr;
X	    nexterr = temperr;
X	    fs_direction = ! fs_direction;
X	    break;
X
X	    case QT_THRESH:
X	    for ( col = 0, gP = grayrow, bP = bitrow; col < cols; col++, gP++, bP++ )
X		if ( *gP >= threshval )
X		    *bP = PBM_WHITE;
X		else
X		    *bP = PBM_BLACK;
X	    break;
X
X	    case QT_DITHER8:
X	    for ( col = 0, gP = grayrow, bP = bitrow; col < cols; col++, gP++, bP++ )
X		if ( *gP >= dither8[row % 16][col % 16] )
X		    *bP = PBM_WHITE;
X		else
X		    *bP = PBM_BLACK;
X	    break;
X
X	    case QT_CLUSTER3:
X	    for ( col = 0, gP = grayrow, bP = bitrow; col < cols; col++, gP++, bP++ )
X		if ( *gP >= cluster3[row % 6][col % 6] )
X		    *bP = PBM_WHITE;
X		else
X		    *bP = PBM_BLACK;
X	    break;
X
X	    case QT_CLUSTER4:
X	    for ( col = 0, gP = grayrow, bP = bitrow; col < cols; col++, gP++, bP++ )
X		if ( *gP >= cluster4[row % 8][col % 8] )
X		    *bP = PBM_WHITE;
X		else
X		    *bP = PBM_BLACK;
X	    break;
X
X	    case QT_CLUSTER8:
X	    for ( col = 0, gP = grayrow, bP = bitrow; col < cols; col++, gP++, bP++ )
X		if ( *gP >= cluster8[row % 16][col % 16] )
X		    *bP = PBM_WHITE;
X		else
X		    *bP = PBM_BLACK;
X	    break;
X
X	    default:
X	    pm_error( "can't happen", 0,0,0,0,0 );
X	    exit( 1 );
X	    }
X
X	pbm_writepbmrow( stdout, bitrow, cols );
X	}
X
X    pm_close( ifd );
X
X    exit( 0 );
X    }
SHAR_EOF
if test 7022 -ne "`wc -c < 'pgm/pgmtopbm.c'`"
then
	echo shar: error transmitting "'pgm/pgmtopbm.c'" '(should have been 7022 characters)'
fi
fi # end of overwriting check
if test ! -d 'pgm'
then
	echo shar: creating directory "'pgm'"
	mkdir 'pgm'
fi
echo shar: extracting "'pgm/pgmtopbm.1'" '(1883 characters)'
if test -f 'pgm/pgmtopbm.1'
then
	echo shar: will not over-write existing file "'pgm/pgmtopbm.1'"
else
sed 's/^X//' << \SHAR_EOF > 'pgm/pgmtopbm.1'
X.TH pgmtopbm 1 "26 July 1988"
X.SH NAME
Xpgmtopbm - convert a portable graymap into a portable bitmap
X.SH SYNOPSIS
Xpgmtopbm [-floyd|-fs | -threshold | -dither8|-d8 |
X	  -cluster3|-c3|-cluster4|-c4|-cluster8|-c8] [-value <val>] [pgmfile]
X.SH DESCRIPTION
XReads a portable graymap as input.
XProduces a portable bitmap as output.
XThe default quantization method is boustrophedonic Floyd-Steinberg error
Xdiffusion (-floyd).
XAlso available are simple thresholding;
XBayer's ordered dither (-dither8) with a 16x16 matrix;
Xthree different sizes of 45-degree clustered-dot dither
X(-cluster3, -cluster4, -cluster8);
X.PP
XFloyd-Steinberg will almost always give the best looking results; however,
Xlooking good is not always what you want.
XFor instance, thresholding can be used in a pipeline with the ppmconvol
Xtool, for tasks like edge and peak detection.
XAnd clustered-dot dithering gives a newspaper-ish look, a useful special effect.
X.PP
XThe -value flag alters the thresholding value for Floyd-Steinberg and
Xsimple threshholding.
XIt should be a real number between 0 and 1.
XAbove 0.5 means darker images; below 0.5 means lighter.
X.PP
XAll flags can be abbreviated to their shortest unique prefix.
X.PP
XNote that there is no pbmtopgm converter, because any pgm program can
Xread pbm files automagically.
X.SH REFERENCES
XThe only reference you need for this stuff is "Digital Halftoning" by
XRobert Ulichney, MIT Press, ISBN 0-262-21009-6.
X.SH "SEE ALSO"
Xpbmreduce(1), pgm(5), pbm(5)
X.SH AUTHOR
XCopyright (C) 1989 by Jef Poskanzer.
X
XPermission to use, copy, modify, and distribute this software and its
Xdocumentation for any purpose and without fee is hereby granted, provided
Xthat the above copyright notice appear in all copies and that both that
Xcopyright notice and this permission notice appear in supporting
Xdocumentation.  This software is provided "as is" without express or
Ximplied warranty.
SHAR_EOF
if test 1883 -ne "`wc -c < 'pgm/pgmtopbm.1'`"
then
	echo shar: error transmitting "'pgm/pgmtopbm.1'" '(should have been 1883 characters)'
fi
fi # end of overwriting check
if test ! -d 'pgm'
then
	echo shar: creating directory "'pgm'"
	mkdir 'pgm'
fi
echo shar: extracting "'pgm/dithers.h'" '(3499 characters)'
if test -f 'pgm/dithers.h'
then
	echo shar: will not over-write existing file "'pgm/dithers.h'"
else
sed 's/^X//' << \SHAR_EOF > 'pgm/dithers.h'
X/*
X** dithers.h
X**
X** Here are some dithering matrices.  They are all taken from "Digital
X** Halftoning" by Robert Ulichney, MIT Press, ISBN 0-262-21009-6.
X*/
X
X/*
X** Order-6 ordered dithering matrix.  Note that smaller ordered dithers
X** have no advantage over larger ones, so use dither8 instead.
X*/
Xstatic int dither6[8][8] = {
X     1, 59, 15, 55,  2, 56, 12, 52,
X    33, 17, 47, 31, 34, 18, 44, 28,
X     9, 49,  5, 63, 10, 50,  6, 60,
X    41, 25, 37, 21, 42, 26, 38, 22,
X     3, 57, 13, 53,  0, 58, 14, 54,
X    35, 19, 45, 29, 32, 16, 46, 30,
X    11, 51,  7, 61,  8, 48,  4, 62,
X    43, 27, 39, 23, 40, 24, 36, 20 };
X
X/* Order-8 ordered dithering matrix. */
Xstatic int dither8[16][16] = {
X      1,235, 59,219, 15,231, 55,215,  2,232, 56,216, 12,228, 52,212,
X    129, 65,187,123,143, 79,183,119,130, 66,184,120,140, 76,180,116,
X     33,193, 17,251, 47,207, 31,247, 34,194, 18,248, 44,204, 28,244,
X    161, 97,145, 81,175,111,159, 95,162, 98,146, 82,172,108,156, 92,
X      9,225, 49,209,  5,239, 63,223, 10,226, 50,210,  6,236, 60,220,
X    137, 73,177,113,133, 69,191,127,138, 74,178,114,134, 70,188,124,
X     41,201, 25,241, 37,197, 21,255, 42,202, 26,242, 38,198, 22,252,
X    169,105,153, 89,165,101,149, 85,170,106,154, 90,166,102,150, 86,
X      3,233, 57,217, 13,229, 53,213,  0,234, 58,218, 14,230, 54,214,
X    131, 67,185,121,141, 77,181,117,128, 64,186,122,142, 78,182,118,
X     35,195, 19,249, 45,205, 29,245, 32,192, 16,250, 46,206, 30,246,
X    163, 99,147, 83,173,109,157, 93,160, 96,144, 80,174,110,158, 94,
X     11,227, 51,211,  7,237, 61,221,  8,224, 48,208,  4,238, 62,222,
X    139, 75,179,115,135, 71,189,125,136, 72,176,112,132, 68,190,126,
X     43,203, 27,243, 39,199, 23,253, 40,200, 24,240, 36,196, 20,254,
X    171,107,155, 91,167,103,151, 87,168,104,152, 88,164,100,148, 84 };
X
X/* Order-3 clustered dithering matrix. */
Xstatic int cluster3[6][6] = {
X     9,11,10, 8, 6, 7,
X    12,17,16, 5, 0, 1,
X    13,14,15, 4, 3, 2,
X     8, 6, 7, 9,11,10,
X     5, 0, 1,12,17,16,
X     4, 3, 2,13,14,15 };
X
X/* Order-4 clustered dithering matrix. */
Xstatic int cluster4[8][8] = {
X    18,20,19,16,13,11,12,15,
X    27,28,29,22, 4, 3, 2, 9,
X    26,31,30,21, 5, 0, 1,10,
X    23,25,24,17, 8, 6, 7,14,
X    13,11,12,15,18,20,19,16,
X     4, 3, 2, 9,27,28,29,22,
X     5, 0, 1,10,26,31,30,21,
X     8, 6, 7,14,23,25,24,17 };
X
X/* Order-8 clustered dithering matrix. */
Xstatic int cluster8[16][16] = {
X     64, 69, 77, 87, 86, 76, 68, 67, 63, 58, 50, 40, 41, 51, 59, 60,
X     70, 94,100,109,108, 99, 93, 75, 57, 33, 27, 18, 19, 28, 34, 52,
X     78,101,114,116,115,112, 98, 83, 49, 26, 13, 11, 12, 15, 29, 44,
X     88,110,123,124,125,118,107, 85, 39, 17,  4,  3,  2,  9, 20, 42,
X     89,111,122,127,126,117,106, 84, 38, 16,  5,  0,  1, 10, 21, 43,
X     79,102,119,121,120,113, 97, 82, 48, 25,  8,  6,  7, 14, 30, 45,
X     71, 95,103,104,105, 96, 92, 74, 56, 32, 24, 23, 22, 31, 35, 53,
X     65, 72, 80, 90, 91, 81, 73, 66, 62, 55, 47, 37, 36, 46, 54, 61,
X     63, 58, 50, 40, 41, 51, 59, 60, 64, 69, 77, 87, 86, 76, 68, 67,
X     57, 33, 27, 18, 19, 28, 34, 52, 70, 94,100,109,108, 99, 93, 75,
X     49, 26, 13, 11, 12, 15, 29, 44, 78,101,114,116,115,112, 98, 83,
X     39, 17,  4,  3,  2,  9, 20, 42, 88,110,123,124,125,118,107, 85,
X     38, 16,  5,  0,  1, 10, 21, 43, 89,111,122,127,126,117,106, 84,
X     48, 25,  8,  6,  7, 14, 30, 45, 79,102,119,121,120,113, 97, 82,
X     56, 32, 24, 23, 22, 31, 35, 53, 71, 95,103,104,105, 96, 92, 74,
X     62, 55, 47, 37, 36, 46, 54, 61, 65, 72, 80, 90, 91, 81, 73, 66 };
SHAR_EOF
if test 3499 -ne "`wc -c < 'pgm/dithers.h'`"
then
	echo shar: error transmitting "'pgm/dithers.h'" '(should have been 3499 characters)'
fi
fi # end of overwriting check
if test ! -d 'pgm'
then
	echo shar: creating directory "'pgm'"
	mkdir 'pgm'
fi
echo shar: extracting "'pgm/tiff.h'" '(2762 characters)'
if test -f 'pgm/tiff.h'
then
	echo shar: will not over-write existing file "'pgm/tiff.h'"
else
sed 's/^X//' << \SHAR_EOF > 'pgm/tiff.h'
X/* 
X**---------------------------------------------------------------------
X** Tiff.h
X**---------------------------------------------------------------------
X**      Copyright 1988 by Paul J. Emerson 
X**                                                                     
X**      Permission to use, copy, modify, and distribute this software 
X**      and its documentation for any purpose and without fee is        
X**      hereby granted, provided that the above copyright notice        
X**      appear in all copies and that both that copyright notice and    
X**      this permission notice appear in supporting documentation, and  
X**      that the name of Paul J. Emerson not be used in advertising or 
X**      publicity pertaining to distribution of the software without 
X**      specific, written prior permission.  Paul J. Emerson makes no 
X**      representations about the suitability of this software for 
X**      any purpose.  It is provided "as is" without express or implied 
X**      warranty.          
X**
X**      Version 1.0 
X**        Paul Emerson (ucf-cs!sdgsun!paul) December 1988
X**
X**---------------------------------------------------------------------
X*/
X
X/* Types as defined in the TIFF standard for SUN3 */
X
Xtypedef unsigned char  BYTE;         /* 8-bits */
Xtypedef unsigned char  ASCII;        /* 8-bits */
Xtypedef unsigned short SHORT;        /* 16 bits */
Xtypedef unsigned int   LONG;         /* 32 bits */
Xtypedef unsigned long  RATIONAL;     /* 2 LONG's numerator : denominator
X
X#define INFINITY  99999
X
X/*
X** Data Types
X*/
X
X#define TYPEBYTE     1      
X#define TYPEASCII    2     
X#define TYPESHORT    3    
X#define TYPELONG     4   
X#define TYPERATIONAL 5  
X
Xstruct TiffHeader 
X	   {
X	   BYTE            ByteOrder[2];
X	   SHORT           Version; 
X	   LONG            IdfOffset;
X	   };
X
Xstruct IDF
X	   {
X	   SHORT    NumEntries;
X	   struct   IDF_Entry *idfptr;	
X	   };
X
Xstruct IDF_Entry 
X	   {
X	   SHORT Tag;
X	   SHORT Type;
X	   LONG  Length;
X	   LONG  ValueOffset;
X	   };
X
Xstruct  Tiffstruct 
X     {
X	 int SubFileType;
X	 int ImageWidth;
X	 int ImageLength;
X	 int BitsPerSample;
X	 int Compression;
X	 int PhotoInterp;
X	 int Threshold;
X	 int CellWidth;
X	 int CellLength;
X	 int FillOrder;
X	 char *DocName;
X	 char *ImageDescript;
X	 char *Make;
X	 char *Model;
X	 int StOffsetCnt;
X	 LONG *StripOffset;
X	 int Orientation;
X	 int SamplesPixel;
X	 int RowsStrip;
X	 int StripByteCnt;
X	 LONG *SBytesCntOffset;
X	 int MinSampleValue;
X	 int MaxSampleValue;
X	 int Xres;
X	 int Yres;
X	 int PlanarConfig;
X	 char *PageName;
X	 int XPos; 
X	 int YPos;
X	 int FreeOffsets;
X	 int FreeByteCount;
X	 int GrayResUnit;
X	 int GrayResCurve;
X	 int Group3Option;
X	 int Group4Option;
X	 int ResolutionUnit;
X	 int PageNumber;
X	 int ColorResUnit;
X	 int ColorResCurv;
X	 };
SHAR_EOF
if test 2762 -ne "`wc -c < 'pgm/tiff.h'`"
then
	echo shar: error transmitting "'pgm/tiff.h'" '(should have been 2762 characters)'
fi
fi # end of overwriting check
if test ! -d 'pgm'
then
	echo shar: creating directory "'pgm'"
	mkdir 'pgm'
fi
echo shar: extracting "'pgm/pgmtops.c'" '(9439 characters)'
if test -f 'pgm/pgmtops.c'
then
	echo shar: will not over-write existing file "'pgm/pgmtops.c'"
else
sed 's/^X//' << \SHAR_EOF > 'pgm/pgmtops.c'
X/* pgmtops.c - read a portable graymap 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 <stdio.h>
X#include "pgm.h"
X#ifdef SYSV
X#include <string.h>
X#define index strchr
X#else /*SYSV*/
X#include <strings.h>
X#endif /*SYSV*/
X
X#define max(a,b) ((a) > (b) ? (a) : (b))
X
Xmain( argc, argv )
Xint argc;
Xchar *argv[];
X    {
X    FILE *ifd;
X    register gray *grayrow, *gP;
X    int argn, rleflag, rows, cols, format, bps, padright, row, col;
X    gray maxval;
X    float scale;
X    char name[100], *cp;
X    int maxvaltobps();
X    char *usage = "[-rle] [-scale <x>] [pgmfile]";
X
X    pm_progname = argv[0];
X
X    argn = 1;
X    rleflag = 0;
X    scale = 1.0;
X
X    /* Check for flags. */
X    while ( argn < argc && argv[argn][0] == '-' )
X	{
X	if ( strncmp(argv[argn],"-rle",max(strlen(argv[argn]),2)) == 0 ||
X	     strncmp(argv[argn],"-runlength",max(strlen(argv[argn]),2)) == 0 )
X	    rleflag = 1;
X	else if ( strncmp(argv[argn],"-scale",max(strlen(argv[argn]),2)) == 0 )
X	    {
X	    argn++;
X	    if ( argn == argc || sscanf( argv[argn], "%f", &scale ) != 1 )
X		pm_usage( usage );
X	    }
X	else
X	    pm_usage( usage );
X	argn++;
X	}
X
X    if ( argn < argc )
X	{
X	ifd = 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	ifd = stdin;
X	strcpy( name, "noname" );
X	}
X
X    if ( argn != argc )
X	pm_usage( usage );
X
X    pgm_readpgminit( ifd, &cols, &rows, &maxval, &format );
X    grayrow = pgm_allocrow( cols );
X
X    /* Figure out bps. */
X    bps = maxvaltobps( maxval );
X    
X    /* Compute padding to round cols * bps up to the nearest multiple of 8. */
X    padright = ( ( cols * bps + 7 ) / 8 ) * 8 - cols * bps;
X
X    if ( rleflag )
X	rleputinit( name, cols, rows, bps, scale );
X    else
X	putinit( name, cols, rows, bps, scale );
X    for ( row = 0; row < rows; row++ )
X	{
X	pgm_readpgmrow( ifd, grayrow, cols, maxval, format );
X        for ( col = 0, gP = grayrow; col < cols; col++, gP++ )
X	    if ( rleflag )
X		rleputgray( *gP );
X	    else
X		putgray( *gP );
X	for ( col = 0; col < padright; col++ )
X	    if ( rleflag )
X		rleputgray( maxval );
X	    else
X		putgray( maxval );
X        }
X
X    pm_close( ifd );
X
X    if ( rleflag )
X	rleputrest( );
X    else
X	putrest( );
X
X    exit( 0 );
X    }
X
Xint
Xmaxvaltobps( maxval )
Xgray maxval;
X    {
X    switch ( maxval )
X	{
X	case 1:
X	return 1;
X
X	case 3:
X	return 2;
X
X	case 15:
X	return 4;
X
X	case 255:
X	return 8;
X
X#ifdef notdef
X	case 7:
X	return 3;
X
X	case 31:
X	return 5;
X
X	case 63:
X	return 6;
X
X	case 127:
X	return 7;
X#endif /*notdef*/
X
X	default:
X	pm_error( "maxval of %d is not supported", maxval, 0,0,0,0 );
X	/* NOTREACHED */
X	}
X    }
X
X
Xint bitspersample, item, bitsperitem, bitshift, itemsperline, items;
Xint rleitem, rlebitsperitem, rlebitshift;
Xint repeat, itembuf[128], count, repeatitem, repeatcount;
X#define HSBUFSIZ 256
X
Xputinit( name, cols, rows, bps, scale )
Xchar *name;
Xint cols, rows, bps;
Xfloat scale;
X    {
X    float scols, srows, llx, lly;
X
X    scols = scale * cols * 0.96 + 0.5;	/*   0.96 is the multiple of   */
X    srows = scale * rows * 0.96 + 0.5;	/* 72/300 that is closest to 1 */
X    llx = ( 612.0 - scols ) / 2;
X    lly = ( 792.0 - srows ) / 2;
X    if ( llx < 0.0 || lly < 0.0 )
X	pm_message( "warning, image too large for page", 0,0,0,0,0 );
X
X    printf( "%%!PS-Adobe-2.0 EPSF-2.0\n" );
X    printf( "%%%%Creator: pgmtops\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, (int) ( llx + scols ), (int) ( lly + srows ) );
X    printf( "%%%%EndComments\n" );
X    printf( "%%%%EndProlog\n" );
X    printf( "%%%%Page 1 1\n" );
X    printf( "/picstr %d string def\n", HSBUFSIZ );
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    printf( "{ currentfile picstr readhexstring pop }\n" );
X    printf( "image\n" );
X
X    bitspersample = bps;
X    itemsperline = items = 0;
X    item = 0;
X    bitsperitem = 0;
X    bitshift = 8 - bitspersample;
X    }
X
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
Xputgray( g )
Xgray g;
X    {
X    if ( bitsperitem == 8 )
X	putitem( );
X    item += g << bitshift;
X    bitsperitem += bitspersample;
X    bitshift -= bitspersample;
X    }
X
Xputrest( )
X    {
X    if ( bitsperitem > 0 )
X	putitem( );
X    while ( items % HSBUFSIZ != 0 )
X	putitem( );
X    printf( "\n" );
X    printf( "grestore\n" );
X    printf( "showpage\n" );
X    printf( "%%%%Trailer\n" );
X    }
X
Xrleputinit( name, cols, rows, bps, scale )
Xchar *name;
Xint cols, rows, bps;
Xfloat scale;
X    {
X    float scols, srows, llx, lly;
X
X    scols = scale * cols * 0.96 + 0.5;	/*   0.96 is the multiple of   */
X    srows = scale * rows * 0.96 + 0.5;	/* 72/300 that is closest to 1 */
X    llx = ( 612.0 - scols ) / 2;
X    lly = ( 792.0 - srows ) / 2;
X    if ( llx < 0.0 || lly < 0.0 )
X	pm_message( "warning, image too large for page", 0,0,0,0,0 );
X
X    printf( "%%!PS-Adobe-2.0 EPSF-2.0\n" );
X    printf( "%%%%Creator: pgmtops\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, (int) ( llx + scols ), (int) ( lly + srows ) );
X    printf( "%%%%EndComments\n" );
X    printf( "%%%%EndProlog\n" );
X    printf( "/rlestr1 1 string def\n" );
X    printf( "/rlestr 128 string def\n" );
X    printf( "/readrlestring {\n" );
X    printf( "  currentfile rlestr1 readhexstring pop  0 get\n" );
X    printf( "  dup 127 le {\n" );
X    printf( "    currentfile rlestr 0  4 3 roll  1 add  getinterval\n" );
X    printf( "    readhexstring  pop\n" );
X    printf( "  } {\n" );
X    printf( "    256 exch sub  dup\n" );
X    printf( "    currentfile rlestr1 readhexstring pop  0 get\n" );
X    printf( "    exch 0 exch 1 exch 1 sub { rlestr exch 2 index put } for\n" );
X    printf( "    pop  rlestr exch 0 exch getinterval\n" );
X    printf( "  } ifelse\n" );
X    printf( "} bind def\n" );
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    printf( "{ readrlestring }\n" );
X    printf( "image\n" );
X
X    bitspersample = bps;
X    itemsperline = items = 0;
X    rleitem = 0;
X    rlebitsperitem = 0;
X    rlebitshift = 8 - bitspersample;
X    repeat = 1;
X    count = 0;
X    }
X
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
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 - bitsperitem;
X    }
X
Xrleputgray( g )
Xgray g;
X    {
X    if ( rlebitsperitem == 8 )
X	{
X	rleputitem( );
X	}
X    rleitem += g << rlebitshift;
X    rlebitsperitem += bitsperitem;
X    rlebitshift -= bitsperitem;
X    }
X
Xrleputrest( )
X    {
X    if ( rlebitsperitem > 0 )
X	rleputitem( );
X    if ( count > 0 )
X	rleputbuffer( );
X    printf( "\n" );
X    printf( "grestore\n" );
X    printf( "showpage\n" );
X    printf( "%%%%Trailer\n" );
X    }
SHAR_EOF
if test 9439 -ne "`wc -c < 'pgm/pgmtops.c'`"
then
	echo shar: error transmitting "'pgm/pgmtops.c'" '(should have been 9439 characters)'
fi
fi # end of overwriting check
if test ! -d 'pgm'
then
	echo shar: creating directory "'pgm'"
	mkdir 'pgm'
fi
echo shar: extracting "'pgm/pgmtops.1'" '(1677 characters)'
if test -f 'pgm/pgmtops.1'
then
	echo shar: will not over-write existing file "'pgm/pgmtops.1'"
else
sed 's/^X//' << \SHAR_EOF > 'pgm/pgmtops.1'
X.TH pgmtops 1 "04 March 1989"
X.SH NAME
Xpgmtops - convert a portable graymap into Encapsulated PostScript
X.SH SYNOPSIS
Xpgmtops [-rle] [-scale <x>] [<pgmfile>]
X.SH DESCRIPTION
XReads a portable graymap as input.
XProduces Encapsulated PostScript as output.
X.PP
XThe -scale flag controls the scale of the result.  The default scale is 1,
Xwhich results in one pgm pixel producing a 3x3 square of PostScript
Xpixels.  On a 300 dpi printer such as the Apple LaserWriter, this 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 pgm pixel per LaserWriter pixel, use "-s 0.333333".
X.PP
XThe -rle flag specifies run-length compression.  This may save time
Xif the host-to-printer link is slow; but normally the printer's processing
Xtime dominates, so -rle makes things slower.
X.PP
XAll flags can be abbreviated to their shortest unique prefix.
X.PP
XNote that there is no pstopgm
Xtool - this transformation is one-way, because a pstopgm tool would
Xbe a full-fledged PostScript interpreter, which is beyond the scope
Xof this package.
XHowever, see the psidtopgm tool.
X.SH "SEE ALSO"
Xpsidtopgm(1), pgm(5), ppmtops(1)
X.BUGS
XOne NeXT user reported that, while the EPS image did load, it also
Xlocked up his machine.
X.SH AUTHOR
XCopyright (C) 1989 by Jef Poskanzer.
X
XPermission to use, copy, modify, and distribute this software and its
Xdocumentation for any purpose and without fee is hereby granted, provided
Xthat the above copyright notice appear in all copies and that both that
Xcopyright notice and this permission notice appear in supporting
Xdocumentation.  This software is provided "as is" without express or
Ximplied warranty.
SHAR_EOF
if test 1677 -ne "`wc -c < 'pgm/pgmtops.1'`"
then
	echo shar: error transmitting "'pgm/pgmtops.1'" '(should have been 1677 characters)'
fi
fi # end of overwriting check
if test ! -d 'pgm'
then
	echo shar: creating directory "'pgm'"
	mkdir 'pgm'
fi
echo shar: extracting "'pgm/psidtopgm.c'" '(2883 characters)'
if test -f 'pgm/psidtopgm.c'
then
	echo shar: will not over-write existing file "'pgm/psidtopgm.c'"
else
sed 's/^X//' << \SHAR_EOF > 'pgm/psidtopgm.c'
X/* psidtopgm.c - convert PostScript "image" data into a portable graymap
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 <stdio.h>
X#include "pgm.h"
X#ifdef SYSV
X#include <string.h>
X#else /*SYSV*/
X#include <strings.h>
X#endif /*SYSV*/
X
Xmain( argc, argv )
Xint argc;
Xchar *argv[];
X    {
X    FILE *ifd;
X    register gray *grayrow, *gP;
X    int argn, row;
X    register int col, val;
X    int maxval;
X    int rows, cols, bitspersample;
X    char *usage = "<width> <height> <bits/sample> [imagedata]";
X
X    pm_progname = argv[0];
X
X    argn = 1;
X
X    if ( argn + 3 > argc )
X	pm_usage( usage );
X
X    cols = atoi( argv[argn++] );
X    rows = atoi( argv[argn++] );
X    bitspersample = atoi( argv[argn++] );
X    if ( cols <= 0 || rows <= 0 || bitspersample <= 0 )
X	pm_usage( usage );
X
X    if ( argn < argc )
X	{
X	ifd = pm_openr( argv[argn] );
X	argn++;
X	}
X    else
X	ifd = stdin;
X
X    if ( argn != argc )
X	pm_usage( usage );
X
X    maxval = ( 1 << bitspersample ) - 1;
X    if ( maxval > PGM_MAXMAXVAL )
X	pm_error( "bits/sample is too large - try recompiling with a larger gray type" );
X
X    pgm_writepgminit( stdout, cols, rows, (gray) maxval );
X    grayrow = pgm_allocrow( ( cols + 7 ) / 8 * 8 );
X    for ( row = 0; row < rows; row++)
X	{
X	for ( col = 0, gP = grayrow; col < cols; )
X	    {
X	    val = gethexit( ifd ) << 4;
X	    val += gethexit( ifd );
X	    switch ( bitspersample )
X		{
X		case 1:
X		*gP++ = val >> 7;
X		*gP++ = ( val >> 6 ) & 0x1;
X		*gP++ = ( val >> 5 ) & 0x1;
X		*gP++ = ( val >> 4 ) & 0x1;
X		*gP++ = ( val >> 3 ) & 0x1;
X		*gP++ = ( val >> 2 ) & 0x1;
X		*gP++ = ( val >> 1 ) & 0x1;
X		*gP++ = val & 0x1;
X		col += 8;
X		break;
X
X		case 2:
X		*gP++ = val >> 6;
X		*gP++ = ( val >> 4 ) & 0x3;
X		*gP++ = ( val >> 2 ) & 0x3;
X		*gP++ = val & 0x3;
X		col += 4;
X		break;
X
X		case 4:
X		*gP++ = val >> 4;
X		*gP++ = val & 0xf;
X		col += 2;
X		break;
X
X		case 8:
X		*gP++ = val;
X		col++;
X		break;
X
X		default:
X		pm_error(
X		    "bitspersample of %d not supported", bitspersample,
X		    0,0,0,0 );
X		}
X	    }
X	pgm_writepgmrow( stdout, grayrow, cols, (gray) maxval );
X	}
X    pm_close( ifd );
X
X    exit( 0 );
X    }
X
Xint
Xgethexit( ifd )
XFILE *ifd;
X    {
X    register int i;
X    register char c;
X
X    for ( ; ; )
X	{
X	i = getc( ifd );
X	if ( i == EOF )
X	    pm_error( "premature EOF", 0,0,0,0,0 );
X	c = (char) i;
X	if ( c >= '0' && c <= '9' )
X	    return c - '0';
X	else if ( c >= 'A' && c <= 'F' )
X	    return c - 'A' + 10;
X	else if ( c >= 'a' && c <= 'f' )
X	    return c - 'a' + 10;
X	/* Else ignore - whitespace. */
X	}
X    }
SHAR_EOF
if test 2883 -ne "`wc -c < 'pgm/psidtopgm.c'`"
then
	echo shar: error transmitting "'pgm/psidtopgm.c'" '(should have been 2883 characters)'
fi
fi # end of overwriting check
if test ! -d 'pgm'
then
	echo shar: creating directory "'pgm'"
	mkdir 'pgm'
fi
echo shar: extracting "'pgm/psidtopgm.1'" '(1419 characters)'
if test -f 'pgm/psidtopgm.1'
then
	echo shar: will not over-write existing file "'pgm/psidtopgm.1'"
else
sed 's/^X//' << \SHAR_EOF > 'pgm/psidtopgm.1'
X.TH psidtopgm 1 "02 August 89"
X.SH NAME
Xpsidtopgm - convert PostScript "image" data into a portable graymap
X.SH SYNOPSIS
Xpsidtopgm <width> <height> <bits/sample> [imagedata]
X.SH DESCRIPTION
XReads the "image" data from a PostScript file as input.
XProduces a portable graymap as output.
X.PP
XThis is a very simple and limited program, and is here only because
Xso many people have asked for it.
XTo use it you have to
X.I manually
Xextract the readhexstring data portion from your PostScript file, and then
Xgive the width, height, and bits/sample on the command line.
XBefore you attempt this, you should
X.I at least
Xread the description of the "image" operator in the PostScript Language
XReference Manual.
X.PP
XIt would probably not be too hard to write a script that uses this filter
Xto read a specific variety of PostScript image, but the variation is too
Xgreat to make a general-purpose reader.
XUnless, of course, you want to write a full-fledged PostScript interpreter...
X.SH "SEE ALSO"
Xpgmtops(1), pgm(5)
X.SH AUTHOR
XCopyright (C) 1989 by Jef Poskanzer.
X
XPermission to use, copy, modify, and distribute this software and its
Xdocumentation for any purpose and without fee is hereby granted, provided
Xthat the above copyright notice appear in all copies and that both that
Xcopyright notice and this permission notice appear in supporting
Xdocumentation.  This software is provided "as is" without express or
Ximplied warranty.
SHAR_EOF
if test 1419 -ne "`wc -c < 'pgm/psidtopgm.1'`"
then
	echo shar: error transmitting "'pgm/psidtopgm.1'" '(should have been 1419 characters)'
fi
fi # end of overwriting check
if test ! -d 'pgm'
then
	echo shar: creating directory "'pgm'"
	mkdir 'pgm'
fi
echo shar: extracting "'pgm/fitstopgm.c'" '(4533 characters)'
if test -f 'pgm/fitstopgm.c'
then
	echo shar: will not over-write existing file "'pgm/fitstopgm.c'"
else
sed 's/^X//' << \SHAR_EOF > 'pgm/fitstopgm.c'
X/* fitstopgm.c - read a FITS file and produce a portable graymap
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 <stdio.h>
X#include "pgm.h"
X#ifdef SYSV
X#include <string.h>
X#else /*SYSV*/
X#include <strings.h>
X#endif /*SYSV*/
X
X#define min(a,b) ((a) < (b) ? (a) : (b))
X
Xstruct FITS_Header {
X    int simple;		/* basic format or not */
X    int bitpix;		/* number of bits per pixel */
X    int naxis;		/* number of axes */
X    int naxis1;		/* number of points on axis 1 */
X    int naxis2;		/* number of points on axis 2 */
X    double datamin;	/* min # */
X    double datamax;	/* max # */
X    double bzero;	/* ??? */
X    double bscale;	/* ??? */
X    };
X
Xmain( argc, argv )
Xint argc;
Xchar *argv[];
X    {
X    FILE *ifd;
X    register gray *grayrow, *gP;
X    int argn, row;
X    register int col;
X    gray maxval;
X    double fmaxval, scale;
X    int rows, cols;
X    struct FITS_Header h;
X
X    pm_progname = argv[0];
X
X    argn = 1;
X
X    if ( argn < argc )
X	{
X	ifd = pm_openr( argv[argn] );
X	argn++;
X	}
X    else
X	ifd = stdin;
X
X    if ( argn != argc )
X	pm_usage( "[fitsfile]" );
X
X    read_fits_header( ifd, &h );
X
X    if ( ! h.simple )
X	pm_error( "FITS file is not in simple format, can't read", 0,0,0,0,0 );
X    switch ( h.bitpix )
X	{
X	case 8:
X	fmaxval = 255.0;
X	break;
X
X	case 16:
X	fmaxval = 65535.0;
X	break;
X
X	case 32:
X	fmaxval = 4294967295.0;
X	break;
X
X	default:
X	pm_error( "unusual bits per pixel (%d), can't read", h.bitpix, 0,0,0,0 );
X	}
X    if ( h.naxis != 2 )
X	pm_error( "FITS file has %d axes, can't read", h.naxis, 0,0,0,0 );
X    cols = h.naxis1;
X    rows = h.naxis2;
X    maxval = min( fmaxval, PGM_MAXMAXVAL );
X    scale = maxval / ( h.datamax - h.datamin );
X
X    pgm_writepgminit( stdout, cols, rows, maxval );
X    grayrow = pgm_allocrow( cols );
X    for ( row = 0; row < rows; row++)
X	{
X	for ( col = 0, gP = grayrow; col < cols; col++, gP++ )
X	    {
X	    int ich;
X	    double val;
X
X	    switch ( h.bitpix )
X		{
X		case 8:
X		ich = getc( ifd );
X		if ( ich == EOF )
X		    pm_error( "premature EOF", 0,0,0,0,0 );
X		val = ich;
X		break;
X
X		case 16:
X		ich = getc( ifd );
X		if ( ich == EOF )
X		    pm_error( "premature EOF", 0,0,0,0,0 );
X		val = ich << 8;
X		ich = getc( ifd );
X		if ( ich == EOF )
X		    pm_error( "premature EOF", 0,0,0,0,0 );
X		val += ich;
X		break;
X
X		case 32:
X		ich = getc( ifd );
X		if ( ich == EOF )
X		    pm_error( "premature EOF", 0,0,0,0,0 );
X		val = ich << 24;
X		ich = getc( ifd );
X		if ( ich == EOF )
X		    pm_error( "premature EOF", 0,0,0,0,0 );
X		val += ich << 16;
X		ich = getc( ifd );
X		if ( ich == EOF )
X		    pm_error( "premature EOF", 0,0,0,0,0 );
X		val += ich << 8;
X		ich = getc( ifd );
X		if ( ich == EOF )
X		    pm_error( "premature EOF", 0,0,0,0,0 );
X		val += ich;
X		break;
X
X		default:
X		pm_error( "can't happen", 0,0,0,0,0 );
X		}
X	    *gP = (gray) ( scale * ( val * h.bscale + h.bzero - h.datamin) );
X	    }
X	pgm_writepgmrow( stdout, grayrow, cols, maxval );
X	}
X    pm_close( ifd );
X
X    exit( 0 );
X    }
X
Xread_fits_header( fd, hP )
XFILE *fd;
Xstruct FITS_Header *hP;
X    {
X    char buf[80];
X    int seen_end;
X    int i;
X    char c;
X
X    seen_end = 0;
X    hP->simple = 0;
X    hP->bzero = 0.0;
X    hP->bscale = 1.0;
X    hP->datamin = 0.0;
X    hP->datamax = 1.0;
X
X    while ( ! seen_end )
X	for ( i = 0; i < 36; i++ )
X	    {
X	    read_card( fd, buf );
X
X	    if ( sscanf( buf, "SIMPLE = %c", &c ) == 1 )
X		{
X		if ( c == 'T' || c == 't' )
X		    hP->simple = 1;
X		}
X	    else if ( sscanf( buf, "BITPIX = %d", &(hP->bitpix) ) == 1 );
X	    else if ( sscanf( buf, "NAXIS = %d", &(hP->naxis) ) == 1 );
X	    else if ( sscanf( buf, "NAXIS1 = %d", &(hP->naxis1) ) == 1 );
X	    else if ( sscanf( buf, "NAXIS2 = %d", &(hP->naxis2) ) == 1 );
X	    else if ( sscanf( buf, "DATAMIN = %lg", &(hP->datamin) ) == 1 );
X	    else if ( sscanf( buf, "DATAMAX = %lg", &(hP->datamax) ) == 1 );
X	    else if ( sscanf( buf, "BZERO = %lg", &(hP->bzero) ) == 1 );
X	    else if ( sscanf( buf, "BSCALE = %lg", &(hP->bscale) ) == 1 );
X	    else if ( strncmp( buf, "END ", 4 ) == 0 ) seen_end = 1;
X	    }
X    }
X
Xread_card( fd, buf )
XFILE *fd;
Xchar *buf;
X    {
X    if ( fread( buf, 1, 80, fd ) == 0 )
X	pm_error( "error reading header", 0,0,0,0,0 );
X    }
SHAR_EOF
if test 4533 -ne "`wc -c < 'pgm/fitstopgm.c'`"
then
	echo shar: error transmitting "'pgm/fitstopgm.c'" '(should have been 4533 characters)'
fi
fi # end of overwriting check
if test ! -d 'pgm'
then
	echo shar: creating directory "'pgm'"
	mkdir 'pgm'
fi
echo shar: extracting "'pgm/fitstopgm.1'" '(922 characters)'
if test -f 'pgm/fitstopgm.1'
then
	echo shar: will not over-write existing file "'pgm/fitstopgm.1'"
else
sed 's/^X//' << \SHAR_EOF > 'pgm/fitstopgm.1'
X.TH fitstopgm 1 "20 September 89"
X.SH NAME
Xfitstopgm - convert a FITS file into a portable graymap
X.SH SYNOPSIS
Xfitstopgm [fitsfile]
X.SH DESCRIPTION
XReads a FITS file as input.
XProduces a portable graymap as output.
XThe results may need to be flipped top for bottom; if so, just
Xpipe the output through pnmflip -tb.
X.PP
XFITS stands for Flexible Image Transport System.  A full description
Xcan be found in Astronomy & Astrophysics Supplement Series 44 (1981),
Xpage 363.
X.SH "SEE ALSO"
Xpgmtofits(1), pgm(5)
X.SH AUTHOR
XCopyright (C) 1989 by Jef Poskanzer.
X
XPermission to use, copy, modify, and distribute this software and its
Xdocumentation for any purpose and without fee is hereby granted, provided
Xthat the above copyright notice appear in all copies and that both that
Xcopyright notice and this permission notice appear in supporting
Xdocumentation.  This software is provided "as is" without express or
Ximplied warranty.
SHAR_EOF
if test 922 -ne "`wc -c < 'pgm/fitstopgm.1'`"
then
	echo shar: error transmitting "'pgm/fitstopgm.1'" '(should have been 922 characters)'
fi
fi # end of overwriting check
#	End of shell archive
exit 0