PBMPLUS, part 15 of 18
Jef Poskanzer
pokey at well.UUCP
Thu Sep 14 21:26:04 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:
# ppm/qrttoppm.c
# ppm/qrttoppm.1
# ppm/ppmtops.c
# ppm/ppmtops.1
# ppm/ppmtogif.c
# ppm/ppmtogif.1
# ppm/ppmtoilbm.c
# ppm/ppmtoilbm.1
# This archive created: Thu Sep 14 03:43:48 1989
# By: Jef Poskanzer (Paratheo-Anametamystikhood Of Eris Esoteric, Ada Lovelace Cabal)
export PATH; PATH=/bin:$PATH
if test ! -d 'ppm'
then
echo shar: creating directory "'ppm'"
mkdir 'ppm'
fi
echo shar: extracting "'ppm/qrttoppm.c'" '(1788 characters)'
if test -f 'ppm/qrttoppm.c'
then
echo shar: will not over-write existing file "'ppm/qrttoppm.c'"
else
sed 's/^X//' << \SHAR_EOF > 'ppm/qrttoppm.c'
X/* qrttoppm.c - read a QRT ray-tracer output file and produce a portable pixmap
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 "ppm.h"
X
Xmain( argc, argv )
Xint argc;
Xchar *argv[];
X {
X FILE *ifd;
X register pixel *pixelrow;
X int rows, cols, row, col;
X pixval maxval;
X unsigned char *buf;
X
X pm_progname = argv[0];
X
X if ( argc > 2 )
X pm_usage( "[qrtfile]" );
X
X if ( argc == 2 )
X ifd = pm_openr( argv[1] );
X else
X ifd = stdin;
X
X /* Read in the QRT file. First the header. */
X cols = getc( ifd );
X cols += getc( ifd ) << 8;
X rows = getc( ifd );
X rows += getc( ifd ) << 8;
X
X if ( cols <= 0 || rows <= 0 )
X pm_error( "invalid size: %d %d", cols, rows, 0,0,0 );
X maxval = 255;
X
X ppm_writeppminit( stdout, cols, rows, maxval );
X pixelrow = ppm_allocrow( cols );
X buf = (unsigned char *) malloc( 3 * cols );
X if ( buf == (unsigned char *) 0 )
X pm_error( "out of memory", 0,0,0,0,0 );
X
X for ( row = 0; row < rows; row++ )
X {
X (void) getc( ifd ); /* discard */
X (void) getc( ifd ); /* linenum */
X if ( fread( buf, 3 * cols, 1, ifd ) != 1 )
X pm_error( "premature EOF", 0,0,0,0,0 );
X for ( col = 0; col < cols; col++ )
X PPM_ASSIGN(
X pixelrow[col], buf[col], buf[cols + col], buf[2 * cols + col] );
X ppm_writeppmrow( stdout, pixelrow, cols, maxval );
X }
X
X pm_close( ifd );
X
X exit( 0 );
X }
SHAR_EOF
if test 1788 -ne "`wc -c < 'ppm/qrttoppm.c'`"
then
echo shar: error transmitting "'ppm/qrttoppm.c'" '(should have been 1788 characters)'
fi
fi # end of overwriting check
if test ! -d 'ppm'
then
echo shar: creating directory "'ppm'"
mkdir 'ppm'
fi
echo shar: extracting "'ppm/qrttoppm.1'" '(666 characters)'
if test -f 'ppm/qrttoppm.1'
then
echo shar: will not over-write existing file "'ppm/qrttoppm.1'"
else
sed 's/^X//' << \SHAR_EOF > 'ppm/qrttoppm.1'
X.TH qrttoppm 1 "25 August 1989"
X.SH NAME
Xqrttoppm - convert output from the QRT ray tracer into a portable pixmap
X.SH SYNOPSIS
Xqrttoppm [qrtfile]
X.SH DESCRIPTION
XReads a qrt file as input.
XProduces a portable pixmap as output.
X.SH "SEE ALSO"
Xppm(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 666 -ne "`wc -c < 'ppm/qrttoppm.1'`"
then
echo shar: error transmitting "'ppm/qrttoppm.1'" '(should have been 666 characters)'
fi
fi # end of overwriting check
if test ! -d 'ppm'
then
echo shar: creating directory "'ppm'"
mkdir 'ppm'
fi
echo shar: extracting "'ppm/ppmtops.c'" '(4720 characters)'
if test -f 'ppm/ppmtops.c'
then
echo shar: will not over-write existing file "'ppm/ppmtops.c'"
else
sed 's/^X//' << \SHAR_EOF > 'ppm/ppmtops.c'
X/* ppmtops.c - read a portable pixmap 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 "ppm.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 pixel *pixrow, *pP;
X int argn, rows, cols, format, bps, padright, row, col;
X pixval maxval;
X float scale;
X char name[100], *cp;
X char *usage = "[-scale <x>] [ppmfile]";
X
X pm_progname = argv[0];
X
X argn = 1;
X scale = 1.0;
X
X /* Check for flags. */
X while ( argn < argc && argv[argn][0] == '-' )
X {
X 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 ppm_readppminit( ifd, &cols, &rows, &maxval, &format );
X pixrow = ppm_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 putinit( name, cols, rows, bps, scale );
X for ( row = 0; row < rows; row++ )
X {
X ppm_readppmrow( ifd, pixrow, cols, maxval, format );
X for ( col = 0, pP = pixrow; col < cols; col++, pP++ )
X putpix( *pP );
X for ( col = 0; col < padright; col++ )
X putpix( maxval );
X }
X
X pm_close( ifd );
X
X putrest( );
X
X exit( 0 );
X }
X
Xint
Xmaxvaltobps( maxval )
Xpixval 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;
X#define HSBUFSIZ 384
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.)\n" );
X printf( "%%%%Creator: ppmtops\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( "false 3\n" );
X printf( "colorimage\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
Xputpix( p )
Xpixel p;
X {
X putgray( PPM_GETR( p ) );
X putgray( PPM_GETG( p ) );
X putgray( PPM_GETB( p ) );
X }
X
Xputgray( g )
Xpixval 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 }
SHAR_EOF
if test 4720 -ne "`wc -c < 'ppm/ppmtops.c'`"
then
echo shar: error transmitting "'ppm/ppmtops.c'" '(should have been 4720 characters)'
fi
fi # end of overwriting check
if test ! -d 'ppm'
then
echo shar: creating directory "'ppm'"
mkdir 'ppm'
fi
echo shar: extracting "'ppm/ppmtops.1'" '(1551 characters)'
if test -f 'ppm/ppmtops.1'
then
echo shar: will not over-write existing file "'ppm/ppmtops.1'"
else
sed 's/^X//' << \SHAR_EOF > 'ppm/ppmtops.1'
X.TH ppmtops 1 "01 September 1989"
X.SH NAME
Xppmtops - convert a portable pixmap into color Encapsulated PostScript
X.SH SYNOPSIS
Xppmtops [-scale <x>] [<ppmfile>]
X.SH DESCRIPTION
XReads a portable pixmap as input.
XProduces Encapsulated PostScript as output, using the colorimage
Xoperator.
XThis operator is only defined on color printers and very recent B&W printers.
XMost of the time you will NOT want to use ppmtops; instead, do a
Xppmtopgm | pgmtops.
X.PP
XThe -scale flag controls the scale of the result. The default scale is 1,
Xwhich results in one ppm 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 ppm pixel per LaserWriter pixel, use "-s 0.333333".
X.PP
XAll flags can be abbreviated to their shortest unique prefix.
X.PP
XNote that there is no pstoppm
Xtool - this transformation is one-way, because a pstoppm tool would
Xbe a full-fledged PostScript interpreter, which is beyond the scope
Xof this package.
X.SH "SEE ALSO"
Xppm(5), pgmtops(1), psidtopgm(1)
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 1551 -ne "`wc -c < 'ppm/ppmtops.1'`"
then
echo shar: error transmitting "'ppm/ppmtops.1'" '(should have been 1551 characters)'
fi
fi # end of overwriting check
if test ! -d 'ppm'
then
echo shar: creating directory "'ppm'"
mkdir 'ppm'
fi
echo shar: extracting "'ppm/ppmtogif.c'" '(19592 characters)'
if test -f 'ppm/ppmtogif.c'
then
echo shar: will not over-write existing file "'ppm/ppmtogif.c'"
else
sed 's/^X//' << \SHAR_EOF > 'ppm/ppmtogif.c'
X/* ppmtogif.c - read a portable pixmap and produce a GIF file
X**
X** Based on GIFENCOD by David Rowley <mgardi at watdscu.waterloo.edu>.A
X** Lempel-Zim compression based on "compress".
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 "ppm.h"
X#include "ppmcmap.h"
X
X#define MAXCOLORS 256
X
Xpixel **pixels;
Xcolorhash_table cht;
X
Xmain( argc, argv )
Xint argc;
Xchar *argv[];
X {
X FILE *ifd;
X int argn, rows, cols, colors, i, BitsPerPixel;
X pixval maxval;
X colorhist_vector chv;
X int Red[MAXCOLORS], Green[MAXCOLORS], Blue[MAXCOLORS];
X int GetPixel();
X char *usage = "[ppmfile]";
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( usage );
X
X pixels = ppm_readppm( ifd, &cols, &rows, &maxval );
X
X pm_close( ifd );
X
X /* Figure out the colormap. */
X fprintf( stderr, "(Computing colormap..." );
X fflush( stderr );
X chv = ppm_computecolorhist( pixels, cols, rows, MAXCOLORS, &colors );
X if ( chv == (colorhist_vector) 0 )
X pm_error(
X "too many colors - try running the pixmap through 'ppmquant 256'",
X 0,0,0,0,0 );
X fprintf( stderr, " Done. %d colors found.)\n", colors );
X
X /* Now turn the ppm colormap into the appropriate GIF colormap. */
X if ( maxval > 255 )
X fprintf(
X stderr, "(Maxval is not 255 -- automatically rescaling colors.)\n");
X for ( i = 0; i < colors; i++ )
X {
X if ( maxval == 255 )
X {
X Red[i] = PPM_GETR( chv[i].color );
X Green[i] = PPM_GETG( chv[i].color );
X Blue[i] = PPM_GETB( chv[i].color );
X }
X else
X {
X Red[i] = (int) PPM_GETR( chv[i].color ) * 255 / maxval;
X Green[i] = (int) PPM_GETG( chv[i].color ) * 255 / maxval;
X Blue[i] = (int) PPM_GETB( chv[i].color ) * 255 / maxval;
X }
X }
X BitsPerPixel = colorstobpp( colors );
X
X /* And make a hash table for fast lookup. */
X cht = ppm_colorhisttocolorhash( chv, colors );
X ppm_freecolorhist( chv );
X
X /* All set, let's do it. */
X GIFEncode(
X stdout, cols, rows, 0, 0, BitsPerPixel, Red, Green, Blue, GetPixel );
X
X exit( 0 );
X }
X
Xint
Xcolorstobpp( colors )
Xint colors;
X {
X int bpp;
X
X if ( colors <= 2 )
X bpp = 1;
X else if ( colors <= 4 )
X bpp = 2;
X else if ( colors <= 8 )
X bpp = 3;
X else if ( colors <= 16 )
X bpp = 4;
X else if ( colors <= 32 )
X bpp = 5;
X else if ( colors <= 64 )
X bpp = 6;
X else if ( colors <= 128 )
X bpp = 7;
X else if ( colors <= 256 )
X bpp = 8;
X else
X pm_error( "can't happen", 0,0,0,0,0 );
X
X return bpp;
X }
X
XGetPixel( x, y )
Xint x, y;
X {
X int color;
X
X color = ppm_lookupcolor( cht, pixels[y][x] );
X return color;
X }
X
X
X/*****************************************************************************
X *
X * GIFENCODE.C - GIF Image compression interface
X *
X * GIFEncode( FName, GHeight, GWidth, GInterlace, Background,
X * BitsPerPixel, Red, Green, Blue, GetPixel )
X *
X *****************************************************************************/
X
X/*
X * Pointer to function returning an int
X */
Xtypedef int (* ifunptr)();
X
X#define TRUE 1
X#define FALSE 0
X
Xint Width, Height;
Xint curx, cury;
Xlong CountDown;
Xint Pass = 0;
Xint Interlace;
X
X/*
X * Bump the 'curx' and 'cury' to point to the next pixel
X */
XBumpPixel()
X{
X /*
X * Bump the current X position
X */
X curx++;
X
X /*
X * If we are at the end of a scan line, set curx back to the beginning
X * If we are interlaced, bump the cury to the appropriate spot,
X * otherwise, just increment it.
X */
X if( curx == Width ) {
X curx = 0;
X
X if( !Interlace )
X cury++;
X else {
X switch( Pass ) {
X
X case 0:
X cury += 8;
X if( cury >= Height ) {
X Pass++;
X cury = 4;
X }
X break;
X
X case 1:
X cury += 8;
X if( cury >= Height ) {
X Pass++;
X cury = 2;
X }
X break;
X
X case 2:
X cury += 4;
X if( cury >= Height ) {
X Pass++;
X cury = 1;
X }
X break;
X
X case 3:
X cury += 2;
X break;
X }
X }
X }
X}
X
X/*
X * Return the next pixel from the image
X */
XGIFNextPixel( getpixel )
Xifunptr getpixel;
X{
X int r;
X
X if( CountDown == 0 )
X return EOF;
X
X CountDown--;
X
X r = ( * getpixel )( curx, cury );
X
X BumpPixel();
X
X return r;
X}
X
X/* public */
X
XGIFEncode( fp, GWidth, GHeight, GInterlace, Background,
X BitsPerPixel, Red, Green, Blue, GetPixel )
X
XFILE *fp;
Xint GWidth, GHeight;
Xint GInterlace;
Xint Background;
Xint BitsPerPixel;
Xint Red[], Green[], Blue[];
Xifunptr GetPixel;
X
X{
X int B;
X int RWidth, RHeight;
X int LeftOfs, TopOfs;
X int Resolution;
X int ColorMapSize;
X int InitCodeSize;
X int i;
X
X Interlace = GInterlace;
X
X ColorMapSize = 1 << BitsPerPixel;
X
X RWidth = Width = GWidth;
X RHeight = Height = GHeight;
X LeftOfs = TopOfs = 0;
X
X Resolution = BitsPerPixel;
X
X /*
X * Calculate number of bits we are expecting
X */
X CountDown = (long)Width * (long)Height;
X
X /*
X * Indicate which pass we are on (if interlace)
X */
X Pass = 0;
X
X /*
X * The initial code size
X */
X if( BitsPerPixel <= 1 )
X InitCodeSize = 2;
X else
X InitCodeSize = BitsPerPixel;
X
X /*
X * Set up the current x and y position
X */
X curx = cury = 0;
X
X /*
X * Write the Magic header
X */
X fwrite( "GIF87a", 1, 6, fp );
X
X /*
X * Write out the screen width and height
X */
X Putword( RWidth, fp );
X Putword( RHeight, fp );
X
X /*
X * Indicate that there is a global colour map
X */
X B = 0x80; /* Yes, there is a color map */
X
X /*
X * OR in the resolution
X */
X B |= (Resolution - 1) << 5;
X
X /*
X * OR in the Bits per Pixel
X */
X B |= (BitsPerPixel - 1);
X
X /*
X * Write it out
X */
X fputc( B, fp );
X
X /*
X * Write out the Background colour
X */
X fputc( Background, fp );
X
X /*
X * Byte of 0's (future expansion)
X */
X fputc( 0, fp );
X
X /*
X * Write out the Global Colour Map
X */
X for( i=0; i<ColorMapSize; i++ ) {
X fputc( Red[i], fp );
X fputc( Green[i], fp );
X fputc( Blue[i], fp );
X }
X
X /*
X * Write an Image separator
X */
X fputc( ',', fp );
X
X /*
X * Write the Image header
X */
X
X Putword( LeftOfs, fp );
X Putword( TopOfs, fp );
X Putword( Width, fp );
X Putword( Height, fp );
X
X /*
X * Write out whether or not the image is interlaced
X */
X if( Interlace )
X fputc( 0x40, fp );
X else
X fputc( 0x00, fp );
X
X /*
X * Write out the initial code size
X */
X fputc( InitCodeSize, fp );
X
X /*
X * Go and actually compress the data
X */
X compress( InitCodeSize+1, fp, GetPixel );
X
X /*
X * Write out a Zero-length packet (to end the series)
X */
X fputc( 0, fp );
X
X /*
X * Write the GIF file terminator
X */
X fputc( ';', fp );
X
X /*
X * And close the file
X */
X fclose( fp );
X
X}
X
X/*
X * Write out a word to the GIF file
X */
XPutword( w, fp )
Xint w;
XFILE *fp;
X{
X fputc( w & 0xff, fp );
X fputc( (w / 256) & 0xff, fp );
X}
X
X
X/***************************************************************************
X *
X * GIFCOMPR.C - GIF Image compression routines
X *
X * Lempel-Ziv compression based on 'compress'. GIF modifications by
X * David Rowley (mgardi at watdcsu.waterloo.edu)
X *
X ***************************************************************************/
X
X/*
X * General DEFINEs
X */
X
X#define BITS 12
X
X#define HSIZE 5003 /* 80% occupancy */
X
X/*
X * a code_int must be able to hold 2**BITS values of type int, and also -1
X */
Xtypedef int code_int;
X
X#ifdef SIGNED_COMPARE_SLOW
Xtypedef unsigned long int count_int;
Xtypedef unsigned short int count_short;
X#else
Xtypedef long int count_int;
X#endif
X
X#ifdef NO_UCHAR
X typedef char char_type;
X#else
X typedef unsigned char char_type;
X#endif /* UCHAR */
X
X/*
X *
X * GIF Image compression - modified 'compress'
X *
X * Based on: compress.c - File compression ala IEEE Computer, June 1984.
X *
X * By Authors: Spencer W. Thomas (decvax!harpo!utah-cs!utah-gr!thomas)
X * Jim McKie (decvax!mcvax!jim)
X * Steve Davies (decvax!vax135!petsd!peora!srd)
X * Ken Turkowski (decvax!decwrl!turtlevax!ken)
X * James A. Woods (decvax!ihnp4!ames!jaw)
X * Joe Orost (decvax!vax135!petsd!joe)
X *
X */
X#include <ctype.h>
X/* #include <signal.h> */
X
X#define ARGVAL() (*++(*argv) || (--argc && *++argv))
X
Xint n_bits; /* number of bits/code */
Xint maxbits = BITS; /* user settable max # bits/code */
Xcode_int maxcode; /* maximum code, given n_bits */
Xcode_int maxmaxcode = (code_int)1 << BITS; /* should NEVER generate this
Xcode */
X#ifdef COMPATIBLE /* But wrong! */
X# define MAXCODE(n_bits) ((code_int) 1 << (n_bits) - 1)
X#else
X# define MAXCODE(n_bits) (((code_int) 1 << (n_bits)) - 1)
X#endif /* COMPATIBLE */
X
Xcount_int htab [HSIZE];
Xunsigned short codetab [HSIZE];
X#define HashTabOf(i) htab[i]
X#define CodeTabOf(i) codetab[i]
X
Xcode_int hsize = HSIZE; /* for dynamic table sizing */
Xcount_int fsize;
X
X/*
X * To save much memory, we overlay the table used by compress() with those
X * used by decompress(). The tab_prefix table is the same size and type
X * as the codetab. The tab_suffix table needs 2**BITS characters. We
X * get this from the beginning of htab. The output stack uses the rest
X * of htab, and contains characters. There is plenty of room for any
X * possible stack (stack used to be 8000 characters).
X */
X
X#define tab_prefixof(i) CodeTabOf(i)
X#define tab_suffixof(i) ((char_type *)(htab))[i]
X#define de_stack ((char_type *)&tab_suffixof((code_int)1<<BITS))
X
Xcode_int free_ent = 0; /* first unused entry */
Xint exit_stat = 0;
X
X/*
X * block compression parameters -- after all codes are used up,
X * and compression rate changes, start over.
X */
Xint clear_flg = 0;
X
Xint offset;
Xlong int in_count = 1; /* length of input */
Xlong int out_count = 0; /* # of codes output (for debugging) */
X
X/*
X * compress stdin to stdout
X *
X * Algorithm: use open addressing double hashing (no chaining) on the
X * prefix code / next character combination. We do a variant of Knuth's
X * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
X * secondary probe. Here, the modular division first probe is gives way
X * to a faster exclusive-or manipulation. Also do block compression with
X * an adaptive reset, whereby the code table is cleared when the compression
X * ratio decreases, but after the table fills. The variable-length output
X * codes are re-sized at this point, and a special CLEAR code is generated
X * for the decompressor. Late addition: construct the table according to
X * file size for noticeable speed improvement on small files. Please direct
X * questions about this implementation to ames!jaw.
X */
X
Xint g_init_bits;
XFILE *g_outfile;
X
Xint ClearCode;
Xint EOFCode;
X
Xcompress( init_bits, outfile, ReadValue )
Xint init_bits;
XFILE *outfile;
Xifunptr ReadValue;
X{
X register long fcode;
X register code_int i = 0;
X register int c;
X register code_int ent;
X register code_int disp;
X register code_int hsize_reg;
X register int hshift;
X
X /*
X * Set up the globals: g_init_bits - initial number of bits
X * g_outfile - pointer to output file
X */
X g_init_bits = init_bits;
X g_outfile = outfile;
X
X /*
X * Set up the necessary values
X */
X offset = 0;
X out_count = 0;
X clear_flg = 0;
X in_count = 1;
X maxcode = MAXCODE(n_bits = g_init_bits);
X
X ClearCode = (1 << (init_bits - 1));
X EOFCode = ClearCode + 1;
X free_ent = ClearCode + 2;
X
X char_init();
X
X ent = GIFNextPixel( ReadValue );
X
X hshift = 0;
X for ( fcode = (long) hsize; fcode < 65536L; fcode *= 2L )
X hshift++;
X hshift = 8 - hshift; /* set hash code range bound */
X
X hsize_reg = hsize;
X cl_hash( (count_int) hsize_reg); /* clear hash table */
X
X output( (code_int)ClearCode );
X
X#ifdef SIGNED_COMPARE_SLOW
X while ( (c = GIFNextPixel( ReadValue )) != (unsigned) EOF ) {
X#else
X while ( (c = GIFNextPixel( ReadValue )) != EOF ) {
X#endif
X
X in_count++;
X
X fcode = (long) (((long) c << maxbits) + ent);
X /* i = (((code_int)c << hshift) ~ ent); /* xor hashing */
X i = (((code_int)c << hshift) ^ ent); /* xor hashing */
X
X if ( HashTabOf (i) == fcode ) {
X ent = CodeTabOf (i);
X continue;
X } else if ( (long)HashTabOf (i) < 0 ) /* empty slot */
X goto nomatch;
X disp = hsize_reg - i; /* secondary hash (after G. Knott) */
X if ( i == 0 )
X disp = 1;
Xprobe:
X if ( (i -= disp) < 0 )
X i += hsize_reg;
X
X if ( HashTabOf (i) == fcode ) {
X ent = CodeTabOf (i);
X continue;
X }
X if ( (long)HashTabOf (i) > 0 )
X goto probe;
Xnomatch:
X output ( (code_int) ent );
X out_count++;
X ent = c;
X#ifdef SIGNED_COMPARE_SLOW
X if ( (unsigned) free_ent < (unsigned) maxmaxcode) {
X#else
X if ( free_ent < maxmaxcode ) {
X#endif
X CodeTabOf (i) = free_ent++; /* code -> hashtable */
X HashTabOf (i) = fcode;
X } else
X cl_block();
X }
X /*
X * Put out the final code.
X */
X output( (code_int)ent );
X out_count++;
X output( (code_int) EOFCode );
X
X return;
X}
X
X/*****************************************************************
X * TAG( output )
X *
X * Output the given code.
X * Inputs:
X * code: A n_bits-bit integer. If == -1, then EOF. This assumes
X * that n_bits =< (long)wordsize - 1.
X * Outputs:
X * Outputs code to the file.
X * Assumptions:
X * Chars are 8 bits long.
X * Algorithm:
X * Maintain a BITS character long buffer (so that 8 codes will
X * fit in it exactly). Use the VAX insv instruction to insert each
X * code in turn. When the buffer fills up empty it and start over.
X */
X
Xunsigned long cur_accum = 0;
Xint cur_bits = 0;
X
Xunsigned long masks[] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F,
X 0x001F, 0x003F, 0x007F, 0x00FF,
X 0x01FF, 0x03FF, 0x07FF, 0x0FFF,
X 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF };
X
Xoutput( code )
Xcode_int code;
X{
X cur_accum &= masks[ cur_bits ];
X
X if( cur_bits > 0 )
X cur_accum |= ((long)code << cur_bits);
X else
X cur_accum = code;
X
X cur_bits += n_bits;
X
X while( cur_bits >= 8 ) {
X char_out( (unsigned int)(cur_accum & 0xff) );
X cur_accum >>= 8;
X cur_bits -= 8;
X }
X
X /*
X * If the next entry is going to be too big for the code size,
X * then increase it, if possible.
X */
X if ( free_ent > maxcode || clear_flg ) {
X
X if( clear_flg ) {
X
X maxcode = MAXCODE (n_bits = g_init_bits);
X clear_flg = 0;
X
X } else {
X
X n_bits++;
X if ( n_bits == maxbits )
X maxcode = maxmaxcode;
X else
X maxcode = MAXCODE(n_bits);
X }
X }
X
X if( code == EOFCode ) {
X /*
X * At EOF, write the rest of the buffer.
X */
X while( cur_bits > 0 ) {
X char_out( (unsigned int)(cur_accum & 0xff) );
X cur_accum >>= 8;
X cur_bits -= 8;
X }
X
X flush_char();
X
X fflush( g_outfile );
X
X if( ferror( g_outfile ) )
X writeerr();
X }
X}
X
X/*
X * Clear out the hash table
X */
Xcl_block () /* table clear for block compress */
X{
X
X cl_hash ( (count_int) hsize );
X free_ent = ClearCode + 2;
X clear_flg = 1;
X
X output( (code_int)ClearCode );
X}
X
Xcl_hash(hsize) /* reset code table */
Xregister count_int hsize;
X{
X
X register count_int *htab_p = htab+hsize;
X
X register long i;
X register long m1 = -1;
X
X i = hsize - 16;
X do { /* might use Sys V memset(3) here */
X *(htab_p-16) = m1;
X *(htab_p-15) = m1;
X *(htab_p-14) = m1;
X *(htab_p-13) = m1;
X *(htab_p-12) = m1;
X *(htab_p-11) = m1;
X *(htab_p-10) = m1;
X *(htab_p-9) = m1;
X *(htab_p-8) = m1;
X *(htab_p-7) = m1;
X *(htab_p-6) = m1;
X *(htab_p-5) = m1;
X *(htab_p-4) = m1;
X *(htab_p-3) = m1;
X *(htab_p-2) = m1;
X *(htab_p-1) = m1;
X htab_p -= 16;
X } while ((i -= 16) >= 0);
X
X for ( i += 16; i > 0; i-- )
X *--htab_p = m1;
X}
X
Xwriteerr()
X{
X printf( "error writing output file\n" );
X exit(1);
X}
X
X/******************************************************************************
X *
X * GIF Specific routines
X *
X ******************************************************************************/
X
X/*
X * Number of characters so far in this 'packet'
X */
Xint a_count;
X
X/*
X * Set up the 'byte output' routine
X */
Xchar_init()
X{
X a_count = 0;
X}
X
X/*
X * Define the storage for the packet accumulator
X */
Xchar accum[ 256 ];
X
X/*
X * Add a character to the end of the current packet, and if it is 254
X * characters, flush the packet to disk.
X */
Xchar_out( c )
Xint c;
X{
X accum[ a_count++ ] = c;
X if( a_count >= 254 )
X flush_char();
X}
X
X/*
X * Flush the packet to disk, and reset the accumulator
X */
Xflush_char()
X{
X if( a_count > 0 ) {
X fputc( a_count, g_outfile );
X fwrite( accum, 1, a_count, g_outfile );
X a_count = 0;
X }
X}
X
X/* The End */
SHAR_EOF
if test 19592 -ne "`wc -c < 'ppm/ppmtogif.c'`"
then
echo shar: error transmitting "'ppm/ppmtogif.c'" '(should have been 19592 characters)'
fi
fi # end of overwriting check
if test ! -d 'ppm'
then
echo shar: creating directory "'ppm'"
mkdir 'ppm'
fi
echo shar: extracting "'ppm/ppmtogif.1'" '(774 characters)'
if test -f 'ppm/ppmtogif.1'
then
echo shar: will not over-write existing file "'ppm/ppmtogif.1'"
else
sed 's/^X//' << \SHAR_EOF > 'ppm/ppmtogif.1'
X.TH ppmtogif 1 "01 September 1989"
X.SH NAME
Xppmtogif - convert a portable pixmap into a GIF file
X.SH SYNOPSIS
Xppmtogif [<ppmfile>]
X.SH DESCRIPTION
XReads a portable pixmap as input.
XProduces a GIF file as output.
X.SH "SEE ALSO"
Xgiftoppm(1), ppm(5)
X.SH AUTHOR
XBased on GIFENCOD by David Rowley <mgardi at watdcsu.waterloo.edu>.
XLempel-Zim compression based on "compress".
X
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 774 -ne "`wc -c < 'ppm/ppmtogif.1'`"
then
echo shar: error transmitting "'ppm/ppmtogif.1'" '(should have been 774 characters)'
fi
fi # end of overwriting check
if test ! -d 'ppm'
then
echo shar: creating directory "'ppm'"
mkdir 'ppm'
fi
echo shar: extracting "'ppm/ppmtoilbm.c'" '(7039 characters)'
if test -f 'ppm/ppmtoilbm.c'
then
echo shar: will not over-write existing file "'ppm/ppmtoilbm.c'"
else
sed 's/^X//' << \SHAR_EOF > 'ppm/ppmtoilbm.c'
X/* ppmtoilbm.c - read a portable pixmap and produce an Amiga IFF ILBM 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 "ppm.h"
X#include "ppmcmap.h"
X#include "ilbm.h"
X
X#define MAXCOLORS 32
X
X#define odd(n) ((n) & 1)
X#define abs(x) ((x) >= 0 ? (x) : -(x))
X
Xmain( argc, argv )
Xint argc;
Xchar *argv[];
X {
X FILE *ifd;
X int argn, rows, cols, colors, i, ham, nPlanes, formsize, cmapsize;
X pixel **pixels, *pP;
X int row, col, plane;
X pixval maxval;
X colorhash_table cht;
X colorhist_vector chv;
X unsigned char *raw_rowbuf, *coded_rowbuf;
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( "[ppmfile]" );
X
X pixels = ppm_readppm( ifd, &cols, &rows, &maxval );
X
X pm_close( ifd );
X
X /* Figure out the colormap. */
X fprintf( stderr, "(Computing colormap..." );
X fflush( stderr );
X chv = ppm_computecolorhist( pixels, cols, rows, MAXCOLORS, &colors );
X if ( chv == (colorhist_vector) 0 )
X {
X fprintf(
X stderr, " Too many colors - proceeding to write a HAM file.\n" );
X fprintf(
X stderr,
X "If you want a non-HAM file, try running the pixmap through 'ppmquant 32'.)\n" );
X ham = 1;
X colors = 16;
X nPlanes = 6;
X }
X else
X {
X fprintf( stderr, " Done. %d colors found.)\n", colors );
X ham = 0;
X nPlanes = colorstobpp( colors );
X /* Make a hash table for fast color lookup. */
X cht = ppm_colorhisttocolorhash( chv, colors );
X }
X
X /* Start off the ILBM with a FORM ILBM. */
X cmapsize = colors * 3;
X if ( odd( colors ) )
X cmapsize++; /* pad CMAP to word */
X formsize =
X 4 + /* ILBM */
X 4 + 4 + 20 + /* BMHD size header*/
X 4 + 4 + cmapsize + /* CMAP size colors */
X 4 + 4 + 4 + /* CAMG size val */
X 4 + 4 + rows * nPlanes * RowBytes(cols); /* BODY size data */
X put_chunk_head( "FORM", formsize );
X put_fourchars( "ILBM" );
X
X /* Write out the BMHD. */
X put_chunk_head( "BMHD", 20 );
X put_big_short( cols );
X put_big_short( rows );
X put_big_short( 0 ); /* x */
X put_big_short( 0 ); /* y */
X put_byte( nPlanes );
X put_byte( mskNone );
X put_byte( cmpNone );
X put_byte( 0 ); /* pad1 */
X put_big_short( 0 ); /* transparentColor */
X put_byte( 10 ); /* xAsp */
X put_byte( 10 ); /* yAsp */
X put_big_short( cols ); /* pageWidth */
X put_big_short( rows ); /* pageHeight */
X
X /* Write out the CMAP. */
X if ( maxval > 255 )
X fprintf(
X stderr, "(Maxval is not 255 -- automatically rescaling colors.)\n");
X put_chunk_head( "CMAP", cmapsize );
X for ( i = 0; i < colors; i++ )
X {
X if ( ham )
X { /* Grayscale colormap for HAM. */
X put_byte( i << 4 );
X put_byte( i << 4 );
X put_byte( i << 4 );
X }
X else if ( maxval == 255 )
X {
X put_byte( PPM_GETR( chv[i].color ) );
X put_byte( PPM_GETG( chv[i].color ) );
X put_byte( PPM_GETB( chv[i].color ) );
X }
X else
X {
X put_byte( (char) ( (int) PPM_GETR(chv[i].color) * 255 / maxval ) );
X put_byte( (char) ( (int) PPM_GETG(chv[i].color) * 255 / maxval ) );
X put_byte( (char) ( (int) PPM_GETB(chv[i].color) * 255 / maxval ) );
X }
X }
X if ( odd( colors ) )
X put_byte( 0 ); /* Pad to word. */
X
X /* Write out the CAMG. */
X put_chunk_head( "CAMG", 4 );
X if ( ham )
X put_big_long( vmHAM );
X else
X put_big_long( 0 );
X
X /* And finally, encode and write out the BODY. */
X raw_rowbuf = (unsigned char *) malloc( cols );
X coded_rowbuf = (unsigned char *) malloc( RowBytes(cols) );
X if ( raw_rowbuf == 0 || coded_rowbuf == 0 )
X pm_error( "out of memory", 0,0,0,0,0 );
X put_chunk_head( "BODY", rows * nPlanes * RowBytes(cols) );
X for ( row = 0; row < rows; row++ )
X {
X /* Go from pixels to raw bytes. */
X if ( ham )
X { /* HAM mode. */
X register int noprev, pr, pg, pb, r, g, b, l;
X
X noprev = 1;
X for ( col = 0, pP = pixels[row]; col < cols; col++, pP++ )
X {
X r = PPM_GETR( *pP );
X g = PPM_GETG( *pP );
X b = PPM_GETB( *pP );
X l = PPM_LUMIN( *pP );
X if ( maxval != 15 )
X {
X r = r * 15 / maxval;
X g = g * 15 / maxval;
X b = b * 15 / maxval;
X l = l * 15 / maxval;
X }
X if ( noprev )
X { /* No previous pixels, gotta use the gray option. */
X raw_rowbuf[col] = l;
X pr = pg = pb = l;
X noprev = 0;
X }
X else
X {
X register int dred, dgreen, dblue, dgray;
X
X /* Compute distances for the four options. */
X dred = abs( g - pg ) + abs( b - pb );
X dgreen = abs( r - pr ) + abs( b - pb );
X dblue = abs( r - pr ) + abs( g - pg );
X dgray = abs( r - l ) + abs( g - l ) + abs( b - l );
X
X if ( dgray < dred && dgray < dgreen && dgray < dblue )
X {
X raw_rowbuf[col] = l;
X pr = pg = pb = l;
X }
X else if ( dblue < dred && dblue < dgreen )
X {
X raw_rowbuf[col] = ( 1 << 4 ) + b;
X pb = b;
X }
X else if ( dred < dgreen )
X {
X raw_rowbuf[col] = ( 2 << 4 ) + r;
X pr = r;
X }
X else
X {
X raw_rowbuf[col] = ( 3 << 4 ) + g;
X pg = g;
X }
X }
X }
X }
X else
X /* Non-HAM. */
X for ( col = 0, pP = pixels[row]; col < cols; col++, pP++ )
X raw_rowbuf[col] = ppm_lookupcolor( cht, *pP );
X
X /* Encode and write raw bytes in plane-interleaved form. */
X for ( plane = 0; plane < nPlanes; plane++ )
X {
X int mask;
X unsigned char *cp;
X
X mask = 1 << plane;
X cp = coded_rowbuf;
X *cp = 0;
X for ( col = 0; col < cols; col++ )
X {
X int b;
X
X b = ( raw_rowbuf[col] & mask ) ? 1 : 0;
X *cp |= b << ( 7 - col % 8 );
X if ( col % 8 == 7 )
X {
X cp++;
X *cp = 0;
X }
X }
X fwrite( coded_rowbuf, RowBytes(cols), 1, stdout );
X }
X }
X
X exit( 0 );
X }
X
Xint
Xcolorstobpp( colors )
Xint colors;
X {
X int bpp;
X
X if ( colors <= 2 )
X bpp = 1;
X else if ( colors <= 4 )
X bpp = 2;
X else if ( colors <= 8 )
X bpp = 3;
X else if ( colors <= 16 )
X bpp = 4;
X else if ( colors <= 32 )
X bpp = 5;
X else if ( colors <= 64 )
X bpp = 6;
X else if ( colors <= 128 )
X bpp = 7;
X else if ( colors <= 256 )
X bpp = 8;
X else
X pm_error( "can't happen", 0,0,0,0,0 );
X
X return bpp;
X }
X
Xput_chunk_head( str, size )
Xchar *str;
Xlong size;
X {
X put_fourchars( str );
X put_big_long( size );
X }
X
Xput_fourchars( str )
Xchar *str;
X {
X fputs( str, stdout );
X }
X
Xput_big_short( s )
Xshort s;
X {
X put_byte( s >> 8 );
X put_byte( s & 0xff );
X }
X
Xput_big_long( l )
Xlong l;
X {
X put_byte( l >> 24 );
X put_byte( ( l >> 16 ) & 0xff );
X put_byte( ( l >> 8 ) & 0xff );
X put_byte( l & 0xff );
X }
X
Xput_byte( b )
Xunsigned char b;
X {
X putchar( b );
X }
SHAR_EOF
if test 7039 -ne "`wc -c < 'ppm/ppmtoilbm.c'`"
then
echo shar: error transmitting "'ppm/ppmtoilbm.c'" '(should have been 7039 characters)'
fi
fi # end of overwriting check
if test ! -d 'ppm'
then
echo shar: creating directory "'ppm'"
mkdir 'ppm'
fi
echo shar: extracting "'ppm/ppmtoilbm.1'" '(781 characters)'
if test -f 'ppm/ppmtoilbm.1'
then
echo shar: will not over-write existing file "'ppm/ppmtoilbm.1'"
else
sed 's/^X//' << \SHAR_EOF > 'ppm/ppmtoilbm.1'
X.TH ppmtoilbm 1 "07 September 1989"
X.SH NAME
Xppmtoilbm - convert a portable pixmap into an Amiga IFF ILBM file
X.SH SYNOPSIS
Xppmtoilbm [<ppmfile>]
X.SH DESCRIPTION
XReads a portable pixmap as input.
XProduces an Amiga IFF ILBM file as output.
X.PP
XIf the pixmap won't fit into the Amiga's maximum of 5 planes, a HAM
Xfile is written.
X.SH "SEE ALSO"
Xilbmtoppm(1), ppm(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 781 -ne "`wc -c < 'ppm/ppmtoilbm.1'`"
then
echo shar: error transmitting "'ppm/ppmtoilbm.1'" '(should have been 781 characters)'
fi
fi # end of overwriting check
# End of shell archive
exit 0
More information about the Alt.sources
mailing list