diff options
author | Joseph Hunkeler <jhunkeler@gmail.com> | 2015-07-08 20:46:52 -0400 |
---|---|---|
committer | Joseph Hunkeler <jhunkeler@gmail.com> | 2015-07-08 20:46:52 -0400 |
commit | fa080de7afc95aa1c19a6e6fc0e0708ced2eadc4 (patch) | |
tree | bdda434976bc09c864f2e4fa6f16ba1952b1e555 /unix/gdev/sgidev/sgi2ueps.c | |
download | iraf-linux-fa080de7afc95aa1c19a6e6fc0e0708ced2eadc4.tar.gz |
Initial commit
Diffstat (limited to 'unix/gdev/sgidev/sgi2ueps.c')
-rw-r--r-- | unix/gdev/sgidev/sgi2ueps.c | 530 |
1 files changed, 530 insertions, 0 deletions
diff --git a/unix/gdev/sgidev/sgi2ueps.c b/unix/gdev/sgidev/sgi2ueps.c new file mode 100644 index 00000000..345eb702 --- /dev/null +++ b/unix/gdev/sgidev/sgi2ueps.c @@ -0,0 +1,530 @@ +/* Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + */ + +#include <stdio.h> +#include <ctype.h> +#include <time.h> +#include <pwd.h> +#include <string.h> +#include <stdlib.h> + +#define import_spp +#define import_error +#include <iraf.h> + +#include "sgiUtil.h" + + +/* + * SGI2UEPS.C -- Read IRAF SGI metacode from standard input, translate into + * Encapsulated Postscript and write to standard output. + * + * Usage: + * + * sgi2ueps.e [-params] [sgi_metacode] [| lpr -Plw] + * + * -4 use 4 byte point encoding scheme (default is 7 byte) + * -l N left edge; x plot origin in device pixels + * -b N bottom edge; y plot origin in device pixels + * -w N width of plot, device pixels starting from l + * -h N height of plot, device pixels starting from b + * -p O.S pen width `origin' and `slope' + * + * Numeric values may be appended directly to their flags or separated by a + * space; the input file name and the switches may occur in any order. + * Note that you can arrange for the Postscript output to be saved in a file + * as well as directed to the printer by calling the translator as + * + * sgi2ueps.e [params] | tee -a file | lpr -Plw + */ + +#define OSOK 0 /* normal successful completion */ +#define LEN_MCBUF 1024 /* number of SGK instrs in buffer */ +#define SGK_FRAME 1 /* new frame instruction */ +#define SGK_MOVE 2 /* move pen */ +#define SGK_DRAW 3 /* draw pen */ +#define SGK_SETLW 4 /* set line width */ +#define SGK_MAXNDC 32767 /* SGK units */ + +/* Device opcodes and parameters. The default edge and width parameters (DEF_) + * are given in pixels at 300 dots/inch. Although bypassing the + * device-independence of Postscript, this achieves greater efficiency + * both in translator performance and in transmission rate to the plotter. + * The device y-origin is at the lower left corner of the page, but we take + * care of this with a Postscript coordinate transformation. Thus the maximum + * page `width' is 11*300 pixels, `height' is 8.5*300 pixels. + */ +#define DEV_FRAME "showpage setcoords setjoins\n" /* newframe */ +#define DEV_SETLW "setlinewidth\n" /* linewidth */ + +#define MAX_POINTS 512 /* maximum points on stack before a STROKE */ +#define DEF_LEFT 30 /* origin in device pixels in x */ +#define DEF_WIDTH 3180 /* width in x (300d/i, 11" paper) */ +#define DEF_BOTTOM 60 /* origin in device pixels in y */ +#define DEF_HEIGHT 2415 /* height in y (300d/i, 8.5" paper) */ +#define DEV_UNITS 300 /* EPS translator units: N per inch */ +#define EPS_UNITS 72 /* PostScript units (points) */ +#define DEF_PENBASE 3 /* base pen width (LW 1->2) */ +#define DEF_PENSLOPE 4 /* pen width slope (LW 2->4, 3->6 etc.) */ +#define SZ_PENCMD 16 /* total no. of chars in penwidth instruction */ +#define SZ_PENVAL 2 /* no. of chars in penwidth value */ +#define SZ_VCODE 7 /* no. of chars in MOVE or DRAW opcode */ +#define SZ_VECT 17 /* total no. chars in a MOVE or DRAW inst. */ +#define SZ_COORD 4 /* no. of chars in device coordinate */ +#define XY_MOVE 0 +#define XY_DRAW 1 + +struct sgi_inst { + short opcode; + short x; + short y; +}; + +/* Commands to setup Postscript environment. + */ +static char *ps_init[] = { + "/devppi 300 def", + "/userppi 72 def", + "/pagewidth 8.5 def", + "/devpixtouser { userppi mul devppi div } def", + "/setscale { 1 devpixtouser 1 devpixtouser scale } def", + "/pagetolandscape 90 def", + "/setcoords { pagewidth userppi mul 0 translate", + " pagetolandscape rotate setscale } def", + "/setjoins { 1 setlinejoin 1 setlinecap } def", + NULL }; + +static char *ps_endprolog[] = { + "%%EndProlog", + "%%Page: 1 1", + "gsave setscale setjoins", + NULL }; + +/* 7BYTE -- Postscript procedures to move or draw, with the X,Y coordinates + * encoded as a 4 byte sequence (7 bytes including the command name and spaces) + * following the command name. This is the fastest encoding, since it + * minimizes the Postscript interpreter execution time. + * + * bit 76543210 + * ------------------------------------------ + * 0 01XXXXXX hi 6 X bits + * 1 01XXXXXX li 6 X bits + * 2 01YYYYYY hi 6 Y bits + * 3 01YYYYYY lo 6 Y bits + */ +static char *ps_7byte[] = { + "/getpoint {", + " currentfile read pop 8#77 and 6 bitshift", + " currentfile read pop 8#77 and or", + " currentfile read pop 8#77 and 6 bitshift", + " currentfile read pop 8#77 and or", + " } def", + "/m { getpoint moveto } def", + "/d { getpoint lineto } def", + NULL }; + +/* 4BYTE -- Postscript procedure to draw an arbitrary series of vectors, + * encoded 4 bytes per point. This is the most space efficient encoding, + * but the runtime may be somewhat longer than for the 7byte encoding, + * due to the Postscript interpreter overhead. + * + * Optional Flag byte: + * > move instruction + * + draw instruction + * $ terminate plotting + * other ignored (e.g., whitespace) + * + * Point Encoding: + * bit 76543210 + * ------------------------------------------ + * 1 01XXXXXX hi 6 X bits + * 2 01XXXXXX lo 6 X bits + * 3 01YYYYYY hi 6 Y bits + * 4 01YYYYYY lo 6 Y bits + * + * Data points are encoded 12 bits (0-4095) per X,Y coordinate. The flag byte + * is used as the terminator, to toggle the move/draw state, and to permit + * whitespace to be ignored. A high bit is set in each byte to ensure a + * printable character, as control codes would interfere with the operation of + * the Postscript interpreter. + */ +#define CH_MOVE '>' +#define CH_DRAW '+' +#define CH_EXITPLOT '$' + +static char *ps_4byte[] = { + "/plot { /movepen { moveto } def", + " { currentfile read not { exit } if", + " { dup 8#100 ge", + " { exit }", + " { dup 8#076 eq", + " { pop /movepen { moveto } def", + " currentfile read not { exit } if }", + " { dup 8#053 eq", + " { pop /movepen { lineto } def", + " currentfile read not { exit } if }", + " { dup 8#044 eq", + " { exit }", + " { pop currentfile read not { exit } if }", + " ifelse }", + " ifelse }", + " ifelse }", + " ifelse", + " } loop", + " dup 8#044 eq { pop exit } { 8#77 and 6 bitshift } ifelse", + " currentfile read pop 8#77 and or", + " currentfile read pop 8#77 and 6 bitshift", + " currentfile read pop 8#77 and or", + " movepen", + " } loop", + " } def", + NULL }; + +static int npts = 0; +static int fourbyte = 0; +static int penmode = -1; +static int dev_left; +static int dev_bottom; +static int dev_width; +static int dev_height; +static int dev_penbase = DEF_PENBASE; +static int dev_penslope = DEF_PENSLOPE; +static char progname[SZ_LINE+1]; + +static void translate (FILE *in, FILE *out); +static void xy_point (FILE *out, register int x, register int y, int flag); +static void xy_flush (FILE *out); +static char *penencode (int val, char *code); +static void textout (FILE *out, char *text[]); +static void eps_comments (FILE *out); + + + +/* MAIN -- Main entry point for SGI2UAPL. Optional arguments are device + * window parameters and name of input file. + */ +int +main (int argc, char *argv[]) +{ + FILE *in; + char *infile; + char *argp; + int argno; + int np; + char penparam[SZ_PENCMD]; + + + strcpy (progname, argv[0]); + infile = "stdin"; + + /* Process the command line. + */ + for (argno=1; (argp = argv[argno]) != NULL; argno++) { + if (argp[0] == '-') { + /* A window-control or pen width switch. + */ + switch (argp[1]) { + case '4': + fourbyte++; + break; + case 'l': + dev_left = get_iarg (argp[2], argv, argno, DEF_LEFT); + break; + case 'b': + dev_bottom = get_iarg (argp[2], argv, argno, DEF_BOTTOM); + break; + case 'w': + dev_width = get_iarg (argp[2], argv, argno, DEF_WIDTH); + break; + case 'h': + dev_height = get_iarg (argp[2], argv, argno, DEF_HEIGHT); + break; + case 'p': + if (argp[2] == (char) 0) + if (argv[argno+1] == NULL) { + fprintf (stderr, "missing arg to switch `%s';", + argp); + fprintf (stderr, " reset to %d.%d\n", dev_penbase, + dev_penslope); + } else + strcpy (penparam, argv[++argno]); + else + strcpy (penparam, argv[argno]+2); + + np = sscanf (penparam, "%d . %d", &dev_penbase, + &dev_penslope); + if (np == 1) { + dev_penslope = dev_penbase; + } else if (np < 1) { + dev_penbase = DEF_PENBASE; + dev_penslope = DEF_PENSLOPE; + } + + break; + default: + fprintf (stderr, "sgi2ueps: unknown switch '%s'\n", argp); + } + + } else { + /* Input sgi-metacode file specification. + */ + infile = argp; + } + } + + if (strcmp (infile, "stdin") == 0) + in = stdin; + else + in = fopen (infile, "r"); + + if (in == NULL) { + fprintf (stderr, "Fatal error (sgi2ueps): Cannot open `%s'\n", + infile); + fflush (stderr); + exit (OSOK+1); + } + + /* Process the metacode. + */ + translate (in, stdout); + + if (in != stdin) + fclose (in); + + return (0); +} + + +/* TRANSLATE -- Interpret input SGI metacode instructions into device + * instructions and write to stdout. + */ +static void +translate (FILE *in, FILE *out) +{ + register struct sgi_inst *sgip; + struct sgi_inst inbuf[LEN_MCBUF], *buftop; + int n, x, y, curpoints = 0, swap_bytes; + float xscale, yscale; + + + swap_bytes = isSwapped(); + + xscale = (float) dev_width / (float) SGK_MAXNDC; + yscale = (float) dev_height / (float) SGK_MAXNDC; + + /* Output device initialization. */ + eps_comments (out); + textout (out, ps_init); + + /* Define the Postscript plotting procedures. */ + if (fourbyte) + textout (out, ps_4byte); + else + textout (out, ps_7byte); + + textout (out, ps_endprolog); + + /* Initialize pen width. */ + fwrite (penencode (dev_penbase, DEV_SETLW), SZ_PENCMD, 1, out); + + /* Process the metacode: + */ + while ((n = fread ((char *)inbuf, sizeof(*sgip), LEN_MCBUF, in)) > 0) { + if (swap_bytes) + bswap2 ((unsigned char *)inbuf, (unsigned char *)inbuf, + sizeof(*sgip) * n); + + buftop = inbuf + n; + + for (sgip = inbuf; sgip < buftop; sgip++) { + switch (sgip->opcode) { + case SGK_FRAME: + xy_flush (out); + fprintf (out, DEV_FRAME); + break; + + case SGK_MOVE: + x = dev_left + sgip->x * xscale; + y = dev_bottom + sgip->y * yscale; + xy_point (out, x, y, XY_MOVE); + break; + + case SGK_DRAW: + x = dev_left + sgip->x * xscale; + y = dev_bottom + sgip->y * yscale; + xy_point (out, x, y, XY_DRAW); + + /* Limit number of points passed to Postscript between + * 'stroke' commands to draw the buffered points. + */ + curpoints = curpoints + 1; + if (curpoints > MAX_POINTS) { + xy_flush (out); + xy_point (out, x, y, XY_MOVE); + curpoints = 0; + } + break; + + case SGK_SETLW: { + /* Set pen width. + */ + int x = max (0, sgip->x - 1); + + xy_flush (out); + curpoints = 0; + fwrite (penencode ( + max (1, dev_penbase + x * dev_penslope), DEV_SETLW), + SZ_PENCMD, 1, out); + } + break; + + default: + fprintf (stderr, "sgi2ueps: unrecognized sgi opcode %d\n", + sgip->opcode); + break; + } + } + } + + /* Terminate plotting and exit. + */ + xy_flush (out); + + fprintf (out, "grestore showpage\n"); +} + + +/* XY_POINT -- Output a move or draw instruction, using either the 4 byte or + * 7 byte encoding scheme. + */ +static void +xy_point ( + FILE *out, /* output file */ + register int x, /* coords to move to */ + register int y, /* coords to move to */ + int flag /* move or draw? */ +) +{ + static char o[] = "m XXXX"; + register char *op = o; + register int n; + + if (fourbyte) { + if (npts == 0) { + fputs ("plot\n", out); + penmode = XY_MOVE; + } + + if (flag != penmode) + *op++ = ((penmode = flag) == XY_MOVE) ? CH_MOVE : CH_DRAW; + + *op++ = ((n = ((x >> 6) & 077)) == 077) ? n : (0100 | n); + *op++ = ((n = (x & 077)) == 077) ? n : (0100 | n); + *op++ = ((n = ((y >> 6) & 077)) == 077) ? n : (0100 | n); + *op++ = ((n = (y & 077)) == 077) ? n : (0100 | n); + + fwrite (o, op-o, 1, out); + if (!(++npts % 15)) + fputc ('\n', out); + + } else { + o[0] = (flag == XY_MOVE) ? 'm' : 'd'; + o[2] = ((n = ((x >> 6) & 077)) == 077) ? n : (0100 | n); + o[3] = ((n = (x & 077)) == 077) ? n : (0100 | n); + o[4] = ((n = ((y >> 6) & 077)) == 077) ? n : (0100 | n); + o[5] = ((n = (y & 077)) == 077) ? n : (0100 | n); + + fwrite (o, 6, 1, out); + if (!(++npts % 10)) + fputc ('\n', out); + else + fputc (' ', out); + } +} + + +/* XY_FLUSH -- Terminate the current drawing sequence, if any, and issue the + * stroke command to Postscript to draw the buffered points. + */ +static void +xy_flush (FILE *out) +{ + if (npts > 0) { + if (fourbyte) + fputs ("$\n", out); + else if (npts % 10) + fputc ('\n', out); + fputs ("stroke\n", out); + npts = 0; + } +} + + +/* PENENCODE -- Encode base, slope into a character string formatted for the + * device set-pen command. + */ +static char * +penencode ( + int val, /* device line width */ + char *code /* device set-linewidth command */ +) +{ + static char obuf[SZ_PENCMD+1]; + register int digit, n; + register char *op, *ip; + + for (op = &obuf[SZ_PENVAL-1], digit = SZ_PENVAL, n=val; --digit >= 0; + n = n / 10) + *op-- = n % 10 + '0'; + obuf[SZ_PENVAL] = ' '; + for (op = &obuf[SZ_PENVAL+1], ip = code, n = SZ_PENCMD; --n >= 0; ) + *op++ = *ip++; + + return (obuf); +} + + +/* TEXTOUT -- Output lines of text to a file. + */ +static void +textout ( + FILE *out, /* output file */ + char *text[] /* array of lines of text */ +) +{ + register char **lp; + + for (lp=text; *lp; lp++) { + fputs (*lp, out); + fputc ('\n', out); + } +} + + +/* EPS_COMMENTS -- Set identifying comments for EPS conformance. + */ +static void +eps_comments (FILE *out) +{ + time_t clock; + int llx, lly, urx, ury; + + clock = time(0); + + fprintf (out, "%%!PS-Adobe-3.0 EPSF-3.0\n"); + fprintf (out, "%%%%Title: IRAF SGI plot\n"); + fprintf (out, "%%%%Creator: %s\n", progname); + fprintf (out, "%%%%CreationDate: %s", asctime(localtime(&clock))); + + /* Compute bounding box in PostScript coordinates. */ + llx = ((float) dev_left / (float) DEV_UNITS) * (float) EPS_UNITS; + lly = ((float) dev_bottom / (float) DEV_UNITS) * (float) EPS_UNITS; + urx = ((float) (dev_left + dev_width) / (float) DEV_UNITS) + * (float) EPS_UNITS; + ury = ((float) (dev_bottom + dev_height) / (float) DEV_UNITS) + * (float) EPS_UNITS; + + fprintf (out, "%%%%BoundingBox: %d %d %d %d\n", llx, lly, urx, ury); + fprintf (out, "%%%%Pages: 1\n"); + fprintf (out, "%%%%EndComments\n"); +} |