PBMPLUS, part 9 of 18

Jef Poskanzer pokey at well.UUCP
Thu Sep 14 21:25:18 AEST 1989


#! /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/pgmtops.c
#	pgm/pgmtops.1
#	pgm/psidtopgm.c
#	pgm/psidtopgm.1
#	pgm/fitstopgm.c
#	pgm/fitstopgm.1
# This archive created: Thu Sep 14 03:43:38 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'" '(7016 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#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#include "pgm.h"
X#include "pbm.h"
X#include "dithers.h"
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 7016 -ne "`wc -c < 'pgm/pgmtopbm.c'`"
then
	echo shar: error transmitting "'pgm/pgmtopbm.c'" '(should have been 7016 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/pgmtops.c'" '(9133 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#ifdef	SYSV
X#include <string.h>
X#define index strchr
X#else	SYSV
X#include <strings.h>
X#endif	SYSV
X#include "pgm.h"
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    int scols, srows, llx, lly;
X
X    scols = cols * 0.96 + 0.5;	/*   0.96 is the multiple of   */
X    srows = rows * 0.96 + 0.5;	/* 72/300 that is closest to 1 */
X    llx = 300 - ( scols / 2 );
X    lly = 400 - ( srows / 2 );
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", llx, lly, llx + scols, 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( "%d %d translate\n", llx, lly );
X    printf( "%g %g scale\n", scale, scale );
X    printf( "%d %d 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    if ( itemsperline == 30 )
X	{
X	putchar( '\n' );
X	itemsperline = 0;
X	}
X    printf( "%02x", item );
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    int scols, srows, llx, lly;
X
X    scols = cols * 0.96 + 0.5;	/*   0.96 is the multiple of   */
X    srows = rows * 0.96 + 0.5;	/* 72/300 that is closest to 1 */
X    llx = 300 - ( scols / 2 );
X    lly = 400 - ( srows / 2 );
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", llx, lly, llx + scols, 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( "%d %d translate\n", llx, lly );
X    printf( "%g %g scale\n", scale, scale );
X    printf( "%d %d 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 9133 -ne "`wc -c < 'pgm/pgmtops.c'`"
then
	echo shar: error transmitting "'pgm/pgmtops.c'" '(should have been 9133 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'" '(2745 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#ifdef	SYSV
X#include <string.h>
X#else	SYSV
X#include <strings.h>
X#endif	SYSV
X#include "pgm.h"
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    gray 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
X    pgm_writepgminit( stdout, cols, rows, 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, 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 2745 -ne "`wc -c < 'pgm/psidtopgm.c'`"
then
	echo shar: error transmitting "'pgm/psidtopgm.c'" '(should have been 2745 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'" '(3140 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#ifdef	SYSV
X#include <string.h>
X#else	SYSV
X#include <strings.h>
X#endif	SYSV
X#include "pgm.h"
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    int maxpix;		/* max # */
X    int minpix;		/* min # */
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    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    if ( h.bitpix != 8 )
X	pm_error( "bits per pixel is != 8, can't read", h.naxis, 0,0,0,0 );
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
X    maxval = h.maxpix - h.minpix;
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
X	    ich = getc( ifd );
X	    if ( ich == EOF )
X		pm_error( "premature EOF", 0,0,0,0,0 );
X	    *gP = (gray) ( ich - h.minpix );
X	    /* (I'm not certain we're supposed to normalize to minpix..maxpix
X		liek this, but it seems to look better this way.) */
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 i;
X    char c;
X
X    hP->simple = 0;
X
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	    ;
X	else if ( sscanf( buf, "NAXIS = %d", &(hP->naxis) ) == 1 )
X	    ;
X	else if ( sscanf( buf, "NAXIS1 = %d", &(hP->naxis1) ) == 1 )
X	    ;
X	else if ( sscanf( buf, "NAXIS2 = %d", &(hP->naxis2) ) == 1 )
X	    ;
X	else if ( sscanf( buf, "MAXPIX = %d", &(hP->maxpix) ) == 1 )
X	    ;
X	else if ( sscanf( buf, "MINPIX = %d", &(hP->minpix) ) == 1 )
X	    ;
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 3140 -ne "`wc -c < 'pgm/fitstopgm.c'`"
then
	echo shar: error transmitting "'pgm/fitstopgm.c'" '(should have been 3140 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'" '(805 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 "25 August 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.
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"
Xpgm(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 805 -ne "`wc -c < 'pgm/fitstopgm.1'`"
then
	echo shar: error transmitting "'pgm/fitstopgm.1'" '(should have been 805 characters)'
fi
fi # end of overwriting check
#	End of shell archive
exit 0



More information about the Alt.sources mailing list