[comp.lang.postscript] EPS manipulation example

shiva@well.sf.ca.us (Kenneth Porter) (11/02/90)

/*
Use %%BoundingBox specs in PostScript file to scale to fit
on an A-size sheet with 0.375" margins.
 
Author: Kenneth Porter (shiva@well.sf.ca.us)
1431 Madeline Rd.
San Pablo, CA  94806-1259
 
Compiles with Turbo C 2.0.
*/
 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
#define FALSE 0
#define TRUE (!FALSE)
 
#define ERRSTRING sys_errlist[errno]    /* DOS file error description */
 
char copyrt[] = "Copyright 1989 Kenneth Porter, all rights reserved\n";
 
/* printable area in points */
#define INCH 72.0
#define MARGIN 0.375
#define WIDTH ((8.5-(2*MARGIN)) * INCH)
#define HEIGHT ((11.0-(2*MARGIN)) * INCH)
 
/* file variables */
char *srcname = NULL, *dstname = NULL;
FILE *srcfile, *dstfile;
char inbuf[256];
 
/* Bounding Box info */
char BBs[] = "%%BoundingBox:";
#define BBSize (sizeof(BBs)-1)
char atend[] = "(atend)";
#define atSize (sizeof(atend)-1)
char trailer[] = "%%Trailer";
#define trailSize (sizeof(trailer)-1)
int llx,lly,urx,ury;
 
/* function prototypes */
void OpenSrcFile(char *name);
void OpenDstFile(char *name);
int FindBB(void);
void WriteProlog(void);
void CopySrcToOut(void);
void WriteTrailer(void);
void CloseFiles(void);
 
void main (int argc, char *argv[])
{
    /* first print title and open files */
    puts("PostScript Page-Fitting Utility\n");
    puts(copyrt);
    if (argc != 3) {
        fputs("syntax: PSFIT <source> <destination>\n",stderr);
        exit(1);
    }
    OpenSrcFile(argv[1]);
    if (!FindBB()) {
        fprintf(stderr,"No %%%%BoundingBox comment in %s",srcname);
        exit(1);
    }
    OpenDstFile(argv[2]);
    WriteProlog();
    CopySrcToOut();
    WriteTrailer();
    CloseFiles();
    exit(0);
}
 
void OpenSrcFile(char *name)
{
    srcname = strupr(name);
    srcfile = fopen(srcname,"rt");
    if (!srcfile) {
        fprintf(stderr,"Failed to open %s for reading: %s\n",
            srcname,ERRSTRING);
        exit(1);
    }
}
 
void OpenDstFile(char *name)
{
    dstname = strupr(name);
    if (!strcmp(srcname,dstname)) {
        fputs("Source file and destination file must be different\n",stderr);
        exit(1);
    }
    dstfile = fopen(dstname,"wt");
    if (!dstfile) {
        fprintf(stderr,"Failed to open %s for writing: %s\n",
            dstname,ERRSTRING);
        exit(1);
    }
}
 
int FindBB(void)
{
    /*
    Scan stdin for line beginning with %%BoundingBox or not a
    prolog comment.
    */
 
    int in_prolog, in_trailer, BB_in_trailer, nargs, BB_seen;
 
    in_prolog = TRUE;
    in_trailer = BB_in_trailer = BB_seen = FALSE;
    fgets(inbuf,sizeof(inbuf),srcfile);
    while (!(feof(srcfile) || ferror(srcfile))) {
        if (in_prolog) {
            if (inbuf[0] != '%' || (inbuf[1] != '%' && inbuf[1] != '!'))
                in_prolog = FALSE;
            else {
                if (!strncmp(inbuf,BBs,BBSize)) {
                    if (!strncmp(&inbuf[BBSize+1],atend,atSize)) {
                        BB_in_trailer = TRUE;
                    }
                    else {
                        nargs = sscanf(&inbuf[BBSize],
                               " %d %d %d %d",
                               &llx,&lly,&urx,&ury);
                        if (nargs != 4) {
                            fprintf(stderr,
                                "Bad %%%%BoundingBox comment in header, %d args
parsed:\n",
                                nargs);
                            fprintf(stderr," \"%s\"",inbuf);
                            exit(1);
                        }
                        BB_seen = TRUE;
                        in_prolog = FALSE; /* only look at first */
                    }
                }
            }
        }
        else if (BB_in_trailer) {
            /* not in prolog */
            if (!strncmp(inbuf,trailer,trailSize))
                in_trailer = TRUE;
            if (in_trailer) {
                if (!strncmp(inbuf,BBs,BBSize)) {
                    nargs = sscanf(&inbuf[BBSize],
                           " %d %d %d %d",
                           &llx,&lly,&urx,&ury);
                    if (nargs != 4) {
                        fprintf(stderr,
                            "Bad %%%%BoundingBox comment in trailer, %d args
parsed:\n",
                            nargs);
                        fprintf(stderr," \"%s\"",inbuf);
                        exit(1);
                    }
                    BB_seen = TRUE;
                }
            }
        }
        else break;
    fgets(inbuf,sizeof(inbuf),srcfile);
    } /* while (!eof) */
    if (ferror(srcfile)) {
        fprintf(stderr,"Error reading from %s: %s\n",srcname,ERRSTRING);
        exit(1);
    }
    return(BB_seen);
}
 
char prolog[] =
    "%%!PS-Adobe-2.0\n"
    "%%%%Creator: PSFIT\n"
    "%%%%BoundingBox: %d %d %d %d\n"
    "%%%%EndComments\n"
    "%%%%EndProlog\n"
    "%%%%BeginSetup\n"
    "%f %f translate\n"
    "%f %f scale\n"
    "%f %f translate\n"
    "%f rotate\n"
    "%%%%EndSetup\n"
    "%%%%BeginDocument: %s\n";
 
void WriteProlog(void)
{
    int new_llx,new_lly,new_urx,new_ury;
    double scale,xscale,yscale;
    int rotate;
    
    if (urx-llx > ury-lly) {
        rotate = 90;
        /* rotate BB coords around origin */
        new_llx = -ury;
        new_lly = llx;
        new_urx = -lly;
        new_ury = urx;
        /* copy back into original variables */
        llx = new_llx;
        lly = new_lly;
        urx = new_urx;
        ury = new_ury;
    }
    else rotate = 0;
    new_llx = new_lly = MARGIN*INCH;
    xscale = WIDTH / (double) (urx - llx);
    yscale = HEIGHT / (double) (ury - lly);
    scale = min(xscale,yscale);
    new_urx = new_llx + scale*(urx-llx);
    new_ury = new_lly + scale*(ury-lly);
    fprintf(dstfile,prolog,
        new_llx,new_lly,    /* new BBox */
        new_urx,new_ury,
        (float)new_llx,(float)new_lly,  /* translate */
        (float)scale,(float)scale,      /* scale */
        (float)-llx,(float)-lly,        /* translate */
        (float) rotate,                 /* rotate */
        srcname);
}
 
void CopySrcToOut(void)
{
    rewind(srcfile);
    fgets(inbuf,sizeof(inbuf),srcfile);
    while(! (feof(srcfile) /* || ferror(srcfile) */ ) ) {
        fputs(inbuf,dstfile);
        fgets(inbuf,sizeof(inbuf),srcfile);
    }
    if (ferror(srcfile)) {
        fprintf(stderr,"Error reading from %s: %s\n",srcname,ERRSTRING);
        exit(1);
    }
}
 
void WriteTrailer(void)
{
    fputs("%%EndDocument\n",dstfile);
}
 
void CloseFiles(void)
{
    fclose(srcfile);
    fclose(dstfile);
}