[comp.sources.misc] v02i079: sun2ps - sun rasterfile to PostScript image translator

boysko@l.UUCP (Glenn Boysko) (03/28/88)

Submitted-By: "Glenn Boysko" <boysko@l.UUCP>

Archive-Name: sun2ps


comp.sources.misc: Volume 2, Issue 79
Submitted-By: "Glenn Boysko" <boysko@l.UUCP>
Archive-Name: sun2ps

	Enclosed is "sun2ps" - a Sun Rasterfile to PostScript image translator
that uses run length encoding.

Glenn Boysko
mandrill!boysko
boysko@mandrill.ces.cwru.edu

---------------------------------- cut here -----------------------------------
#!/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:
#	Makefile
#	sun2ps.c
#	sun2ps.l
# This archive created: Fri Mar 25 16:20:42 1988
# By:	Glenn J. Boysko(Case Western Reserve University)
#
export PATH; PATH=/bin:$PATH
echo shar: extracting "'Makefile'" '(515 characters)'
if test -f 'Makefile'
then
	echo shar: over-writing existing file "'Makefile'"
fi
sed 's/^X//' << \SHAR_EOF > 'Makefile'
X#
X# Makefile for Sun2ps and other utilities...
X#
X#	Glenn Boysko	{decvax, sun}!mandrill!boysko
X#			boysko@mandrill.cwru.edu
X
X# Diagnostics about the amount of compression, avg run length, etc
X# are not reported, by default. To view these diagnostics on stderr,
X# define the flag DIAGS. Extra diagnostics about the specifics of
X# raster file (num of samples, image depth, etc) can be found by 
X# defining EXTRADIAGS.
XDIAGFLAGS = -DDIAGS -DEXTRADIAGS
X
XCFLAGS = -O $(DIAGFLAGS)
X
Xsun2ps: sun2ps.o
X	cc -o sun2ps sun2ps.o
SHAR_EOF
if test 515 -ne "`wc -c 'Makefile'`"
then
	echo shar: error transmitting "'Makefile'" '(should have been 515 characters)'
fi
echo shar: extracting "'sun2ps.c'" '(12873 characters)'
if test -f 'sun2ps.c'
then
	echo shar: over-writing existing file "'sun2ps.c'"
