/* * quarto.c * Quickie program to filter PostScript (EPS) files and... * - list the pages * ... | quarto -l ... * - extract selected pages * ... | quarto -p1,2,6-8 ... * - change page order (reverse, even, odd; etc) * ... | quarto -r ... print in reverse order * ... | quarto -p odd ... select the odd pages * - print "N-up" (quarto/octavo; N=2,3,4,6,8,9) layouts * ... | quarto -4 -c -b ... print 4 pages per page * * Currently only tested and used with a NeXT printer + A4 (letter) paper, * with input in portrait orientation. It should be easy to fix for * other media; check PBox, the test pattern, the calculation of 'Scale', * and the macro 'pgx()' (used by the 'putNup()' routines). * * Enjoy at your own peril, but please send me any improvements. * * M. J. Hawley * MIT media Laboratory * 20 Ames Street * Cambridge, MA 02139 * mike@media-lab.mit.edu * Copyright (c) MIT Media Laboratory 1991. * Burn before reading! This means you!! */ #include #include #include #define index strchr /*int index(char *s, char ch) { return (strchr(s,ch)?strchr(s,ch)-s+1:0); } */ /* * Some general utilities ---------------------------------------- */ char *av0; #define Case break; case #define Default break; default static char *_arg, *_argp; /* use by 'for_each_argument */ extern char *av0; /* will hold name of the command */ #define argument (_arg=(*_argp? _argp : av[++i==ac? --i: i]),_argp+=strlen(_argp),_arg) #define for_each_argument av0 = av[0]; for (i=1;is && (*p=='\n' || *p == ' ')) *p-- = '\0'; } char * skipsp(s) char *s; { while (*s==' ' || *s=='\t' || *s == '\n') ++s; return s; } error(a,b,c,d,e,f) int a,b,c,d,e,f; { /* printf an error msg */ fprintf(stderr,(char *)a,b,c,d,e,f); fprintf(stderr,"\n"); } /* ---------------------------------------------------------------- */ FILE *Input, *Output; char *CurFile; typedef struct { float x, y; } Point; typedef struct { Point o, c; } Rectangle; #define HS(r) (r.c.x-r.o.x) #define VS(r) (r.c.y-r.o.y) Rectangle BBox = { 0, 0, 612, 792 }; /* bbox of the document */ Rectangle PBox = { 10, 14, 600, 780 }; /* Letter-sized page-bounding box */ /* These values probably depend on the printer and * paper size; use the test pattern to adjust them for now. */ Rectangle NullRect = {0,0,0,0}; int TestPattern = 0; /* if true, overlay a test pattern on the page*/ int ListPages = 0; /* if true, list pages in the document (no print) */ #define _N_up 1 int N_up = 1; /* default # pages to fit on a sheet */ #define _Gutter 12. float Gutter= _Gutter; #define _CutMarks 0 #define _Borders 1 int CutMarks=_CutMarks, /* print cutmarks around shrunken pages */ Borders=_Borders; /* print dashed borders around shrunken pages */ int ReversePages = 0; float Scale = .45; /* Scale is normally set by the tiling routines; */ int ScaleSet = 0; /* made a user option just in case. */ int Rotate = 0; /* will be true when landscaping for -2,6,8 */ #define MaxP 1024 #define Trailer (MaxP-1) int Page[MaxP], PageLen[MaxP]; Rectangle PageBbox[MaxP], pageBbox; int NP=0; findPageOffsets() { char s[4192]; int i,prevpos=0,prevp=0,p; FILE *f = Input; for(i=0;i0) write(O,b,n); fclose(o); return 1; } else return 0; } use(){ error("use: %s [-[234689]] [-p ] [-bcdlr] [-g #] [PS file]",av0); error("Select pages from a PostScript file, and print in a tiled format."); error("(The input must contain EPS-like directives '%%%%Page:...')"); error(" -p... print the given pages; e.g., '-p1,2,4-8,12-'"); error(" '-p -4' prints through page four;"); error(" '-p 12-' prints from page 12 through the end;"); error(" numbers are original ordinal page numbers, starting at 1"); error(" also, '-p even', '-p odd', '-p1-4,1-4,1-4,1-4' etc."); error(" -2 print 2 tiled, shrunken pages per page;"); error(" # may be 2,3,4,6,8 or 9 (default 1);"); error(" portrait or landscape layout will be chosen accordingly."); error(" -b %sprint borders around each tiled page.", _Borders?"don't ":""); error(" -c %sprint cut-marks for each tiled page.", _CutMarks?"don't ":""); error(" -d overlay a test pattern on the page."); error(" (a box around the paper sheet border, "); error(" and a circle and cross in the middle;"); error(" intended to help calibrate for different printers)"); error(" -g # set the gap between tiles to # (%3f)",_Gutter); error(" -l list the pages+offsets (don't output any PostScript)."); error(" -r reverse the page order"); exit(1); } main(ac,av) char *av[]; { int i; for_each_argument { Case 'l': ListPages = 1; Case 'p': SelectPages = argument; Case 'r': ReversePages = 1; Case 'd': TestPattern = !TestPattern; Case 'c': CutMarks = !CutMarks; Case 'b': Borders = !Borders; Case '1': N_up = 1; Case '2': N_up = 2; Rotate = 1; Case '3': N_up = 3; Rotate = 1; Case '4': N_up = 4; Case '6': N_up = 6; Rotate = 1; Case '8': N_up = 8; Rotate = 1; Case '9': N_up = 9; Case 'g': Gutter = atof(argument); Case 's': Scale = atof(argument); ScaleSet++; /* not mentioned as option */ Default : use(); } Output = stdout; if (i==ac){ char s[1024]; if (savetmp(s,stdin)) CurFile="stdin", doFile(s), unlink(s); else error("%s: couldn't save stdin to a tmp file.",av0), exit(1); } else if ((i+1)==ac) CurFile=av[i], doFile(av[i++]); else error("%s: accepts only one file, or stdin...\n",av0), use(); exit(0); }