/* * 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,16,25) 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!! * * Changes by Corey Satten, corey @ cac.washington.edu: * - 16,25-up additions * - showpage enhancements to work if showpage was already re-defined * - tmpfile removal * - work around for illegal (but common) initial coordinate transformation * in otherwise conforming PostScript Prolog. */ #include #include #include #include /* * 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; 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 */ int Lax = 0; /* x flag relaxes strict Conforming PS requirements */ #ifndef MaxP #define MaxP 4096 /* maximum number of input pages */ #endif #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; int TrailerSeen=0; int ExpectedPageNo = 1; 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,9,16 or 25 (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"); error(" -x Lax enforcement of conforming PS standards"); 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': if (*_argp == '6') ++_argp, N_up = 16; else N_up = 1; Case '2': if (*_argp == '5') ++_argp, N_up = 25; else Rotate = 1, N_up = 2; 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 */ Case 'x': Lax = 1; Default : use(); } 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); } CopyInputAndExit(f) /* called if no pages were counted in input */ FILE *f; { int c; rewind(f); if (getc(f) != '%' || getc(f) != '!') { if (tmpfilename) unlink(tmpfilename); exit(1); } putchar('%'); putchar('!'); while ((c=getc(f))!=EOF) putchar(c); if (tmpfilename) unlink(tmpfilename); exit(1); }