fi
sed 's/^X//' << \SHAR_EOF > 'sun2ps.c'
X/******************************************************************************
X*									      *
X*	File:         sun2ps.c						      *
X*	Author:       Glenn Boysko					      *
X*	Organization: Case Western Reserve University			      *
X*	EMail:	      {decvax, sun}!mandrill!boysko			      *
X*		      boysko@mandrill.cwru.edu				      *
X*	Created:      Wed Mar 23 9:25pm					      *
X*	Contents:     Sun Rasterfile to PostScript image (using a run-length  *
X*			encoding scheme.)				      *
X*									      *
X*	(Adapted from "postimage" filter by J. R. Bammi.)		      *
X*									      *
X*	@(#)sun2ps.c	1.7
X******************************************************************************/
X
X/*
X * Usage:
X *  sun2ps [-s sizex sizey] [-t transx transy] [-r rot] [-l] [-i] [-a] file ...
X *
X *	-s sizex sizey   = size of postscript image - default 7.5 x 10 inches.
X *	-t transx transy = translate image - default 0.5 0.5 inches
X *	-r rotate	 = rotate image     - default 0 degress
X *      -l		 = landscape (overrides *all* settings.) 
X *	-i		 = inverse image - default no inverse 
X *				(Inverse enabled implies white on black.)
X *	-a		 = maintain correct aspect ratio - default none.
X *
X */
X
X/* Sun standard raster file format (as obtained by screendump(1)).
X *
X * Header	(8 16-bit quantities)
X * Color Map
X * Image
X *
X */
X
X/* Header Format:
X * 
X * ras_magic		(int)	Raster Magic number 0x59a66a95
X * ras_width		(int)	Width of image in pixels.
X * ras_height		(int)	Height of image in pixels.
X * ras_depth		(int)	Bits per pixel.	Either 1 or 8 bits.
X * ras_length		(int)	Length of image in bytes.
X * ras_type		(int)	Type of file. Assumed to be RT_STANDARD (1) if
X *				produced by a screendump command.
X * ras_maptype		(int)	Type of color map. 
X * ras_maplength	(int)	Length of color map in bytes.
X *
X */
X
X/* Ras_maplength bytes of Color map data. */
X
X/* Ras_length bytes of Image data. */
X
X#include <stdio.h>
X#include <rasterfile.h>
X
X/* Buffer and Input Modes... */
X#define LITERAL	0
X#define COPY	1
X#define IGNORE	2
X
X/* Transmission Variables. */
Xint BufCount;
X
Xunsigned char Buffer[128],
X     	      CurrByte,
X     	      NextByte,
X     	      *BufferP = Buffer;
X
X/* Diagnostic Variables. */
Xint	DiagNLongRuns = 0,
X     	DiagMaxRunLength = 0,
X     	DiagNumRuns = 0;
Xdouble	DiagSumRunLength = 0;
X
Xmain(argc,argv)
Xint argc;
Xchar **argv;
X{
X     FILE      *fp, *fopen();
X     int 	land, inv, aspect;
X     char      *filename;
X     double 	sizex, sizey, transx, transy, rotate;
X
X     extern double atof();
X     
X     fp = stdin;
X     aspect = 0;
X     land = 0;
X     filename = "STDIN";
X     sizex = 7.5;
X     sizey = 10.0;
X     transx = transy = 0.5;
X     rotate = 0.0;
X     
X     while(--argc > 0)
X     {
X	  ++argv;
X	  if((*argv)[0] == '-')
X	  {
X	       switch((*argv)[1])
X	       {
X		 case 'l':
X		 case 'L':
X		    land = 1;
X		    break;
X		    
X		 case 's':
X		 case 'S':
X		    sizex = atof(*++argv);
X		    sizey = atof(*++argv);
X		    argc -= 2;
X		    break;
X		    
X		 case 't':
X		 case 'T':
X		    transx = atof(*++argv);
X		    transy = atof(*++argv);
X		    argc -= 2;
X		    break;
X		    
X		 case 'r':
X		 case 'R':
X		    rotate = atof(*++argv);
X		    argc--;
X		    break;
X		    
X		 case 'I':
X		 case 'i':
X		    inv = 1;
X		    break;
X		    
X		 case 'A':
X		 case 'a':
X		    aspect = 1;
X		    break;
X		    
X		 default:
X		    fprintf(stderr,"Illegal switch %c - ignored\n",
X			    (*argv)[1]);
X	       }
X	  }
X	  else
X	  {
X	       if((fp = fopen(*argv, "r")) == (FILE *)NULL)
X	       {
X		    fprintf(stderr,"Cannot open %s\n",*argv);
X		    exit(1);
X	       }
X	       filename = *argv;
X	  }
X     }
X     if (land)
X     {
X	  transx = 8.0;
X	  transy = 0.5;
X	  sizex  = 10.0;
X	  sizey  = 7.5;
X	  rotate = 90.0;
X     }
X     process(fp, aspect, inv, filename, sizex, sizey, transx, transy, rotate);
X}
X
Xprocess(Fp, aspect, inv, filename, sizex, sizey, transx, transy, rotate)
XFILE *Fp;
Xint inv, aspect;
Xdouble sizex, sizey, transx, transy, rotate;
Xchar *filename;
X{
X     struct rasterfile rh;
X     int i, BS;
X     
X     if (fread((char *) (&rh), sizeof(rh), 1, Fp) != 1)
X     {
X	  Error("Can't read rasterfile header\n");
X     }
X
X#ifdef EXTRADIAGS
X     fprintf(stderr, "Ras_width = %d, Ras_height = %d, Ras_depth = %d\n", 
X	     rh.ras_width, rh.ras_height, rh.ras_depth);
X     fprintf(stderr, "Ras_length = %d, Ras_type = %d, Ras_maplength = %d\n",
X	     rh.ras_length, rh.ras_type, rh.ras_maplength);
X#endif
X     
X     if (rh.ras_magic != RAS_MAGIC)
X     {	
X	  Error("Input file is not a Sun Rasterfile!\n");
X     }
X     
X     if (rh.ras_type != RT_STANDARD)
X     {
X	  Error("Input file is not in Sun Standard Rasterfile format.\n");
X     }
X     
X     /* Scan off color table */
X     for (i=0; i < rh.ras_maplength; i++)
X     {
X	  gb(Fp);
X     }
X     
X     if (aspect)
X     {
X	  if ((sizex / rh.ras_width) < (sizey / rh.ras_height))
X	  {
X	       sizey = sizex * (rh.ras_height * 1.0 / rh.ras_width);
X	  }
X	  else
X	  {
X	       sizex = sizey * (rh.ras_width * 1.0 / rh.ras_height);
X	  }
X
X     }
X     	  
X     PrintPostScriptRoutines(rh.ras_height, rh.ras_width, rh.ras_depth,
X			     transx, transy, sizex, sizey, rotate);
X     
X     BS = Encode(Fp, rh.ras_length, inv);
X     
X#ifdef DIAGS
X     fprintf(stderr, "Encoded %d bytes into %d. (Ratio=%d%%)\n",
X	     rh.ras_length, BS, 100 - (100 * BS) / rh.ras_length);
X     Diags();
X#endif     
X     fclose(Fp);
X
X     PrintPostScriptClosing();
X}
X     
X/******************************************************************************
X*	I/O Routines.							      *
X******************************************************************************/
Xint
Xgb(Fp)		/* Get a byte from Fp. */
XFILE *Fp;
X{
X     int byte;
X     
X     if (!feof(Fp))
X	  byte = getc(Fp);
X     else
X	  Error("Premature EOF.\n");
X     if (ferror(Fp))
X	  Error("I/O Error.\n");
X     return(byte);
X}
X
Xint
Xgw(Fp)		/* Get a word (int) from Fp. */
XFILE *Fp;
X{
X     int word;
X     
X     if (!feof(Fp))
X	  word = getw(Fp);
X     else
X	  Error("Premature EOF.\n");
X     if (ferror(Fp))
X	  Error("I/O Error.\n");
X     return(word);
X}
X
XSendHex(Byte)		/* Send a Hex char to Stdout. */
Xunsigned char Byte;
X{
X     static int LineCount = 0;
X
X     printf("%02x",  0xff & Byte);
X     if (++LineCount == 16)
X     {
X	  putchar('\n');
X	  LineCount = 0;
X     }
X}
X     
Xint
XSendBuffer(Inv)		/* Send a buffer to Stdout. Return BytesSent. */
Xint Inv;
X{
X     int i, BytesSent;
X     
X     if (BufferMode() == LITERAL)
X     {
X	  SendHex( (unsigned char) 0xff & BufCount );
X	  for (i = 0; i < BufCount+1; i++)
X	  {
X	       SendHex( (Inv) ? Buffer[i] : ~Buffer[i]);
X	  }
X	  BytesSent = BufCount+2;
X     }
X     else if (BufferMode() == COPY)
X     {
X	  SendHex( (unsigned char) 0xff & (0x100 + BufCount) );
X	  SendHex( (Inv) ? Buffer[0] : ~Buffer[0]);
X	  BytesSent = 2;
X	  DiagRecLRun(mag(BufCount)+1);
X     }
X     return(BytesSent);
X}
X
X/******************************************************************************
X*	Utility Routines.						      *
X******************************************************************************/
Xint
Xmag(Byte)	/* Magitude of a signed char. */
Xint Byte;
X{
X     if (Byte & 0x80)
X     {
X	  /* Signed */
X	  Byte = ~(--Byte);
X     }
X     return( 0xff & Byte );
X}
X	  
X/******************************************************************************
X*	Buffer Management Routines.					      *
X******************************************************************************/
Xint
XInputMode()
X{
X     if (CurrByte == NextByte)
X	  return(COPY);
X     return(LITERAL);
X}
X
Xint
XBufferMode()
X{
X     if (BufCount >= 0 && BufCount <= 127)
X	  return(LITERAL);
X     else if (BufCount >= -127 && BufCount <= -1)
X	  return(COPY);
X     return(IGNORE);
X}
X
XInitLitMode(Fp, NBytes, Inv)
XFILE *Fp;
Xint *NBytes, Inv;
X{
X     BufferP    = Buffer;
X     BufCount   = -1;
X     ContLitMode(Fp, NBytes, Inv);
X}
X
XContLitMode(Fp, NBytes, Inv)
XFILE *Fp;
Xint *NBytes, Inv;
X{
X     if (BufCount == 127)
X     {
X	  SendBuffer(Inv);
X	  BufferP  = Buffer;
X	  BufCount = -1;
X     }
X     *BufferP++ = CurrByte;
X     BufCount++;
X     CurrByte   = NextByte;
X     NextByte   = (unsigned char) gb(Fp);
X     (*NBytes)--;
X}
X     
XInitCopyMode(Fp, NBytes, Inv)
XFILE *Fp;
Xint *NBytes, Inv;
X{
X     BufferP    = Buffer;
X     *BufferP++ = CurrByte;
X     BufCount   = -1;
X     CurrByte   = (unsigned char) gb(Fp);
X     NextByte   = (unsigned char) gb(Fp);
X     *NBytes   -= 2;
X}
X
XContCopyMode(Fp, NBytes, Inv)
XFILE *Fp;
Xint *NBytes, Inv;
X{
X     if (BufCount == -127)
X     {
X	  SendBuffer(Inv);
X	  InitCopyMode(Fp, NBytes, Inv);
X	  DiagNLongRuns++;
X     }
X     BufCount--;
X     CurrByte   = NextByte;
X     NextByte   = gb(Fp);
X     (*NBytes)--;
X}
X
X/******************************************************************************
X*	Encoding Algorithm.						      *
X******************************************************************************/
Xint
XEncode(Fp, NBytes, Inv)
XFILE *Fp;
Xint NBytes, Inv;
X{
X     int BytesSent = 0;
X     
X     /* Initialize Buffer, BufCount, NextByte, CurrByte */
X     CurrByte = (unsigned char) gb(Fp);
X     NextByte = (unsigned char) gb(Fp);
X     if (InputMode() == LITERAL)
X     {
X	  InitLitMode(Fp, &NBytes, Inv);
X     }
X     else
X     {
X	  InitCopyMode(Fp, &NBytes, Inv);
X     }
X     while (NBytes > 2)
X     {
X	  switch(BufferMode())
X	  {
X	    case LITERAL:
X	       if (InputMode() == COPY)
X	       {
X		    BytesSent += SendBuffer(Inv);
X		    InitCopyMode(Fp, &NBytes, Inv);
X	       }
X	       else
X	       {
X		    ContLitMode(Fp, &NBytes, Inv);
X	       }
X	       break;
X	    case COPY:
X	       if (CurrByte == Buffer[0])
X	       {
X		    ContCopyMode(Fp, &NBytes, Inv);
X	       }
X	       else
X	       {
X		    BytesSent += SendBuffer(Inv);
X		    if (InputMode() == COPY)
X		    {
X			 InitCopyMode(Fp, &NBytes, Inv);
X		    }
X		    else
X		    {
X			 InitLitMode(Fp, &NBytes, Inv);
X		    }
X	       }
X	       break;
X	    default:
X	       Error("Bad Buffer Mode... Sorry\n");
X	       break;
X	  }
X     }
X     BytesSent += SendBuffer(Inv);
X     /* Send out rem'g 2 bytes in LITERAL mode. */
X     Buffer[0] = CurrByte;
X     Buffer[1] = NextByte;
X     BufCount = 1;
X     BytesSent += SendBuffer(Inv);
X     return(BytesSent);
X}
X
X/******************************************************************************
X*	Diagnostic Routines.						      *
X******************************************************************************/
XDiagRecLRun(Rlength)
Xint Rlength;
X{
X#ifdef DIAGS
X     if (Rlength > DiagMaxRunLength)
X	  DiagMaxRunLength = Rlength;
X     DiagSumRunLength += Rlength;
X     DiagNumRuns++;
X#endif
X}
X
XDiags()
X{
X#ifdef DIAGS
X     fprintf(stderr, "Longest Run (<= 128) = %d\n", DiagMaxRunLength);
X     fprintf(stderr, "Number of Runs over 128 = %d\n", DiagNLongRuns);
X     fprintf(stderr, "Average Run Length of %d. (%d Runs)\n",
X	     (int) DiagSumRunLength / DiagNumRuns, DiagNumRuns);
X#endif
X}
X
X/******************************************************************************
X*	PostScript Output Routines. 					      *
X******************************************************************************/
XPrintPostScriptRoutines(ras_h, ras_w, ras_d, tx, ty, sx, sy, rot)
Xint ras_h, ras_w, ras_d;
Xdouble tx, ty, sx, sy, rot;
X{
X     printf("%%!\n/inch {72 mul} def\n");
X     printf("/bpp %d def\n", ras_d);
X     printf("/scanlines %d def\n", ras_h);
X     printf("/scansize %d def\n", ras_w);
X     printf("/bitmapx\n{");
X     printf(" %d %d %d [%d 0 0 %d 0 %d] ", ras_w, ras_h, ras_d, ras_w, 
X	    -ras_h, ras_h);
X     printf("{currentfile readrlehexstring pop } image\n} def\n");
X     printf("gsave\n");
X     printf("%f inch %f inch translate\n",tx, ty);
X     printf("%f rotate\n", rot );
X     printf("%f inch %f inch scale\n", sx, sy);
X     printf("/readrlehexstring\t%% rle_file => decoded_string boolean\n");
X     printf("{\n\t/fileptr exch def\n\tfileptr 1 string readhexstring {");
X     printf("\n\t\t0 get dup 128 and 0 eq\n");
X     printf("\t\t{ 1 add /Buffer exch string def\n");
X     printf("\t\t\tfileptr Buffer readhexstring\n\t\t}\n\t\t{");
X     printf(" 256 exch sub /BufCount exch def\n");
X     printf("\t\t\t/Buffer BufCount 1 add string def\n");
X     printf("\t\t\t/RunInt fileptr 1 string readhexstring");
X     printf(" pop 0 get def\n");
X     printf("\t\t\t0 1 BufCount { RunInt Buffer 3 1 roll put } for\n");
X     printf("\t\t\tBuffer true\n\t\t} ifelse\n\t}\n\t{ false } ifelse\n");
X     printf("} def\n");
X     printf("/clipathx\n{\tnewpath\n\t0 0 moveto\n\t%f inch 0", sx);
X     printf(" lineto\n\t%f inch %f inch lineto\n\t0 %f inch lineto\n",
X	    sx, sy, sy);
X     printf("\tclosepath\n} def\nclipathx clip\n");
X     printf("bitmapx\n");
X}
X
XPrintPostScriptClosing()
X{     
X     printf("\ngrestore\n");
X     printf("showpage\n");
X}
X
X/******************************************************************************
X*	Error Routine.							      *
X******************************************************************************/
XError(S1, S2, S3)
Xchar *S1, *S2, *S3;
X{
X     fprintf(stderr, S1, S2, S3);
X     exit(-1);
X}
SHAR_EOF
if test 12873 -ne "`wc -c 'sun2ps.c'`"
then
	echo shar: error transmitting "'sun2ps.c'" '(should have been 12873 characters)'
