🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Thread View: comp.lang.postscript
1 messages
1 total messages Started by Michael Hawley Mon, 16 Nov 1992 02:31
quarto
#5672
Author: Michael Hawley
Date: Mon, 16 Nov 1992 02:31
896 lines
26310 bytes
There have been a few more requests for an "N-up" program
(that works with embedded EPS illustrations)
ways of listing pages, printing booklets in signatures, etc.
Here's a simple one I use on the NeXT (known to work on other
Unix machines).
    quarto -l your-dissertation.ps
lists the pages, and
    quarto -2 your-nobel-prize-acceptance-speech.ps | lpr
prints 2 pages per sheet.
    quarto -8 ... | quarto -3 | ...
prints 8*3 = 24 little pages per sheet, if that's really what you want.

- - - -
/*
 * quarto.c
 *
 * Quickie program to filter PostScript (EPS) files and...
 *   - extract selected pages
 *         ... | quarto -p1,2,6-8 ...    print those pages
 *   - 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 (small) pages per side
 *
 * For printing books or booklets in signatures, e.g.,
 *   quarto -2 -S 4 ...
 * means that a signature is 4 sheets, 2 (small) pages per side.
 * The page ordering is such that you can run them through a copier
 * printing 2 pages onto 1 double-sided page (or take every other sheet,
 * flip it over, and glue it back to back on the previous sheet).
 *
 * Currently only tested and used with a NeXT printer + Letter-size  
paper,
 * with input in portrait orientation.  It should be easy to fix for
 * other varieties; check PBox, the test pattern, the calculation of  
'Scale',
 * and the macro 'pgx()' (used by the 'putNup()' routines).  If you can
 * print out test patterns (the "-d" option) you're close if not  
working.
 *
 * Enjoy at your own peril, but please send me any improvements.
 *
 * Also, if you like this program and get good use out of it, consider
 * sending $4.37 to:
 *    Bob Greene
 *    Media Lab Crew Treasurer
 *    MIT Media Lab
 *    20 Ames Street
 *    Cambridge, MA 02139
 * 
 *    Say "Yo Bob!  I'm dying to find out how your boys did at Henley.
 *         Did they really row in the nude because you are too poor
 *         to buy uniforms?  Perhaps this miserly contribution will  
help."
 *
 *
 * M. J. Hawley
 * MIT media Laboratory
 * 20 Ames Street
 * Cambridge, MA 02139
 * mike@media-lab.mit.edu
 * Copyright (c) MIT Media Laboratory 1991.
 * Top secret!  Burn before reading!  This means you!!
 *
 *
 * Notes -- version 1.1
 *
 * - added signature printing and fixed the nested-page bug (November,  
1992)
 */
#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>

/*
 * 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;i<ac &&  
*av[i]=='-';i++)\
                        for (_argp = &av[i][1]; *_argp;)\
                                switch(*_argp++)

extern char *malloc(), *index();
extern int atoi();
extern double atof();

stripnl(s) char *s; { /* remove trailing \n and space from 's' */
    char *p = s + strlen(s)-1;
    while (p>s && (*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;
int Signatures = 0;	/* determine signature page order */

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], *s2=s+2;
    int i,prevpos=0,prevp=0,p,nested=0;
    FILE *f = Input;

    for(i=0;i<MaxP;i++){
        Page[i]=PageLen[i]=0;
        PageBbox[i] = NullRect;
    }

    rewind(f);
    while (fgets(s,sizeof s,f)){
     if (s[0]=='%' && s[1]=='%'){
      if (strncmp(s2,"BeginDocument",13)==0 ||
          strncmp(s2,"BeginBinary",11)==0){
            nested++;
      } else
      if (strncmp(s2,"EndDocument",11)==0 ||
          strncmp(s2,"EndBinary",9)==0){
            if (nested>0) nested--;
      } else
      if (nested==0){
        if (strncmp(s2,"Page:",5)==0){
            sscanf(s,"%%%%Page: %*s %d",&p);
            Page[p] = ftell(f)-strlen(s);
            PageLen[prevp] = Page[p] - prevpos;
            prevp = p;
            prevpos = Page[p];
            NP++;
        } else
        if (strncmp(s2,"Trailer",7)==0){
            Page[Trailer] = ftell(f)-strlen(s);
            PageLen[prevp] = Page[Trailer] - prevpos;
            prevpos = Page[Trailer];
        } else
        if (strncmp(s2,"BoundingBox:",12)==0){
            char *q = skipsp(index(s,':')+1);
            if (isdigit(*q))
                sscanf(q,"%f %f %f %f",
                         &BBox.o.x,&BBox.o.y,&BBox.c.x,&BBox.c.y);
        } else
        if (strncmp(s2,"PageBoundingBox:",16)==0){
            Rectangle r;
            char *q = skipsp(index(s,':')+1);
            if (isdigit(*q)){
                sscanf(q,"%f %f %f %f", &r.o.x,&r.o.y,&r.c.x,&r.c.y);
                if (NP) PageBbox[NP] = r;
            }
        }
      }
     }
    }
    PageLen[Trailer] = ftell(f) - prevpos;
    pageBbox = PageBbox[1]; /* hack ... */
        /*
         * Some NeXT programs put out PageBoundingBoxes
         * with various origins for each page,
         * but draw relative to the *first* PageBoundingBox.
         * See "hack", below.
         */
}

