diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/postscript/postbgi |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/postscript/postbgi')
-rwxr-xr-x | sys/src/cmd/postscript/postbgi/README | 21 | ||||
-rwxr-xr-x | sys/src/cmd/postscript/postbgi/mkfile | 61 | ||||
-rwxr-xr-x | sys/src/cmd/postscript/postbgi/postbgi.1 | 243 | ||||
-rwxr-xr-x | sys/src/cmd/postscript/postbgi/postbgi.c | 1523 | ||||
-rwxr-xr-x | sys/src/cmd/postscript/postbgi/postbgi.h | 203 | ||||
-rwxr-xr-x | sys/src/cmd/postscript/postbgi/postbgi.mk | 93 | ||||
-rwxr-xr-x | sys/src/cmd/postscript/postbgi/postbgi.ps | 135 |
7 files changed, 2279 insertions, 0 deletions
diff --git a/sys/src/cmd/postscript/postbgi/README b/sys/src/cmd/postscript/postbgi/README new file mode 100755 index 000000000..de815330e --- /dev/null +++ b/sys/src/cmd/postscript/postbgi/README @@ -0,0 +1,21 @@ + +BGI (Basic Graphical Instructions) to PostScript translator. Probably +not useful outside the Computer Centers. Added code to tie lines to +device space coordinates. Helps eliminate variations in line widths +noticeable when users selected a non-zero linewidth with the -w option. + +Much that was omitted from early versions of the program has been +implemented. What's in place will handle most STARE (black and white) +and PRISM (color) BGI jobs. PRISM jobs often fill regions with color, +and need require device specific tuning to get things just right. An +easy solution is add "-P/prism true def" option to the postbgi command +line when you translate PRISM jobs. + +A typical command line for STARE jobs would be, + + postbgi file >file.ps + +while for PRISM jobs use, + + postbgi -P"/prism true def" file >file.ps + diff --git a/sys/src/cmd/postscript/postbgi/mkfile b/sys/src/cmd/postscript/postbgi/mkfile new file mode 100755 index 000000000..5722ae6ca --- /dev/null +++ b/sys/src/cmd/postscript/postbgi/mkfile @@ -0,0 +1,61 @@ +BUILTINS= +</$objtype/mkfile +MAKE=mk + +SYSTEM=plan9 +VERSION=3.3.1 + +ROOT= +MAN1DIR=$ROOT/tmp +POSTBIN=$ROOT/rc/bin/postscript/ +POSTLIB=$ROOT/sys/lib/postscript/prologues + +COMMONDIR=../common + +CC=pcc +LD=pcc + +CFLAGS=-c -D$SYSTEM -D_POSIX_SOURCE -I$COMMONDIR -B +LDFLAGS= + +all :V: $O.out + +install :V: $POSTBIN/$objtype/postbgi $POSTLIB/postbgi.ps $MAN1DIR/postbgi.1 + +installall :V: + for(objtype in $CPUS) { \ + $MAKE 'MAKE=$MAKE' \ + 'SYSTEM=$SYSTEM' 'VERSION=$VERSION' \ + 'FONTDIR=$FONTDIR' 'HOSTDIR=$HOSTDIR' 'MAN1DIR=$MAN1DIR' \ + 'POSTBIN=$POSTBIN' 'POSTLIB=$POSTLIB' 'TMACDIR=$TMACDIR' \ + 'DKHOST=$DKHOST' 'DKSTREAMS=$DKSTREAMS' \ + 'ROUNDPAGE=$ROUNDPAGE' \ + 'CC=$CC' 'LD=$LD' 'CFLAGS=$CFLAGS' 'LDFLAGS=$LDFLAGS' \ + install \ + } + +clean :V: + rm -f *.$O + +clobber :V: clean + rm -f $O.out + +$POSTBIN/$objtype/postbgi : $O.out + cp $prereq $target + +$POSTLIB/postbgi.ps : postbgi.ps + cp $prereq $target + +$MAN1DIR/postbgi.1 : postbgi.1 + cp $prereq $target + +$O.out : postbgi.$O $COMMONDIR/glob.$O $COMMONDIR/misc.$O $COMMONDIR/request.$O $COMMONDIR/getopt.$O + $LD $LDFLAGS $prereq + +%.$O: %.c + $CC $CFLAGS $stem.c + +postbgi.$O : $COMMONDIR/comments.h $COMMONDIR/gen.h $COMMONDIR/path.h $COMMONDIR/ext.h postbgi.h + +common :V: + cd $COMMONDIR; $MAKE diff --git a/sys/src/cmd/postscript/postbgi/postbgi.1 b/sys/src/cmd/postscript/postbgi/postbgi.1 new file mode 100755 index 000000000..971e14a0c --- /dev/null +++ b/sys/src/cmd/postscript/postbgi/postbgi.1 @@ -0,0 +1,243 @@ +.ds dQ /usr/lib/postscript +.TH POSTBGI 1 "DWB 3.2" +.SH NAME +.B postbgi +\- PostScript translator for +.SM BGI +(Basic Graphical Instructions) files +.SH SYNOPSIS +\*(mBpostbgi\f1 +.OP "" options [] +.OP "" files [] +.SH DESCRIPTION +.B postbgi +translates +.SM BGI +(Basic Graphical Instructions) +.I files +into PostScript and writes the results on the +standard output. +If no +.I files +are specified, or if +.OP \- +is one of the input +.IR files , +the standard input is read. +The following +.I options +are understood: +.TP 0.75i +.OP \-c num +Print +.I num +copies of each page. +By default only one copy is printed. +.TP +.OP \-f name +Print text using font +.IR name . +Any PostScript font can be used, +although the best results will only be +obtained with constant width fonts. +The default font is Courier. +.TP +.OP \-m num +Magnify each logical page by the factor +.IR num . +Pages are scaled uniformly about the origin, +which by default is located at the center of +each page. +The default magnification is 1.0. +.TP +.OP \-n num +Print +.I num +logical pages on each piece of paper, +where +.I num +can be any positive integer. +By default +.I num +is set to 1. +.TP +.OP \-o list +Print pages whose numbers are given in the comma-separated +.IR list . +The list contains single numbers +.I N +and ranges +.IR N1\-\|N2 . +A missing +.I N1 +means the lowest numbered page, a missing +.I N2 +means the highest. +.TP +.OP \-p mode +Print +.I files +in either \*(mBportrait\fP or \*(mBlandscape\fP +.IR mode . +Only the first character of +.I mode +is significant. +The default +.I mode +is \*(mBportrait\fP. +.TP +.OP \-w num +Set the line width used for graphics to +.I num +points, where a point is approximately 1/72 +of an inch. +By default +.I num +is set to 0 points, which forces lines to be +one pixel wide. +.TP +.OP \-x num +Translate the origin +.I num +inches along the positive x axis. +The default +coordinate system has the origin fixed at the +center of the page, with positive +x to the right and positive y up the page. +Positive +.I num +moves everything right. +The default offset is 0 inches. +.TP +.OP \-y num +Translate the origin +.I num +inches along the positive y axis. +Positive +.I num +moves everything up the page. +The default offset is 0 inches. +.TP +.OP \-E name +Set the character encoding for text fonts to +.IR name . +Requesting +.I name +means include file +.MI \*(dQ name .enc \f1. +A nonexistent encoding file is silently ignored. +The default selects file +.MR \*(dQ/Default.enc . +.TP +.OP \-L file +Use +.I file +as the PostScript prologue. +.br +The default is +.MR \*(dQ/postbgi.ps . +.PP +Three options allow insertion of arbitrary PostScript +at controlled points in the translation process: +.TP 0.75i +.OP \-C file +Copy +.I file +to the output file; +.I file +must contain legitimate PostScript. +.TP +.OP \-P string +Include +.I string +in the output file; +.I string +must be legitimate PostScript. +.TP +.OP \-R action +Requests special +.I action +(e.g., +.MR manualfeed ) +on a per page or global basis. +The +.I action +string can be given as +.IR request , +.IM request : page\f1\|, +or +.IM request : page : file\f1\|. +If +.I page +is omitted or given as 0, the request +applies to all pages. +If +.I file +is omitted, the request +lookup is done in +.MR \*(dQ/ps.requests . +.PP +.B postbgi +can handle +.SM STARE +(black and white) and +.SM PRISM +(color) +.SM BGI +jobs. +By default plots are rigidly scaled to fill the page, which produces +the good results for most +.SM STARE +jobs. +.SM PRISM +jobs typically fill regions with colors, and often require device +specific tuning to produce acceptable results. +Adding the +.MW \-P"/prism\ true\ def" +option is strongly recommended when +.B postbgi +is translating +.SM PRISM +jobs. +.br +.ne 7v +.SH EXAMPLES +For most +.SM STARE +jobs, +.EX +postbgi \f2file +.EE +gives good results, while +.EX +postbgi \-P"/prism true def" \f2file +.EE +is recommended when translating +.SM PRISM +jobs. +.SH DIAGNOSTICS +A 0 exit status is returned if +.I files +were successfully processed. +.SH BUGS +The default line width is too small for write-white +print engines, like the one used by the PS-2400. +Several +.SM BGI +opcodes have not been implemented. +.SH FILES +.MW \*(dQ/postbgi.ps +.br +.MW \*(dQ/forms.ps +.br +.MW \*(dQ/ps.requests +.SH SEE ALSO +.BR dpost (1), +.BR postdaisy (1), +.BR postdmd (1), +.BR postio (1), +.BR postmd (1), +.BR postprint (1), +.BR postreverse (1), +.BR posttek (1), +.BR psencoding (1) diff --git a/sys/src/cmd/postscript/postbgi/postbgi.c b/sys/src/cmd/postscript/postbgi/postbgi.c new file mode 100755 index 000000000..c6047d75b --- /dev/null +++ b/sys/src/cmd/postscript/postbgi/postbgi.c @@ -0,0 +1,1523 @@ +/* + * + * postbgi - BGI (Basic Graphical Instructions) to PostScript translator. + * + * A simple program that translates BGI files into PostScript. Probably only + * useful in Computer Centers that support STARE or PRISM plotters. Most of the + * code was borrowed from the corresponding program that was written for printers + * that understand Impress. + * + * Extending the original program to handle PRISM jobs was not trivial. Graphics + * packages that support PRISM occasionally use BGI commands that I ignored in the + * STARE implementation. Subroutines, color requests, patterns (for filling), and + * filled trapeziods were the most important omissions. All are now implemented, + * and at present only repeats, filled slices, and raster rectangles are missing. + * + * Pattern filling results were not always predictable or even good, unless the + * halftone screen definitions were changed and scaling was adjusted so one pixel + * in user space mapped into an integral number of device space pixels. Doing that + * makes the resulting PostScript output device dependent, but was often necessary. + * I've added two booleans to the PostScript prologue (fixscreen and scaletodevice) + * that control what's done. By default both are false (check postbgi.ps) but can + * be set to true on the command line using the -P option or by hand by changing + * the definitions in the prologue. A command line that would set fixscreen and + * scaletodevice true would look like, + * + * postbgi -P"/fixscreen true" -P"/scaletodevice true" file >file.ps + * + * Several other approaches are available if you want to have your spooler handle + * STARE and PRISM jobs differently. A boolean called prism is defined in the + * prologue (postbgi.ps) and if it's set to true PostScript procedure setup will + * set fixscreen and scaletodevice to true before anything important is done. That + * means the following command line, + * + * postbgi -P"/prism true" file >file.ps + * + * accomplishes the same things as the last example. Two different prologue files, + * one for STARE jobs and the other for PRISM, could be used and the spooler could + * point postbgi to the appropriate one using the -L option. In that case the only + * important difference in the two prologues would be the definition of prism. The + * prologue used for PRISM jobs would have prism set to true, while the STARE + * prologue would have it set to false. + * + * Also included is code that ties lines to device space coordinates. What you get + * is a consistent line thickness, but placement of lines won't be exact. It's a + * trade-off that should be right for most jobs. Everything is implemented in the + * prologue (postbgi.ps) and nothing will be done if the linewidth is zero or if + * the boolean fixlinewidth (again in postbgi.ps) is false. Once again the -P + * option can be used to set fixlinewidth to whatever you choose. + * + * BGI supports color mixing but PostScript doesn't. BGI files that expect to mix + * colors won't print properly. PostScript's fill operator overlays whatever has + * already been put down. Implementing color mixing would have been a terribly + * difficult job - not worth the effort! + * + * The PostScript prologue is copied from *prologue before any of the input files + * are translated. The program expects that the following PostScript procedures + * are defined in that file: + * + * setup + * + * mark ... setup - + * + * Handles special initialization stuff that depends on how the program + * was called. Expects to find a mark followed by key/value pairs on the + * stack. The def operator is applied to each pair up to the mark, then + * the default state is set up. + * + * pagesetup + * + * page pagesetup - + * + * Does whatever is needed to set things up for the next page. Expects + * to find the current page number on the stack. + * + * v + * + * dx1 dy1 ... dxn dyn x y v - + * + * Draws the vector described by the numbers on the stack. The top two + * numbers are the coordinates of the starting point. The rest of the + * numbers are relative displacements from the preceeding point. + * + * pp + * + * x1 y1 ... xn yn string pp - + * + * Prints string, which is always a single character, at the points + * represented by the rest of the numbers on the stack. + * + * R + * + * n deltax deltay x y R - + * + * Creates a rectangular path with its lower left corner at (x, y) and + * sides of length deltax and deltay. The resulting path is stroked if + * n is 0 and filled otherwise. + * + * T + * + * dx3 dy3 dx2 dy2 dx1 dy1 x y T - + * + * Fills a trapezoid starting at (x, y) and having relative displacements + * given by the (dx, dy) pairs. + * + * t + * + * angle x y string t - + * + * Prints string starting at (x, y) using an orientation of angle degrees. + * The PostScript procedure can handle any angle, but BGI files will only + * request 0 or 90 degrees. Text printed at any other orientation will be + * vector generated. + * + * p + * + * x y p - + * + * Called to mark the point (x, y). It fills a small circle, that right + * now has a constant radius. This stuff could probably be much more + * efficient? + * + * l + * + * array l - + * + * Sets the line drawing mode according to the description given in + * array. The arrays that describe the different line styles are declared + * in STYLES (file posttek.h), although it would be better to have them + * defined in the prologue. + * + * c + * + * red green blue c - + * + * Sets the current PostScript RGB color using setrgbcolor. Also used for + * selecting appropriate patterns as colors. + * + * f + * + * bgisize f - + * + * Changes the size of the font that's used to print text. bgisize is a + * grid separation in a 5 by 7 array in which characters are assumed to + * be built. + * + * done + * + * done + * + * Makes sure the last page is printed. Only needed when we're printing + * more than one page on each sheet of paper. + * + * The default line width is zero, which forces lines to be one pixel wide. That + * works well for 'write to black' engines but won't be right for 'write to white' + * engines. The line width can be changed using the -w option, or you can change + * the initialization of linewidth in the prologue. Code in the prologue supports + * the generation of uniform width lines when linewidth is non-zero and boolean + * fixlinewidth is true. + * + * Many default values, like the magnification and orientation, are defined in + * the prologue, which is where they belong. If they're changed (by options), an + * appropriate definition is made after the prologue is added to the output file. + * The -P option passes arbitrary PostScript through to the output file. Among + * other things it can be used to set (or change) values that can't be accessed by + * other options. + * + */ + +#include <stdio.h> +#include <sys/types.h> +#include <fcntl.h> +#include <signal.h> +#include <math.h> +#include <ctype.h> +#ifdef plan9 +#define isascii(c) ((unsigned char)(c)<=0177) +#endif + +#include "comments.h" /* PostScript file structuring comments */ +#include "gen.h" /* general purpose definitions */ +#include "path.h" /* for the prologue */ +#include "ext.h" /* external variable declarations */ +#include "postbgi.h" /* a few definitions just used here */ + +char *optnames = "a:c:f:m:n:o:p:w:x:y:A:C:E:J:L:P:R:DI"; + +char *prologue = POSTBGI; /* default PostScript prologue */ +char *formfile = FORMFILE; /* stuff for multiple pages per sheet */ + +int formsperpage = 1; /* page images on each piece of paper */ +int copies = 1; /* and this many copies of each sheet */ + +char *styles[] = STYLES; /* descriptions of line styles */ + +int hpos = 0; /* current horizontal */ +int vpos = 0; /* and vertical position */ + +int bgisize = BGISIZE; /* just the character grid spacing */ +int linespace; /* distance between lines of text */ + +int bgimode; /* character or graph mode */ + +int in_subr = FALSE; /* currently defining a subroutine */ +int in_global = FALSE; /* to save space with subroutine defs */ +int subr_id = 0; /* defining this subroutine */ +int shpos = 0; /* starting horizontal */ +int svpos = 0; /* and vertical positions - subroutines */ +Disp displacement[64]; /* dx and dy after a subroutine call */ + +Fontmap fontmap[] = FONTMAP; /* for translating font names */ +char *fontname = "Courier"; /* use this PostScript font */ + +int page = 0; /* page we're working on */ +int printed = 0; /* printed this many pages */ + +FILE *fp_in = stdin; /* read from this file */ +FILE *fp_out = NULL; /* and write stuff here */ +FILE *fp_acct = NULL; /* for accounting data */ + +/*****************************************************************************/ + +main(agc, agv) + + int agc; + char *agv[]; + +{ + +/* + * + * A program that converts BGI (Basic Graphical Instructions) files generated by + * packages like GRAFPAC and DISSPLA into PostScript. It does an adequate job but + * is far from perfect. A few things still haven't been implemented (eg. repeats + * and raster rectangles), but what's here should be good enough for most of our + * STARE and PRISM jobs. Color mixing (in PRISM jobs) won't work on PostScript + * printers, and there's no chance I'll implement it! + * + */ + + argc = agc; /* global so everyone can use them */ + argv = agv; + + prog_name = argv[0]; /* just for error messages */ + + init_signals(); /* set up interrupt handling */ + header(); /* PostScript header comments */ + options(); /* command line options */ + setup(); /* for PostScript */ + arguments(); /* followed by each input file */ + done(); /* print the last page etc. */ + account(); /* job accounting data */ + + exit(x_stat); /* everything probably went OK */ + +} /* End of main */ + +/*****************************************************************************/ + +init_signals() + +{ + +/* + * + * Make sure we handle interrupts. + * + */ + + if ( signal(SIGINT, interrupt) == SIG_IGN ) { + signal(SIGINT, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + signal(SIGHUP, SIG_IGN); + } else { + signal(SIGHUP, interrupt); + signal(SIGQUIT, interrupt); + } /* End else */ + + signal(SIGTERM, interrupt); + +} /* End of init_signals */ + +/*****************************************************************************/ + +header() + +{ + + int ch; /* return value from getopt() */ + int old_optind = optind; /* for restoring optind - should be 1 */ + +/* + * + * Scans the option list looking for things, like the prologue file, that we need + * right away but could be changed from the default. Doing things this way is an + * attempt to conform to Adobe's latest file structuring conventions. In particular + * they now say there should be nothing executed in the prologue, and they have + * added two new comments that delimit global initialization calls. Once we know + * where things really are we write out the job header, follow it by the prologue, + * and then add the ENDPROLOG and BEGINSETUP comments. + * + */ + + while ( (ch = getopt(argc, argv, optnames)) != EOF ) + if ( ch == 'L' ) + prologue = optarg; + else if ( ch == '?' ) + error(FATAL, ""); + + optind = old_optind; /* get ready for option scanning */ + + fprintf(stdout, "%s", CONFORMING); + fprintf(stdout, "%s %s\n", VERSION, PROGRAMVERSION); + fprintf(stdout, "%s %s\n", DOCUMENTFONTS, ATEND); + fprintf(stdout, "%s %s\n", PAGES, ATEND); + fprintf(stdout, "%s", ENDCOMMENTS); + + if ( cat(prologue) == FALSE ) + error(FATAL, "can't read %s", prologue); + + fprintf(stdout, "%s", ENDPROLOG); + fprintf(stdout, "%s", BEGINSETUP); + fprintf(stdout, "mark\n"); + +} /* End of header */ + +/*****************************************************************************/ + +options() + +{ + + int ch; /* option name - from getopt() */ + +/* + * + * Reads and processes the command line options. + * + */ + + while ( (ch = getopt(argc, argv, optnames)) != EOF ) { + switch ( ch ) { + case 'a': /* aspect ratio */ + fprintf(stdout, "/aspectratio %s def\n", optarg); + break; + + case 'c': /* copies */ + copies = atoi(optarg); + fprintf(stdout, "/#copies %s def\n", optarg); + break; + + case 'f': /* new font */ + fontname = get_font(optarg); + fprintf(stdout, "/font /%s def\n", fontname); + break; + + case 'm': /* magnification */ + fprintf(stdout, "/magnification %s def\n", optarg); + break; + + case 'n': /* forms per page */ + formsperpage = atoi(optarg); + fprintf(stdout, "%s %s\n", FORMSPERPAGE, optarg); + fprintf(stdout, "/formsperpage %s def\n", optarg); + break; + + case 'o': /* output page list */ + out_list(optarg); + break; + + case 'p': /* landscape or portrait mode */ + if ( *optarg == 'l' ) + fprintf(stdout, "/landscape true def\n"); + else fprintf(stdout, "/landscape false def\n"); + break; + + case 'w': /* line width */ + fprintf(stdout, "/linewidth %s def\n", optarg); + break; + + case 'x': /* shift horizontally */ + fprintf(stdout, "/xoffset %s def\n", optarg); + break; + + case 'y': /* and vertically on the page */ + fprintf(stdout, "/yoffset %s def\n", optarg); + break; + + case 'A': /* force job accounting */ + case 'J': + if ( (fp_acct = fopen(optarg, "a")) == NULL ) + error(FATAL, "can't open accounting file %s", optarg); + break; + + case 'C': /* copy file straight to output */ + if ( cat(optarg) == FALSE ) + error(FATAL, "can't read %s", optarg); + break; + + case 'E': /* text font encoding */ + fontencoding = optarg; + break; + + case 'L': /* Postscript prologue file */ + prologue = optarg; + break; + + case 'P': /* PostScript pass through */ + fprintf(stdout, "%s\n", optarg); + break; + + case 'R': /* special global or page level request */ + saverequest(optarg); + break; + + case 'D': /* debug flag */ + debug = ON; + break; + + case 'I': /* ignore FATAL errors */ + ignore = ON; + break; + + case '?': /* don't know the option */ + error(FATAL, ""); + break; + + default: /* don't know what to do for ch */ + error(FATAL, "missing case for option %c", ch); + break; + } /* End switch */ + } /* End while */ + + argc -= optind; /* get ready for non-option args */ + argv += optind; + +} /* End of options */ + +/*****************************************************************************/ + +char *get_font(name) + + char *name; /* name the user asked for */ + +{ + + int i; /* for looking through fontmap[] */ + +/* + * + * Called from options() to map a user's font name into a legal PostScript name. + * If the lookup fails *name is returned to the caller. That should let you choose + * any PostScript font. + * + */ + + for ( i = 0; fontmap[i].name != NULL; i++ ) + if ( strcmp(name, fontmap[i].name) == 0 ) + return(fontmap[i].val); + + return(name); + +} /* End of get_font */ + +/*****************************************************************************/ + +setup() + +{ + +/* + * + * Handles things that must be done after the options are read but before the + * input files are processed. + * + */ + + writerequest(0, stdout); /* global requests eg. manual feed */ + setencoding(fontencoding); + fprintf(stdout, "setup\n"); + + if ( formsperpage > 1 ) { + if ( cat(formfile) == FALSE ) + error(FATAL, "can't read %s", formfile); + fprintf(stdout, "%d setupforms\n", formsperpage); + } /* End if */ + + fprintf(stdout, "%s", ENDSETUP); + +} /* End of setup */ + +/*****************************************************************************/ + +arguments() + +{ + +/* + * + * Makes sure all the non-option command line options are processed. If we get + * here and there aren't any arguments left, or if '-' is one of the input files + * we'll process stdin. + * + */ + + if ( argc < 1 ) + conv(); + else + while ( argc > 0 ) { + if ( strcmp(*argv, "-") == 0 ) + fp_in = stdin; + else if ( (fp_in = fopen(*argv, "r")) == NULL ) + error(FATAL, "can't open %s", *argv); + conv(); + if ( fp_in != stdin ) + fclose(fp_in); + argc--; + argv++; + } /* End while */ + +} /* End of arguments */ + +/*****************************************************************************/ + +done() + +{ + +/* + * + * Finished with the last input file, so mark the end of the pages, make sure the + * last page is printed, and restore the initial environment. + * + */ + + fprintf(stdout, "%s", TRAILER); + fprintf(stdout, "done\n"); + fprintf(stdout, "%s %s\n", DOCUMENTFONTS, fontname); + fprintf(stdout, "%s %d\n", PAGES, printed); + +} /* End of done */ + +/*****************************************************************************/ + +account() + +{ + +/* + * + * Writes an accounting record to *fp_acct, provided it's not NULL. + * + */ + + if ( fp_acct != NULL ) + fprintf(fp_acct, " print %d\n copies %d\n", printed, copies); + +} /* End of account */ + +/*****************************************************************************/ + +conv() + +{ + + int ch; /* next input character */ + +/* + * + * Controls the conversion of BGI files into PostScript. Not everything has been + * implemented, but what's been done should be good enough for our purposes. + * + */ + + redirect(-1); /* get ready for the first page */ + bgimode = 0; + formfeed(); + + while ( (ch = get_char()) != EOF ) { + switch ( ch ) { + case BRCHAR: /* rotated character mode */ + bgimode = ch; + text(90); + break; + + case BCHAR: /* graphical character mode */ + bgimode = ch; + text(0); + break; + + case BGRAPH: /* graphical master mode */ + bgimode = ch; + break; + + case BSUB: /* subroutine definition */ + subr_def(); + break; + + case BRET: /* end of subroutine */ + subr_end(); + break; + + case BCALL: /* subroutine call */ + subr_call(); + break; + + case BEND: /* end display - page */ + formfeed(); + break; + + case BERASE: /* erase - shouldn't be used */ + error(FATAL, "BGI erase opcode obsolete"); + break; + + case BREP: /* repeat */ + error(FATAL, "Repeat not implemented"); + repeat(); + break; + + case BSETX: /* new x coordinate */ + hgoto(get_int(0)); + break; + + case BSETY: /* new y coordinate */ + vgoto(get_int(0)); + break; + + case BSETXY: /* new x and y coordinates */ + hgoto(get_int(0)); + vgoto(get_int(0)); + break; + + case BINTEN: /* mark the current point */ + fprintf(fp_out, "%d %d p\n", hpos, vpos); + break; + + case BVISX: /* visible x */ + vector(X_COORD, VISIBLE); + break; + + case BINVISX: /* invisible x */ + vector(X_COORD, INVISIBLE); + break; + + case BVISY: /* visible y */ + vector(Y_COORD, VISIBLE); + break; + + case BINVISY: /* invisible y */ + vector(Y_COORD, INVISIBLE); + break; + + case BVEC: /* arbitrary vector */ + vector(LONGVECTOR, VISIBLE); + break; + + case BSVEC: /* short vector */ + vector(SHORTVECTOR, VISIBLE); + break; + + case BRECT: /* draw rectangle */ + rectangle(OUTLINE); + break; + + case BPOINT1: /* point plot 1 */ + case BPOINT: /* point plot 2 */ + point_plot(ch, get_char()); + break; + + case BLINE: /* line plot */ + line_plot(); + break; + + case BLTY: /* line type */ + fprintf(fp_out, "%s l\n", styles[get_data()]); + break; + + case BARC: /* circular arc */ + arc(OUTLINE); + break; + + case BFARC: /* filled circle */ + arc(FILL); + break; + + case BFRECT: /* filled rectangle */ + rectangle(FILL); + break; + + case BRASRECT: /* raster rectangle */ + error(FATAL, "Raster Rectangle not implemented"); + break; + + case BCOL: /* select color */ + set_color(get_data()); + break; + + case BFTRAPH: /* filled trapezoid */ + trapezoid(); + break; + + case BPAT: /* pattern for area filling */ + pattern(); + break; + + case BCSZ: /* change BGI character 'size' */ + setsize(get_data()); + break; + + case BNOISE: /* from bad file format */ + break; + + default: /* don't recognize the code */ + error(FATAL, "bad BGI command %d (0%o)", ch, ch); + break; + } /* End switch */ + + if ( debug == ON ) + fprintf(stderr, "\n"); + } /* End while */ + + formfeed(); /* in case BEND was missing */ + +} /* End of conv */ + +/*****************************************************************************/ + +hgoto(n) + + int n; /* new horizontal position */ + +{ + +/* + * + * Sets the current BGI horizontal position to n. + * + */ + + hpos = n; + +} /* End of hgoto */ + +/*****************************************************************************/ + +vgoto(n) + + int n; /* move to this vertical position */ + +{ + +/* + * + * Sets the absolute vertical position to n. + * + */ + + vpos = n; + +} /* End of vgoto */ + +/*****************************************************************************/ + +setsize(n) + + int n; /* BGI size - just a grid separation */ + +{ + +/* + * + * Called when we're supposed to change the BGI character size to n. The BGI + * size is the grid separation in a 5 by 7 array in which characters are assumed + * to be built. + * + */ + + bgisize = n; + linespace = LINESPACE(bgisize); + + fprintf(fp_out, "%d f\n", bgisize); + + if ( debug == ON ) + fprintf(stderr, "BGI size = %d\n", n); + +} /* End of setsize */ + +/*****************************************************************************/ + +repeat() + +{ + + int count; /* repeat this many times */ + int ch; /* next input character */ + +/* + * + * Haven't implemented repeats, although it wouldn't be difficult. Apparently it's + * not used by any graphics packages that generate BGI. + * + */ + + count = get_int(); /* get the repeat count */ + + while ( (ch = get_char()) != EOF && ch != BENDR ) ; + +} /* End of repeat */ + +/*****************************************************************************/ + +text(angle) + + int angle; /* either 0 or 90 degrees */ + +{ + + int ch; /* next character from file *fp_in */ + +/* + * + * Called from conv() after we've entered one of the graphical character modes. + * Characters are read from the input file and printed until the next mode change + * opcode is found (or until EOF). angle will be 90 for rotated character mode + * and 0 otherwise. + * + * + */ + + fprintf(fp_out, "%d %d %d(", angle, hpos, vpos); + + while ( (ch = get_char()) != EOF ) { + if ( ch == BGRAPH || ch == BCHAR || ch == BRCHAR ) { + ungetc(ch, fp_in); + position--; + break; + } /* End if */ + + switch ( ch ) { + case '\012': + vgoto(vpos - linespace); + + case '\015': + hgoto(0); + fprintf(fp_out, ")t\n%d %d %d(", angle, hpos, vpos); + break; + + case '(': + case ')': + case '\\': + putc('\\', fp_out); + + default: + if ( isascii(ch) && isprint(ch) ) + putc(ch, fp_out); + else fprintf(fp_out, "\\%.3o", ch & 0377); + break; + } /* End switch */ + } /* End while */ + + fprintf(fp_out, ") t\n"); + +} /* End of text */ + +/*****************************************************************************/ + +formfeed() + +{ + + int ch; /* repeat count for this page */ + +/* + * + * Does whatever is needed to print the last page and get ready for the next one. + * It's called, from conv(), after a BEND code is processed. I'm ignoring the + * copy count that's expected to follow each page. + * + */ + + if ( bgimode == BGRAPH && (ch = get_char()) != EOF && ! (ch & MSB) ) { + ungetc(ch, fp_in); + position--; + } /* End if */ + + if ( fp_out == stdout ) /* count the last page */ + printed++; + + fprintf(fp_out, "cleartomark\n"); + fprintf(fp_out, "showpage\n"); + fprintf(fp_out, "saveobj restore\n"); + fprintf(fp_out, "%s %d %d\n", ENDPAGE, page, printed); + + while ( (ch = get_char()) == 0 ) ; /* skip any NULL characters */ + ungetc(ch, fp_in); + position--; + + if ( ungetc(getc(fp_in), fp_in) == EOF ) + redirect(-1); + else redirect(++page); + + fprintf(fp_out, "%s %d %d\n", PAGE, page, printed+1); + fprintf(fp_out, "/saveobj save def\n"); + fprintf(fp_out, "mark\n"); + writerequest(printed+1, fp_out); + fprintf(fp_out, "%d pagesetup\n", printed+1); + + setsize(bgisize); + hpos = vpos = 0; + +} /* End of formfeed */ + +/*****************************************************************************/ + +subr_def() + +{ + +/* + * + * Starts a subroutine definition. All subroutines are defined as PostScript + * procedures that begin with the character S and end with the subroutine's id + * (a number between 0 and 63 - I guess). The primary, and perhaps only use of + * subroutines is in special color plots produced by several graphics libraries, + * and even there it's not all that common. I've also chosen not to worry about + * nested subroutine definitions - that would certainly be overkill! + * + * All subroutines set up their own (translated) coordinate system, do their work + * in that system, and restore things when they exit. To make everything work + * properly we save the current point (in shpos and svpos), set our position to + * (0, 0), and restore things at the end of the subroutine definition. That means + * hpos and vpos measure the relative displacement after a subroutine returns, and + * we save those values in the displacement[] array. The displacements are used + * (in subr_call()) to properly adjust our position after each subroutine call, + * and all subroutines are called with the current x and y coordinates on top of + * the stack. + * + */ + + if ( in_subr == TRUE ) /* a nested subroutine definition?? */ + error(FATAL, "can't handle nested subroutine definitions"); + + if ( (subr_id = get_data()) == EOF ) + error(FATAL, "missing subroutine identifier"); + + if ( in_global == FALSE ) { /* just used to reduce file size some */ + fprintf(fp_out, "cleartomark\n"); + fprintf(fp_out, "saveobj restore\n"); + fprintf(fp_out, "%s", BEGINGLOBAL); + in_global = TRUE; + } /* End if */ + + fprintf(fp_out, "/S%d {\n", subr_id); + fprintf(fp_out, "gsave translate\n"); + + shpos = hpos; /* save our current position */ + svpos = vpos; + + hgoto(0); /* start at the origin */ + vgoto(0); + + in_subr = TRUE; /* in a subroutine definition */ + +} /* End of subr_def */ + +/*****************************************************************************/ + +subr_end() + +{ + + int ch; /* for looking at next opcode */ + +/* + * + * Handles stuff needed at the end of each subroutine. Want to remember the change + * in horizontal and vertical positions for each subroutine so we can adjust our + * position after each call - just in case. The current position was set to (0, 0) + * before we started the subroutine definition, so when we get here hpos and vpos + * are the relative displacements after the subroutine is called. They're saved in + * the displacement[] array and used to adjust the current position when we return + * from a subroutine. + * + */ + + if ( in_subr == FALSE ) /* not in a subroutine definition?? */ + error(FATAL, "subroutine end without corresponding start"); + + fprintf(fp_out, "grestore\n"); + fprintf(fp_out, "} def\n"); + + if ( in_global == TRUE && (ch = get_char()) != BSUB ) { + fprintf(fp_out, "%s", ENDGLOBAL); + fprintf(fp_out, "/saveobj save def\n"); + fprintf(fp_out, "mark\n"); + in_global = FALSE; + } /* End if */ + + ungetc(ch, fp_in); /* put back the next opcode */ + + displacement[subr_id].dx = hpos; + displacement[subr_id].dy = vpos; + + hgoto(shpos); /* back to where we started */ + vgoto(svpos); + + in_subr = FALSE; /* done with the definition */ + +} /* End of subr_end */ + +/*****************************************************************************/ + +subr_call() + +{ + + int ch; /* next byte from *fp_in */ + int id; /* subroutine id if ch wasn't an opcode */ + +/* + * + * Handles subroutine calls. Everything that follows the BCALL opcode (up to the + * next opcode) is taken as a subroutine identifier - thus the loop that generates + * the subroutine calls. + * + */ + + while ( (ch = get_char()) != EOF && (ch & MSB) ) { + id = ch & DMASK; + fprintf(fp_out, "%d %d S%d\n", hpos, vpos, id); + + hgoto(hpos + displacement[id].dx); /* adjust our position */ + vgoto(vpos + displacement[id].dy); + } /* End while */ + + ungetc(ch, fp_in); + +} /* End of subr_call */ + +/*****************************************************************************/ + +vector(var, mode) + + int var; /* coordinate that varies next? */ + int mode; /* VISIBLE or INVISIBLE vectors */ + +{ + + int ch; /* next character from *fp_in */ + int x, y; /* line drawn to this point */ + int count = 0; /* number of points so far */ + +/* + * + * Handles plotting of all types of BGI vectors. If it's a manhattan vector var + * specifies which coordinate will be changed by the next number in the input + * file. + * + */ + + x = hpos; /* set up the first point */ + y = vpos; + + while ( (ch = get_char()) != EOF && ch & MSB ) { + if ( var == X_COORD ) /* next length is change in x */ + x += get_int(ch); + else if ( var == Y_COORD ) /* it's the change in y */ + y += get_int(ch); + else if ( var == LONGVECTOR ) { /* long vector */ + x += get_int(ch); + y += get_int(0); + } else { /* must be a short vector */ + x += ((ch & MSBMAG) * ((ch & SGNB) ? -1 : 1)); + y += (((ch = get_data()) & MSBMAG) * ((ch & SGNB) ? -1 : 1)); + } /* End else */ + + if ( mode == VISIBLE ) { /* draw the line segment */ + fprintf(fp_out, "%d %d\n", hpos - x, vpos - y); + count++; + } /* End if */ + + hgoto(x); /* adjust the current BGI position */ + vgoto(y); + + if ( var == X_COORD ) /* vertical length comes next */ + var = Y_COORD; + else if ( var == Y_COORD ) /* change horizontal next */ + var = X_COORD; + } /* End while */ + + if ( count > 0 ) + fprintf(fp_out, "%d %d v\n", hpos, vpos); + + ungetc(ch, fp_in); /* it wasn't part of the vector */ + position--; + +} /* End of vector */ + +/*****************************************************************************/ + +rectangle(mode) + + int mode; /* FILL or OUTLINE the rectangle */ + +{ + + int deltax; /* displacement for horizontal side */ + int deltay; /* same but for vertical sides */ + +/* + * + * Draws a rectangle and either outlines or fills it, depending on the value of + * mode. Would be clearer, and perhaps better, if {stroke} or {fill} were put on + * the stack instead of 0 or 1. R could then define the path and just do an exec + * to fill or stroke it. + * + */ + + deltax = get_int(0); /* get the height and width */ + deltay = get_int(0); + + if ( mode == OUTLINE ) + fprintf(fp_out, "0 %d %d %d %d R\n", deltax, deltay, hpos, vpos); + else fprintf(fp_out, "1 %d %d %d %d R\n", deltax, deltay, hpos, vpos); + +} /* End of rectangle */ + +/*****************************************************************************/ + +trapezoid() + +{ + + int kind; /* which sides are parallel */ + int d[6]; /* true displacements - depends on kind */ + +/* + * + * Handles filled trapeziods. A data byte of 0101 following the opcode means the + * horizontal sides are parallel, 0102 means the vertical sides are parallel. + * Filling is handled by eofill so we don't need to get things in the right order. + * + */ + + kind = get_data(); + + d[0] = get_int(0); + d[1] = 0; + d[2] = get_int(0); + d[3] = get_int(0); + d[4] = get_int(0); + d[5] = 0; + + if ( kind == 2 ) { /* parallel sides are vertical */ + d[1] = d[0]; + d[0] = 0; + d[5] = d[4]; + d[4] = 0; + } /* End if */ + + fprintf(fp_out, "%d %d %d %d %d %d %d %d T\n", d[4], d[5], d[2], d[3], d[0], d[1], hpos, vpos); + +} /* End of trapezoid */ + +/*****************************************************************************/ + +point_plot(mode, ch) + + int mode; /* plotting mode BPOINT or BPOINT1 */ + int ch; /* will be placed at the points */ + +{ + + int c; /* next character from input file */ + int x, y; /* ch gets put here next */ + int deltax; /* x increment for BPOINT1 mode */ + +/* + * + * The two point plot modes are used to place a character at selected points. The + * difference in the two modes, namely BPOINT and BPOINT1, is the way we get the + * coordinates of the next point. In BPOINT1 the two bytes immediately following + * ch select a constant horizontal change, while both coordinates are given for + * all points in BPOINT mode. + * + */ + + if ( mode == BPOINT1 ) { /* first integer is change in x */ + deltax = get_int(0); + x = hpos - deltax; + } /* End if */ + + while ( (c = get_char()) != EOF && (c & MSB) ) { + if ( mode == BPOINT1 ) { /* only read y coordinate */ + y = get_int(c); + x += deltax; + } else { /* get new x and y from input file */ + x = get_int(c); + y = get_int(0); + } /* End else */ + + hgoto(x); /* adjust BGI position */ + vgoto(y); + + fprintf(fp_out, "%d %d\n", hpos, vpos); + } /* End while */ + + putc('(', fp_out); + + switch ( ch ) { + case '(': + case ')': + case '\\': + putc('\\', fp_out); + + default: + putc(ch, fp_out); + } /* End switch */ + + fprintf(fp_out, ")pp\n"); + + ungetc(c, fp_in); /* it wasn't part of the point plot */ + position--; + +} /* End of point_plot */ + +/*****************************************************************************/ + +line_plot() + +{ + + int c; /* next input character from fp_in */ + int deltax; /* change in x coordinate */ + int x0, y0; /* starting point for next segment */ + int x1, y1; /* endpoint of the line */ + int count = 0; /* number of points so far */ + +/* + * + * Essentially the same format as BPOINT1, except that in this case we connect + * pairs of points by line segments. + * + */ + + deltax = get_int(0); /* again the change in x is first */ + + x1 = hpos; /* so it works first time through */ + y1 = get_int(0); + + while ( (c = get_char()) != EOF && (c & MSB) ) { + x0 = x1; /* line starts here */ + y0 = y1; + + x1 += deltax; /* and ends at this point */ + y1 = get_int(c); + + fprintf(fp_out, "%d %d\n", -deltax, y0 - y1); + count++; + } /* End while */ + + hgoto(x1); /* adjust current BGI position */ + vgoto(y1); + + if ( count > 0 ) + fprintf(fp_out, "%d %d v\n", hpos, vpos); + + ungetc(c, fp_in); /* wasn't part of the line */ + position--; + +} /* End of line_plot */ + +/*****************************************************************************/ + +arc(mode) + + int mode; /* FILL or OUTLINE the path */ + +{ + + int dx1, dy1; /* displacements for first point */ + int dx2, dy2; /* same for the second point */ + int radius; /* of the arc */ + int angle1, angle2; /* starting and ending angles */ + +/* + * + * Called whenever we need to draw an arc. I'm ignoring filled slices for now. + * + */ + + dx1 = get_int(0); /* displacements relative to center */ + dy1 = get_int(0); + dx2 = get_int(0); + dy2 = get_int(0); + + radius = get_int(0); /* and the radius */ + + if ( radius == 0 ) /* nothing to do */ + return; + + angle1 = (atan2((double) dy1, (double) dx1) * 360) / (2 * PI) + .5; + angle2 = (atan2((double) dy2, (double) dx2) * 360) / (2 * PI) + .5; + + fprintf(fp_out, "%d %d %d %d %d arcn stroke\n", hpos, vpos, radius, angle1, angle2); + +} /* End of arc */ + +/*****************************************************************************/ + +pattern() + +{ + + double red = 0; /* color components */ + double green = 0; + double blue = 0; + int kind; /* corse or fine pattern */ + int val; /* next color data byte */ + int i; /* loop index */ + +/* + * + * Handles patterns by setting the current color based of the values assigned to + * the next four data bytes. BGI supports two kinds of patterns (fine or coarse) + * but I'm handling each in the same way - for now. In a fine pattern the four + * data bytes assign a color to four individual pixels (upperleft first) while + * in a coarse pattern the four colors are assigned to groups of four pixels, + * for a total of 16. Again the first color goes to the group in the upper left + * corner. The byte immediately following the BPAT opcode selects fine (040) or + * coarse (041) patterns. The PostScript RGB color is assigned by averaging the + * RED, GREEN, and BLUE components assigned to the four pixels (or groups of + * pixels). Acceptable results, but there's no distinction between fine and + * coarse patterns. + * + */ + + if ( (kind = get_char()) == EOF ) + error(FATAL, "bad pattern command"); + + for ( i = 0; i < 4; i++ ) { + val = get_data(); + red += get_color(val, RED); + green += get_color(val, GREEN); + blue += get_color(val, BLUE); + } /* End for */ + + fprintf(fp_out, "%g %g %g c\n", red/4, green/4, blue/4); + +} /* End of pattern */ + +/*****************************************************************************/ + +get_color(val, component) + + int val; /* color data byte */ + int component; /* RED, GREEN, or BLUE component */ + +{ + + + int primary; /* color mixing mode - bits 2 to 4 */ + int plane; /* primary color plane - bits 5 to 7 */ + unsigned rgbcolor; /* PostScript expects an RGB triple */ + +/* + * + * Picks the requested color component (RED, GREEN, or BLUE) from val and returns + * the result to the caller. BGI works with Cyan, Yellow, and Magenta so the one's + * complement stuff (following the exclusive or'ing) recovers the RED, BLUE, and + * GREEN components that PostScript's setrgbcolor operator needs. The PostScript + * interpreter in the ColorScript 100 has a setcmycolor operator, but it's not + * generally available so I've decided to stick with setrgbcolor. + * + */ + + primary = (val >> 3) & 07; + plane = val & 07; + rgbcolor = (~(primary ^ plane)) & 07; + + if ( debug == ON ) + fprintf(stderr, "val = %o, primary = %o, plane = %o, rgbcolor = %o\n", + val, primary, plane, rgbcolor); + + switch ( component ) { + case RED: + return(rgbcolor>>2); + + case GREEN: + return(rgbcolor&01); + + case BLUE: + return((rgbcolor>>1)&01); + + default: + error(FATAL, "unknown color component"); + return(0); + } /* End switch */ + +} /* End of get_color */ + +/*****************************************************************************/ + +set_color(val) + + int val; /* color data byte */ + +{ + +/* + * + * Arranges to have the color set to the value requested in the BGI data byte val. + * + */ + + fprintf(fp_out, "%d %d %d c\n", get_color(val, RED), get_color(val, GREEN), get_color(val, BLUE)); + +} /* End of set_color */ + +/*****************************************************************************/ + +get_int(highbyte) + + int highbyte; /* already read this byte */ + +{ + + int lowbyte; /* this and highbyte make the int */ + +/* + * + * Figures out the value on the integer (sign magnitude form) that's next in the + * input file. If highbyte is nonzero we'll use it and the next byte to build the + * integer, otherwise two bytes are read from fp_in. + * + */ + + + if ( highbyte == 0 ) /* need to read the first byte */ + highbyte = get_data(); + + lowbyte = get_data(); /* always need the second byte */ + + return(highbyte & SGNB ? -MAG(highbyte, lowbyte) : MAG(highbyte, lowbyte)); + +} /* End of get_int */ + +/*****************************************************************************/ + +get_data() + +{ + + int val; /* data value returned to caller */ + +/* + * + * Called when we expect to find a single data character in the input file. The + * data bit is turned off and the resulting value is returned to the caller. + * + */ + + if ( (val = get_char()) == EOF || ! (val & MSB) ) + error(FATAL, "missing data value"); + + return(val & DMASK); + +} /* End of get_data */ + +/*****************************************************************************/ + +get_char() + +{ + + int ch; /* character we just read */ + +/* + * + * Reads the next character from file *fp_in and returns the value to the caller. + * This routine isn't really needed, but we may want to deal directly with some + * screwball file formats so I thought it would probably be a good idea to isolate + * all the input in one routine that could be easily changed. + * + */ + + if ( (ch = getc(fp_in)) != EOF ) { + position++; + ch &= CHMASK; + } /* End if */ + + if ( debug == ON ) + fprintf(stderr, "%o ", ch); + + return(ch); + +} /* End of get_char */ + +/*****************************************************************************/ + +redirect(pg) + + int pg; /* next page we're printing */ + +{ + + static FILE *fp_null = NULL; /* if output is turned off */ + +/* + * + * If we're not supposed to print page pg, fp_out will be directed to /dev/null, + * otherwise output goes to stdout. + * + */ + + if ( pg >= 0 && in_olist(pg) == ON ) + fp_out = stdout; + else if ( (fp_out = fp_null) == NULL ) + fp_out = fp_null = fopen("/dev/null", "w"); + +} /* End of redirect */ + +/*****************************************************************************/ + diff --git a/sys/src/cmd/postscript/postbgi/postbgi.h b/sys/src/cmd/postscript/postbgi/postbgi.h new file mode 100755 index 000000000..41e3003c1 --- /dev/null +++ b/sys/src/cmd/postscript/postbgi/postbgi.h @@ -0,0 +1,203 @@ +/* + * + * BGI opcodes. + * + */ + +#define BRCHAR 033 /* rotated character mode */ +#define BCHAR 034 /* graphical character mode */ +#define BGRAPH 035 /* graphical master mode */ + +#define BSUB 042 /* subroutine definition */ +#define BRET 043 /* end of subroutine */ +#define BCALL 044 /* subroutine call */ + +#define BEND 045 /* end page */ +#define BERASE 046 /* erase - obsolete */ +#define BREP 047 /* repeat */ +#define BENDR 050 /* end repeat */ + +#define BSETX 051 /* set horizontal position */ +#define BSETY 052 /* set vertical position */ +#define BSETXY 053 /* set horizontal and vertical positions */ +#define BINTEN 054 /* intensify - mark current pixel */ + +#define BVISX 055 /* manhattan vector - change x first */ +#define BINVISX 056 /* same as BVISX but nothing drawn */ +#define BVISY 057 /* manhattan vector - change y first */ +#define BINVISY 060 /* same as BVISY but nothing drawn */ + +#define BVEC 061 /* arbitrary long vector */ +#define BSVEC 062 /* arbitrary short vector */ +#define BRECT 063 /* outline rectangle */ +#define BPOINT1 064 /* point plot - mode 1 */ +#define BPOINT 065 /* point plot - mode 2 */ +#define BLINE 066 /* line plot */ + +#define BCSZ 067 /* set character size */ +#define BLTY 070 /* select line type */ +#define BARC 071 /* draw circular arc */ +#define BFARC 072 /* filled circular arc */ +#define BFRECT 073 /* filled rectangle */ +#define BRASRECT 074 /* raster rectangle */ +#define BCOL 075 /* select color */ +#define BFTRAPH 076 /* filled trapezoid */ +#define BPAT 077 /* pattern are for filling - no info */ + +#define BNOISE 0 /* from bad file format */ + +/* + * + * Character size is controlled by the spacing of dots in a 5x7 dot matrix, which + * by default is set to BGISIZE. + * + */ + +#define BGISIZE 2 /* default character grid spacing */ + +/* + * + * Definitions used to decode the bytes read from a BGI file. + * + */ + +#define CHMASK 0177 /* characters only use 7 bits */ +#define DMASK 077 /* data values use lower 6 bits */ +#define MSB 0100 /* used to check for data or opcode */ +#define SGNB 040 /* sign bit for integers */ +#define MSBMAG 037 /* mag of most sig byte in a BGI int */ + +/* + * + * Descriptions of BGI vectors and what's done when they're drawn. + * + */ + +#define X_COORD 0 /* change x next in manhattan vector */ +#define Y_COORD 1 /* same but y change comes next */ +#define LONGVECTOR 2 /* arbitrary long vector */ +#define SHORTVECTOR 3 /* components given in 6 bits */ + +#define VISIBLE 0 /* really draw the vector */ +#define INVISIBLE 1 /* just move the current position */ + +/* + * + * What's done with a closed path. + * + */ + +#define OUTLINE 0 /* outline the defined path */ +#define FILL 1 /* fill it in */ + +/* + * + * BGI line style definitions. They're used as an index into the STYLES array, + * which really belongs in the prologue. + * + */ + +#define SOLID 0 +#define DOTTED 1 +#define SHORTDASH 2 +#define DASH 3 +#define LONGDASH 4 +#define DOTDASH 5 +#define THREEDOT 6 + +#define STYLES \ + \ + { \ + "[]", \ + "[.5 2]", \ + "[2 4]", \ + "[4 4]", \ + "[8 4]", \ + "[.5 2 4 2]", \ + "[.5 2 .5 2 .5 2 4 2]" \ + } + +/* + * + * Three constants used to choose which component (RED, GREEN, or BLUE) we're + * interested in. BGI colors are specified as a single data byte and pulling a + * particular component out of the BGI color byte is handled by procedure + * get_color(). + * + */ + +#define RED 0 +#define GREEN 1 +#define BLUE 2 + +/* + * + * An array of type Disp is used to save the horizontal and vertical displacements + * that result after a subroutine has been called. Needed so we can properly adjust + * our horizontal and vertical positions after a subroutine call. Entries are made + * immediately after a subroutine is defined and used after the call. Subroutine + * names are integers that range from 0 to 63 (assigned in the BG file) and the + * name is used as an index into the Disp array when we save or retrieve the + * displacement. + * + */ + +typedef struct { + int dx; /* horizontal and */ + int dy; /* vertical displacements */ +} Disp; + +/* + * + * An array of type Fontmap helps convert font names requested by users into + * legitimate PostScript names. The array is initialized using FONTMAP, which must + * end with and entry that has NULL defined as its name field. + * + */ + +typedef struct { + char *name; /* user's font name */ + char *val; /* corresponding PostScript name */ +} Fontmap; + +#define FONTMAP \ + \ + { \ + "R", "Courier", \ + "I", "Courier-Oblique", \ + "B", "Courier-Bold", \ + "CO", "Courier", \ + "CI", "Courier-Oblique", \ + "CB", "Courier-Bold", \ + "CW", "Courier", \ + "PO", "Courier", \ + "courier", "Courier", \ + "cour", "Courier", \ + "co", "Courier", \ + NULL, NULL \ + } + +/* + * + * Two macros that are useful in processing BGI files: + * + * MAG(A, B) - Takes bytes A and B which have been read from a BGI file + * and returns the magnitude of the integer represented by + * the two bytes. + * + * LINESPACE(A) - Takes BGI size A and returns the number of address units + * that can be used for a reasonable interline spacing. + * + */ + +#define MAG(A, B) (((A & MSBMAG) << 6) | (B & DMASK)) +#define LINESPACE(A) (8 * A) + +/* + * + * Some of the non-integer valued functions in postdmd.c. + * + */ + +char *get_font(); + diff --git a/sys/src/cmd/postscript/postbgi/postbgi.mk b/sys/src/cmd/postscript/postbgi/postbgi.mk new file mode 100755 index 000000000..24ad6b27d --- /dev/null +++ b/sys/src/cmd/postscript/postbgi/postbgi.mk @@ -0,0 +1,93 @@ +MAKE=/bin/make +MAKEFILE=postbgi.mk + +SYSTEM=V9 +VERSION=3.3.2 + +GROUP=bin +OWNER=bin + +MAN1DIR=/tmp +POSTBIN=/usr/bin/postscript +POSTLIB=/usr/lib/postscript + +COMMONDIR=../common + +CFLGS=-O +LDFLGS=-s + +CFLAGS=$(CFLGS) -I$(COMMONDIR) +LDFLAGS=$(LDFLGS) + +HFILES=postbgi.h\ + $(COMMONDIR)/comments.h\ + $(COMMONDIR)/ext.h\ + $(COMMONDIR)/gen.h\ + $(COMMONDIR)/path.h + +OFILES=postbgi.o\ + $(COMMONDIR)/glob.o\ + $(COMMONDIR)/misc.o\ + $(COMMONDIR)/request.o + +all : postbgi + +install : all + @if [ ! -d "$(POSTBIN)" ]; then \ + mkdir $(POSTBIN); \ + chmod 755 $(POSTBIN); \ + chgrp $(GROUP) $(POSTBIN); \ + chown $(OWNER) $(POSTBIN); \ + fi + @if [ ! -d "$(POSTLIB)" ]; then \ + mkdir $(POSTLIB); \ + chmod 755 $(POSTLIB); \ + chgrp $(GROUP) $(POSTLIB); \ + chown $(OWNER) $(POSTLIB); \ + fi + cp postbgi $(POSTBIN)/postbgi + @chmod 755 $(POSTBIN)/postbgi + @chgrp $(GROUP) $(POSTBIN)/postbgi + @chown $(OWNER) $(POSTBIN)/postbgi + cp postbgi.ps $(POSTLIB)/postbgi.ps + @chmod 644 $(POSTLIB)/postbgi.ps + @chgrp $(GROUP) $(POSTLIB)/postbgi.ps + @chown $(OWNER) $(POSTLIB)/postbgi.ps + cp postbgi.1 $(MAN1DIR)/postbgi.1 + @chmod 644 $(MAN1DIR)/postbgi.1 + @chgrp $(GROUP) $(MAN1DIR)/postbgi.1 + @chown $(OWNER) $(MAN1DIR)/postbgi.1 + +clean : + rm -f *.o + +clobber : clean + rm -f postbgi + +postbgi : $(OFILES) + $(CC) $(CFLAGS) $(LDFLAGS) -o postbgi $(OFILES) -lm + +postbgi.o : $(HFILES) + +$(COMMONDIR)/glob.o\ +$(COMMONDIR)/misc.o\ +$(COMMONDIR)/request.o : + @cd $(COMMONDIR); $(MAKE) -f common.mk `basename $@` + +changes : + @trap "" 1 2 3 15; \ + sed \ + -e "s'^SYSTEM=.*'SYSTEM=$(SYSTEM)'" \ + -e "s'^VERSION=.*'VERSION=$(VERSION)'" \ + -e "s'^GROUP=.*'GROUP=$(GROUP)'" \ + -e "s'^OWNER=.*'OWNER=$(OWNER)'" \ + -e "s'^MAN1DIR=.*'MAN1DIR=$(MAN1DIR)'" \ + -e "s'^POSTBIN=.*'POSTBIN=$(POSTBIN)'" \ + -e "s'^POSTLIB=.*'POSTLIB=$(POSTLIB)'" \ + $(MAKEFILE) >XXX.mk; \ + mv XXX.mk $(MAKEFILE); \ + sed \ + -e "s'^.ds dQ.*'.ds dQ $(POSTLIB)'" \ + postbgi.1 >XXX.1; \ + mv XXX.1 postbgi.1 + diff --git a/sys/src/cmd/postscript/postbgi/postbgi.ps b/sys/src/cmd/postscript/postbgi/postbgi.ps new file mode 100755 index 000000000..1fa486f2a --- /dev/null +++ b/sys/src/cmd/postscript/postbgi/postbgi.ps @@ -0,0 +1,135 @@ +% +% Version 3.3.2 prologue for BGI files - STARE or PRISM. +% + +/#copies 1 store +/aspectratio 1 def +/fixlinewidth true def +/fixscreen false def +/font /Courier def +/formsperpage 1 def +/landscape false def +/linewidth 0 def +/magnification 1 def +/margin 0 def +/orientation 0 def +/prism false def +/resolution 128 def +/rotation 1 def +/scaletodevice false def +/screenheight 1280 def +/screenwidth 1024 def +/xoffset 0 def +/yoffset 0 def + +/devres 72 0 matrix defaultmatrix dtransform dup mul exch dup mul add sqrt def + +/useclippath true def +/pagebbox [0 0 612 792] def + +/inch {72 mul} bind def +/min {2 copy gt {exch} if pop} bind def + +/kshow {kshow} bind def % so later references don't bind +/show {show} bind def + +/setup { + counttomark 2 idiv {def} repeat pop + + landscape {/orientation 90 orientation add def} if + prism {/fixscreen true def /scaletodevice true def} if + prism linewidth 0 eq and {/linewidth .3 def} if + fixscreen {devres 4 div orientation currentscreen 3 1 roll pop pop setscreen} if + + pagedimensions + /scaling + scaletodevice + {devres resolution div truncate 72 mul devres div dup} + {height margin sub screenheight div width margin sub screenwidth div} + ifelse + min def + xcenter ycenter translate + orientation rotation mul rotate + xoffset inch yoffset inch translate + magnification dup aspectratio mul scale + scaling scaling scale + screenwidth 2 div neg screenheight 2 div neg translate + + tietodevicespace + linewidth scaling div setlinewidth + 1 setlinecap + newpath +} def + +/pagedimensions { + useclippath { + /pagebbox [clippath pathbbox newpath] def + } if + pagebbox aload pop + 4 -1 roll exch 4 1 roll 4 copy + landscape {4 2 roll} if + sub /width exch def + sub /height exch def + add 2 div /xcenter exch def + add 2 div /ycenter exch def + userdict /gotpagebbox true put +} def + +/pagesetup {/page exch def} bind def + +/tietodevicespace { + fixlinewidth linewidth 0 gt and linewidth 1 lt and { + /moveto { + 2 copy /Y exch def /X exch def + transform round exch round exch itransform + moveto + } bind def + /lineto { + 2 copy /Y exch def /X exch def + transform round exch round exch itransform + lineto + } bind def + /rlineto {Y add exch X add exch lineto} bind def + /v V 0 get bind def + } if +} def + +/V [{moveto counttomark 2 idiv {rlineto} repeat stroke}] def +/v V 0 get bind def +/p {linewidth 2 div 0 360 arc fill} bind def +/pp {/ch exch def counttomark 2 idiv {moveto xc yc rmoveto ch show} repeat} bind def + +/l {{scaling div} forall counttomark array astore 0 setdash} bind def +/c {setrgbcolor} bind def + +/T {newpath moveto rlineto rlineto rlineto closepath eofill} bind def + +/R { + newpath moveto 1 index 0 rlineto 0 exch rlineto neg 0 rlineto closepath + 0 eq {stroke} {eofill} ifelse +} bind def + +/f { + dup dup + /charwidth exch 6 mul def + /xc exch -2.5 mul def + /yc exch -3.5 mul def + font findfont charwidth .6 div scalefont setfont +} bind def + +/t { + /str exch def + gsave + translate rotate + xc yc moveto + currentpoint + { + pop pop + exch charwidth add exch + moveto currentpoint + } str kshow + pop pop + grestore +} bind def + +/done {/lastpage where {pop lastpage} if} def |