fi
echo shar: extracting "'sun2ps.l'" '(3986 characters)'
if test -f 'sun2ps.l'
then
	echo shar: over-writing existing file "'sun2ps.l'"
fi
sed 's/^X//' << \SHAR_EOF > 'sun2ps.l'
X.TH SUN2PS L "" "" "User Contributed Software"
X.SH NAME
Xsun2ps \- a Sun rasterfile to PostScript image filter using run length 
Xencoding
X.SH SYNOPSIS
X.B sun2ps
X[
X.B \-s sizex sizey
X] [ 
X.B \-t transx transy
X] [
X.B \-r rot
X] [
X.B \-i
X] [
X.B \-a
X] [
X.B \-l
X] [ rasfile ]
X.SH OPTIONS
X.TP
X.B \-s
XSet the x and y size of the image to
X.I sizex
Xand
X.I sizey
Xinches, respectively. Defaults to 7.5 x 10 inches.
X.TP
X.B \-t
XTranslate the origin of the x-y axis to 
X.I transx
Xand
X.I transy
Xinches, respectively. Defaults to (0.5, 0.5) inches.
X.TP
X.B \-r 
XRotate the image by
X.I rot
Xdegrees. Note: rotating the image
X.I does not
Xtranslate the x-y origin. When using this option, be sure to translate
Xthe origin accordingly. Default is 0 degrees. See the -l option.
X.TP
X.B \-i
XInvert the image. This implies a white image on a black background.
XDefault is a black image on a white background.
X.TP
X.B \-l
XLandscape mode. This option will override any previous size, translation
Xand rotation settings. Its is intended to provide a quick, landscape
Ximage. Default is off (or portrait mode).
X.TP
X.B \-a
XAutomatically resize the image to conform to its aspect ratio. Normally,
X.I sun2ps
Xwill scale the image to the full page size (or 
X.I sizex
Xand
X.I sizey,
Xif given). Default is off.
X.SH DESCRIPTION
X.sp 1
X.TP
X.B Overview
X.br
X.sp 1
X.I Sun2ps
Xtranslates images stored in Sun Rasterfile format (see
X.I rasterfile(5)
Xfor info on file format) to standard PostScript code. Run length
Xencoding/decoding was also incorporated into 
X.I sun2ps
Xto decrease the size of the text file produced (full sized screendumps
Xproduce a file in excess of 300K, without compression). The specifics
Xof the encoding algorithm are described below. Using this compression,
Xfull screen dumps (using
X.I screendump(1))
Xcan be compressed from 20% to 30% of the original. Unfortunately,
Xdue to the nature of the text file, binary image data is doubled
Xsince each byte is stored as two hex digits. 
X.br
X.TP
X.B Run Length Encoding
X.br
X.sp 1
XThe run length encoding strategy used in
X.I sun2ps
Xis a byte-level scheme that allows runs up to 128. A maximum run length
Xof 128 was chosen so as to conform with images produced by the Degas Elite
Xsystem for the Atari ST. Our intent is to allow for the display of Degas
Ximages on NeWS windows. Using this scheme, image data is sent in two types
Xof packets, or buffers. Along with each buffer is a count, which identifies
Xthe size of the packet and its type. Copy packets, or "runs" in their most
Xconventional sense, consist of a single byte with its count specifying
Xthe number of times this byte is to be repeated. Literal packets consist of
Xa buffer of non-repeated bytes with its count specifying the size of the
Xpacket. A buffer count of 
X.I N
Xindicates:
X.br
X.sp 1
X.I N = 0..127 
X: Literal mode. Send out the next
X.I N
X+ 1 bytes as is.
X.br
X.I N = -1..-127
X: Copy mode. Copy the next byte 
X.I -N
X+ 1 times.
X.br
X.I N = -128
X: Ignore.
X.br
X.TP
X.B Input, Output & Stderr
X.sp 1
X.I Sun2ps
Xsends its PostScript output to stdout. An input rasterfile may be specified
Xon the command line, or if excluded, stdin is used. 
X.I Sun2ps
Xcan be compiled with diagnostic information being reported to stderr.
XDiagnostics include compression ratio, average run length, and number of
Xruns over the maximum. See the Makefile for setting the appropriate
Xflags for the diagnostic output.
X.SH EXAMPLES
X.br
X.sp 1
XStandard usage is:
X.br
X.na
X.sp 1
XMyPrompt% screendump | sun2ps -l | lpr   OR
X.br
X.sp 1
XMyPrompt% screendump | sun2ps -l > screen.ps   OR
X.br
X.sp 1
XMyPrompt% sun2ps -a /u/big/jerk/image.ras > image.ps
X.br
X.ad
X.SH AUTHORS
X.na
XGlenn Boysko    (boysko@mandrill.ces.cwru.edu)
X                ({decvax, sun}!mandrill!boysko)
X.ad
X.br
X.sp 1
XWith references to prior work ("postimage") by:
X.na
X.br
X.sp 1
XJ.R. Bammi      (bammi@mandrill.ces.cwru.edu)
X                ({decvax, sun}!mandrill!bammi)
X.ad
X.SH SEE ALSO
Xscreendump(1), rasterfile(5), rasfilter8to1(1).
X.SH BUGS
XNo Bugs! Just features!
X.SH DATE
X3/25/88
SHAR_EOF
if test 3986 -ne "`wc -c 'sun2ps.l'`"
then
	echo shar: error transmitting "'sun2ps.l'" '(should have been 3986 characters)'
fi
#	End of shell archive
exit 0