showPageOffsets() {
    char s[4192];
    int i,j;
    FILE *f = Input;

    printf("file: %s, %d pages\n",CurFile,NP);
    printf("%8s %8s\n","offset","length");
    for (i=j=0;j<=NP;i++){
        if (Page[i] || i==0){
            fseek(f,Page[i],0);
            fgets(s,sizeof s,f);
            printf("%8d %8d -- %s%s",Page[i], PageLen[i],i?"":"(header)  
",s);
            j++;
        }
    }
    fseek(f,Page[Trailer],0);
    fgets(s,sizeof s,f);
    printf("%8d %8d -- (trailer) %s",Page[Trailer],PageLen[Trailer],s);
}

static char *_s = (char *)0;
static int _sn = 0;

char *
readPage(n){
    size_t r;
    if (_s) *_s = '\0';
    if (Page[n] || (n==0 && PageLen[n])){
        if (_sn < PageLen[n]){
            _sn = 2*PageLen[n];
            _s = (_s? (char *)realloc(_s,_sn) : (char *)malloc(_sn));
            if (!_s) error("%s: no memory!",av0), exit(1);
        }
        rewind(Input);
        fseek(Input,Page[n],0);
        *_s = '\0';
        fread(_s,PageLen[n], (size_t)1, Input);
    }
    return _s;
}

copyPage(n)
/*
 * Write the 'n'th page in 'f' onto 'o'.
 */
{
    char *s = readPage(n);
    if (*s) fwrite(s,PageLen[n],1,Output);
}

P(a,b,c,d,e,f,g,h,i){
    fprintf(Output,(char *)a,b,c,d,e,f,g,h,i);
    fprintf(Output,"\n");
}

putProlog(n){
    char *date, *ctime();
    time_t t;

    time(&t); date = ctime(&t); stripnl(date);
    P("%%!PS-Adobe-2.0");
    P("%%%%Creator: %s, file: %s",av0,CurFile);
    P("%%%%CreationDate: %s",date);
    P("%%%%Pages: (atend)",n);
    P("%%%%BoundingBox: 0 0 612 792");  /* should have options to set */
    P("%%%%EndComments");
    P("");
    P("%% ---------------------- (routines for \"%s\")",av0);
    P("/q_W %f def  /q_H %f def  /q_margin 4 def",BBox.c.x,BBox.c.y);
    P("/q_factor %f def",Scale);
    P("/q_bbox {");
    if (Borders){
	P("    /q_y 0 q_factor mul def");
	P("    /q_x 0 q_factor mul def");
	P("    /q_w q_W q_margin 2 mul add def");
	P("    /q_h q_H q_margin 2 mul add def");
	P("    q_x q_margin sub q_y q_margin sub moveto");
	P("    .2 setgray");
	P("    0 setlinewidth");
	P("    q_w 0 rlineto");
	P("    0 q_h rlineto");
	P("    0 q_w sub 0 rlineto");
	P("    0 0 q_h sub rlineto");
	P("    stroke");
    }
    P("} def");
    P("");
    P("/q_cuts {");
    if (CutMarks){
	P("    /q_y 0 q_factor mul q_margin sub def");
	P("    /q_x 0 q_factor mul q_margin sub def");
	P("    /q_w q_W q_margin 2 mul add def");
	P("    /q_h q_H q_margin 2 mul add def");
	P("    /q_d 10 q_factor mul def");
	P("    0 setgray");
	P("    0 setlinewidth");
	P("    q_x q_d sub q_y moveto -1 -1 rmoveto");
	P("        q_d 0 rlineto 0 0 q_d sub rlineto stroke");
	P("    q_x q_d add q_w add q_y moveto 1 -1 rmoveto");
	P("        0 q_d sub 0 rlineto 0 0 q_d sub rlineto stroke");
	P("    q_x q_d add q_w add q_y q_h add moveto 1 1 rmoveto");
	P("        0 q_d sub 0 rlineto 0 q_d rlineto stroke");
	P("    q_x q_d sub q_y q_h add moveto -1 1 rmoveto");
	P("        q_d 0 rlineto 0 0 q_d rlineto stroke");
    }
    P("} def");
    P("");
    P("/StartShrunkenPage {");
    P("    /q_y exch def /q_x exch def");
    P("    gsave");
    P("    q_x q_y translate");
    P("    q_factor q_factor scale");
    if (Rotate) P("    -90 rotate");
    P("} def");
    P("");
    P("/EndShrunkenPage {");
    P("    grestore");
    P("} def");
    P("");
    if (N_up!=1){
       P("/oldshowpage {showpage} bind def");
       P("/showpage { } bind def");
    }
    P("");
    P("/q_circ { %% x y size ... draw circle + crosshairs");
    P("    /q_size exch def /q_y exch def /q_x exch def");
    P("    0 setlinewidth");
    P("    q_x q_y moveto");
    P("    q_size 0 rlineto");
    P("    -2 q_size mul 0 rlineto");
    P("    q_size 0 rlineto");
    P("    0 q_size rlineto");
    P("    0 -2 q_size mul rlineto");
    P("    stroke");
    P("    q_x q_y moveto");
    P("    q_x q_y q_size 2 div 0 360 arc stroke");
    P("} def");
    P("");
    P("/q_box { %% lx ly ux uy ... draw a box");
    P("    /q_uy exch def /q_ux exch def /q_ly exch def /q_lx exch  
def");
    P("    q_lx q_ly moveto");
    P("    q_ux q_ly lineto");
    P("    q_ux q_uy lineto");
    P("    q_lx q_uy lineto");
    P("    q_lx q_ly lineto");
    P("    stroke");
    P("} def");
    P("");
    P("/q_testPattern {");
    P("    0 setgray 0 setlinewidth");
    P("    %f %f %f %f q_box", PBox.o.x,PBox.o.y,PBox.c.x,PBox.c.y);
    P("    %f %f moveto 8 0 rlineto stroke",  
PBox.o.x-4,VS(PBox)/2+PBox.o.y);
    P("    %f %f moveto -8 0 rlineto stroke",  
PBox.c.x+4,VS(PBox)/2+PBox.o.y);
    P("    %f %f moveto 0 8 rlineto stroke",  
HS(PBox)/2+PBox.o.x,PBox.o.y-4);
    P("    %f %f moveto 0 -8 rlineto stroke",  
HS(PBox)/2+PBox.o.x,PBox.c.y+4);
    P("    %f %f 5 q_circ",HS(PBox)/2+PBox.o.x,VS(PBox)/2+PBox.o.y);
    P("} def");
    P("");
    P("%% ----------------------(end of \"%s\" routines)\n",av0);
    copyPage(0);  /* put out the previous document header page */
}

ShowPage(){
    if (TestPattern) P("q_testPattern");
    P("q_sheet restore\noldshowpage");
}

putTrailer(n){
    copyPage(Trailer);
    P("%%%%Pages: %d %d",n,n);
}

static Point
center(r) Rectangle r; {
    Point c;
    c.x = HS(r)/2. + r.o.x;
    c.y = VS(r)/2. + r.o.y;
    return c;
}

static Point
add(a,b) Point a,b; {
    a.x += b.x;
    a.y += b.y;
    return a;
}

static Point
sub(a,b) Point a,b; {
    a.x -= b.x;
    a.y -= b.y;
    return a;
}

hideOriginalPages(s) char *s; {
    s[2] = 'p';
    while ((s = index(s,'\n')+1) != (char *)1)
        if (strncmp(s,"%%Page:",7)==0) s[2] = 'p'; 
}

pput(n,p) Point p; {
    char *s = readPage(n);
    Rectangle r;
    if (*s){
        hideOriginalPages(s);
        r = pageBbox; /* PageBbox[n]; ... Thus endeth the hack. */
	P("%f %f StartShrunkenPage",p.x,p.y);
	P("%f %f translate",-1.*Scale*r.o.x,-1.*Scale*r.o.y);
        fwrite(s,PageLen[n],1,Output);
        P("EndShrunkenPage");
    }
}

float
fmin(a,b) float a,b; {
    return a<b? a : b;
}

#define maxQ 16

#define up_decls \
    int i, j, N = (NP+(N_up-1))/N_up, page[maxQ];\
    float gap = Gutter;\
    Point c, p, g, b, q[maxQ];\
    g.x=g.y = gap/2.; b = BBox.c

#define nup_init() c = center(PBox); \
                   b.x *= Scale; b.y *= Scale; \
                   putProlog(N)

#define pgx(inc,d) pput(i*N_up+j+1,p); page[j] = *_s; q[j++]=p; p.d +=  
inc
#define putbox() for (j=0; j<N_up;j++) \
                   if (page[j])\
                    P("%f %f StartShrunkenPage q_bbox q_cuts  
EndShrunkenPage",\
                        q[j].x,q[j].y); \
                 ShowPage()


put2up(){
    up_decls;

    if (!ScaleSet)
        Scale =  
fmin((VS(PBox)/2.-(2.*gap))/b.x,((HS(PBox)-(2.*gap))/b.y));
    nup_init();

    for (i=0;i<N;i++){
	P("\n%%%%Page: %d %d\n/q_sheet save def",i+1,i+1);
        j = 0;

        p = c; p.y += g.x + b.x; p.x -= b.y/2.;
        pgx(-(gap+b.x),y);
        pgx(-(gap+b.x),y);
	
        putbox();   /* put out boxes, cut marks, & ShowPage */
    }
    return N;
}

put3up(){
    up_decls;

    if (!ScaleSet)
        Scale =  
fmin((VS(PBox)/3.-(2.*gap))/b.x,((HS(PBox)-(2.*gap))/b.y));
    nup_init();

    for (i=0;i<N;i++){
	P("\n%%%%Page: %d %d\n/q_sheet save def",i+1,i+1);
        j = 0;

        p = c; p.y += g.x + 1.5*b.x; p.x -= b.y/2.;
        pgx(-(gap+b.x),y);
        pgx(-(gap+b.x),y);
        pgx(-(gap+b.x),y);
	
        putbox();   /* put out boxes, cut marks, & ShowPage */
    }
    return N;
}

put6up(){
    up_decls;

    if (!ScaleSet)
        Scale =  
fmin((VS(PBox)/3.-(2.*gap))/b.x,((HS(PBox)/2.-(2.*gap))/b.y));
    nup_init();

    for (i=0;i<N;i++){
	P("\n%%%%Page: %d %d\n/q_sheet save def",i+1,i+1);
        j = 0;

        p = c; p.y += gap + 1.5*b.x; p.x += g.x;
        pgx(-(gap+b.x),y);
        pgx(-(gap+b.x),y);
        pgx(-(gap+b.x),y);
	
        p = c; p.y += gap + 1.5*b.x; p.x -= g.x + b.y;
        pgx(-(gap+b.x),y);
        pgx(-(gap+b.x),y);
        pgx(-(gap+b.x),y);
	
        putbox();   /* put out boxes, cut marks, & ShowPage */
    }
    return N;
}

put8up(){
    up_decls;

    if (!ScaleSet)
        Scale =  
fmin((VS(PBox)/4.-(2.*gap))/b.x,((HS(PBox)/2.-(2.*gap))/b.y));
    nup_init();

    for (i=0;i<N;i++){
	P("\n%%%%Page: %d %d\n/q_sheet save def",i+1,i+1);
        j = 0;

        p = c; p.y += 1.5*gap + 2.*b.x; p.x += g.x;
        pgx(-(gap+b.x),y);
        pgx(-(gap+b.x),y);
        pgx(-(gap+b.x),y);
        pgx(-(gap+b.x),y);
	
        p = c; p.y += 1.5*gap + 2.*b.x; p.x -= g.x + b.y;
        pgx(-(gap+b.x),y);
        pgx(-(gap+b.x),y);
        pgx(-(gap+b.x),y);
        pgx(-(gap+b.x),y);
	
        putbox();   /* put out boxes, cut marks, & ShowPage */
    }
    return N;
}

put4up(){
    up_decls;

    if (!ScaleSet)
        Scale =  
5*fmin((HS(PBox)-(2.*gap))/b.x,(VS(PBox)-(2.*gap))/b.y);
    nup_init();

    for (i=0;i<N;i++){
	P("\n%%%%Page: %d %d\n/q_sheet save def",i+1,i+1);
        j = 0;

        p = c; p.x -= g.x + b.x; p.y += g.y;
        pgx(gap+b.x,x);
        pgx(gap+b.x,x);
        p = c; p.x -= g.x + b.x; p.y -= g.y + b.y;
        pgx(gap+b.x,x);
        pgx(gap+b.x,x);
	
        putbox();   /* put out boxes, cut marks, & ShowPage */
    }
    return N;
}

put9up(){
    up_decls;

    if (!ScaleSet)
        Scale =  
333*fmin((HS(PBox)-(3.*gap))/b.x,(VS(PBox)-(2.*gap))/b.y);
    nup_init();

    for (i=0;i<N;i++){
	P("\n%%%%Page: %d %d\n/q_sheet save def",i+1,i+1);
        j = 0;

        p = c; p.x -= g.x + 1.5*b.x; p.y += g.y + .5*b.y;
        pgx(g.x+b.x,x);
        pgx(g.x+b.x,x);
        pgx(g.x+b.x,x);

        p = c; p.x -= g.x + 1.5*b.x; p.y -= .5*b.y;
        pgx(g.x+b.x,x);
        pgx(g.x+b.x,x);
        pgx(g.x+b.x,x);
	
        p = c; p.x -= g.x + 1.5*b.x; p.y -= g.y + 1.5*b.y;
        pgx(g.x+b.x,x);
        pgx(g.x+b.x,x);
        pgx(g.x+b.x,x);

        putbox();   /* put out boxes, cut marks, & ShowPage */
    }
    return N;
}

putpages(){
    int i;
    char *s, *p, *index();

    putProlog(NP);
    for (i=1;i<=NP;i++){
        s = readPage(i);
        if (*s){
            p = index(s,'\n');
            if (p){
                p+1;
                fprintf(Output,"%%%%Page: %d %d\n",i,i);
                fwrite(p,PageLen[i] - (p-s),1,Output);
                fprintf(Output,"q_bbox\n");
            }
        } else { /* emit blank page, e.g., for signatures */
                fprintf(Output,"%%%%Page: %d %d\n",i,i);
                fprintf(Output,"q_bbox\n");
        }
    }
}

char *SelectPages = (char *)0;

ReorderPages(){
    int i,j;
    int pages[MaxP], po[MaxP], pl[MaxP], np=0;
    Rectangle pr[MaxP];

    bzero(pages,sizeof(pages));

    if (SelectPages){
        char *s = skipsp(SelectPages);
        int start=0,end;
        while (*s){
            if (strncmp(s,"even",4)==0){
                for (i=2;i<=NP;i+=2) pages[np++]=i;
                s+=4;
            } else
            if (strncmp(s,"odd",3)==0){
                for (i=1;i<=NP;i+=2) pages[np++]=i;
                s+=3;
            } else
            if (strncmp(s,"blank",5)==0){
                pages[np++]=NP+1;
                s+=5;
            } else
            if (strncmp(s,"all",3)==0){
                for (i=1;i<=NP;i++) pages[np++]=i;
                s+=3;
            } else
            if (*s == '-'){
                start = 1;
                ++s;
                end = atoi(s);
                while (isdigit(*s)) ++s;
                for (i=start;i<=end;i++) pages[np++] = i;
            } else
            if (isdigit(*s)){
                pages[np++] = atoi(s);
                while (isdigit(*s) || isspace(*s)) ++s;
                if (*s == '-'){
                    ++s;
                    while (*s && !isdigit(*s)) ++s;
                    end = *s? atoi(s) : NP;
                    while (*s && isdigit(*s)) ++s;
                    for (i=pages[np-1]+1;i<=end;i++) pages[np++] = i;
                }
            } else
                ++s;
            while (*s== ',' || *s=='-' || isspace(*s)) ++s;
        }
        for (i=0;i<np;i++){
            po[i] = Page[pages[i]];
            pl[i] = PageLen[pages[i]];
            pr[i] = PageBbox[pages[i]];
        }
        for (i=0;i<np;i++){
            Page[i+1] = po[i];
            PageLen[i+1] = pl[i];
            PageBbox[i+1] = pr[i];
        }
        for (i=np+1;i<=NP;i++) Page[i] = PageLen[i] = 0;
        NP = np;
    } else
        for (i=0;i<NP;i++) pages[i] = i+1;
    if (ReversePages){
#define swap(t, a,b) t = a; a = b; b = t
        for (i=1,j=NP; i<j; i++,j--){
            int t;
            Rectangle r;
            swap(t, pages[i],pages[j]);
            swap(t, Page[i],Page[j]);
            swap(t, PageLen[i],PageLen[j]);
            swap(r,PageBbox[i],PageBbox[j]);
        }
    }
    if (Signatures){
      /* reorder appropriately for 2-sided signatures of
         'Signature' sheets per packet.
         With signatures of 2 sheets, a page ordering of
         1 2 3 4 5 6 7 8 9 10 11 12 . . .
         becomes
         8 1 2 7 6 3 4 5    16 9 10 15 . . .
       */
	int i, p, s, *P, tmp, PP, page[MaxP];
	int SidesPerSig = Signatures*2,
	    PagesPerSig = SidesPerSig*2,
	    NumSigs = (NP + PagesPerSig - 1) / PagesPerSig;
        bzero(page,sizeof(page));
	for (s=0,i=0; s<NumSigs; s++){
	    for (p=0, P = page+s*PagesPerSig+1;p<SidesPerSig;p++, P+=2)
		*P = pages[i++];
	    for (p=0, P-=3 ;p<SidesPerSig;p++, P-=2)
		*P = pages[i++];
	    for (p=0, P=page+s*PagesPerSig+2; p<PagesPerSig;p++,P+=4)
		tmp=P[0],P[0]=P[1],P[1]=tmp;
	}
        PP = NP; NP = PagesPerSig*NumSigs;
        for (i=0;i<NP;i++) if (page[i]>PP || !page[i]) page[i]=NP;

        for (i=0;i<NP;i++){
            po[i+1] = Page[page[i]];
            pl[i+1] = PageLen[page[i]];
            pr[i+1] = PageBbox[page[i]];
        }
        for (i=0;i<NP;i++){
            Page[i+1] = po[i+1];
            PageLen[i+1] = pl[i+1];
            PageBbox[i+1] = pr[i+1];
        }
	fprintf(stderr,"%d %d-page signatures:\n  ",NumSigs,Signatures);
	for (i=0;i<NP;i++){
	    if (i && i%4 == 0) fprintf(stderr,"  ");
	    if (i && i%PagesPerSig == 0) fprintf(stderr,"\n  ");
	    if (page[i]==NP)
		fprintf(stderr," . ");
	    else
		fprintf(stderr,"%2d ",page[i]);
	}
	fprintf(stderr,"\n");
    }
}

doFile(s) char *s; {
    FILE *f = fopen(s,"r");
    int n;
    if (!f) return error("%s: couldn't open %s",av0,s);
    Input = f;
    findPageOffsets();

    if (ListPages)
        showPageOffsets();
    else {
	ReorderPages();
    
	switch (N_up){
	case 2: n=put2up();
	Case 3: n=put3up();
	Case 4: n=put4up();
	Case 6: n=put6up();
	Case 8: n=put8up();
	Case 9: n=put9up();
	Default:n=putpages();
	}
    
	putTrailer(n);
    }
    fclose(f);
}

savetmp(s,f) char *s; FILE *f;
/* 
 * Copy 'f' into a tmp file; put the name in s,
 * and return 1 if success.
 */
{
    FILE *o;
    int n, F, O;
    char b[8192];
    strcpy(s,"/tmp/quartoXXXXXX");
    mktemp(s);
    strcat(s,".eps");
    if (o = fopen(s,"w")){
        F = fileno(f);
        O = fileno(o);
        while ((n=read(F,b,sizeof b))>0)
            write(O,b,n);
        fclose(o);
        return 1;
    } else
        return 0;    
}

use(){
    error("use: %s [-[234689]] [-p <pages>] [-S #] [-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("        'blank' or 0 inserts a blank page; 'all' inserts all  
the pages");
    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("  -S #  reorder pages to print them in signatures of #  
sheets;");
    error("        e.g., '-2 -S 3' prints pages 2-up per page for  
signatures");
    error("        of 3 double-sided sheets that will be folded and  
bound together.");
    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 */
    Case 'S': Signatures = atof(argument);
              if (N_up != 2)
                 error("You may want to specify -2 sheets per page.");
    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);
}
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads