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