[comp.lang.postscript] Summary: saving trees - a tool needed

chris@yarra.oz.au (Chris Jankowski) (11/08/89)

Original question:
=================

>If I have a simple document (no graphics and other fancies) already 
>formatted in Postscript how can I print a selection of pages from it?

Summary (in order of work required):
=======
	1. Use psrev from Transcript package by Adobe (RTFM again).
	2. Use a C program, source appended.
        3. Write your own program - algorithm outlines appended.

Thanks to all who responded.

Details:
=======

        3. Algorithm.
        -------------

From: raymond@bosco.Berkeley.EDU (Raymond Chen)
      raymond@math.berkeley.edu

[1] Copy everything from the beginning of the file to the
    "%%EndProlog" line.
[2] When you hit a "%%Page" directive, increment your internal page number
    counter.  If you want this page, start copying, and stop when you
    hit the next "%%Page" directive.
[3] Repeat for each page of the document, until you hit a "%%Trailer"
    directive.  Copy everything after "%%Trailer" to your output file.
-----------------

From: J Greely <jgreely@cis.ohio-state.edu>

	if the first line of the file doesn't start with '%!PS-Adobe',
		scream bloody murder and die
	save all lines before the first '%%Page:' line in a file
		named header
	parse out the sheet number from the '%%Page:' line
	save everything before the next '%%Page:' line in a file
		named <sheet number>.  Don't save the '%%Page:' line!
	keep doing this until you can't find another '%%Page:' line
	the last page is not followed by another '%%Page:', so stop
		at the '%%Trailer' line
	save everything from the '%%Trailer' line on in a file named
		trailer

You now have a set of files (header,1..<pages>,trailer).  To print
them, do the following:

	print header, inserting '%%Pages: (atend)' as the second line.
		If you don't do this, your output won't conform.
	print the desired pages, prefixed by a '%%Page:' comment
		containing the sheet order.  For strict conformance,
		they *must* be numbered sequentially starting at 1,
		but printers don't care (Adobe's own software cheats
		on this)
	print trailer
	print the actual pagecount, as a '%%Pages: n' comment.  For
		conformance with version 1.0, this must be the last
		'%%Pages:' line in the document.  Unfortunately, the
		relevant sentence was deleted from version 2.0, so
		you're only safe if you delete all other '%%Pages:'
		lines in the trailer.

  If you're not interested in rearranging pages, you can speed things
up quite a bit by discarding undesired pages as you read them, and
hacking '%%Page:' lines on the fly.

  Note that everything I say ignores some of the advanced comment
structures possible in version 2.0, like embedded documents (which may
contain their own comment structures, including '%%Trailer').  For
details about this, read the Adobe Document Structuring Conventions
document, version 2.1.


        2. C source code.
        =================

I compiled the following program in att universe and it does what I want.

From: Jingbai  Wang <jbw@unix.cis.pitt.edu>

/* Here is a program I developed called psscribe.c that is self-instructive*/
/*  Copyright (C) 1989 by Jingbai Wang

   This program is released to public as shareware.
   Any individual and institution can use, modify and distribute
   it freely provided the copyright note and the following box 
   are retained. One exeption is that profitable distribution (i.e., charge
   over the cost of materials and ship&handling) should have author's written
   permission.
                             */   

/* **********************************************************************
 *            This program is an auxiliary program for Scribe TEC.mak   *
 *                          desgined by myself.                         *
 *             It is used to manipulate Scribe PostScript output files  *
 *          or equally standard PostScript output from a text formatter *
 *             such that a long .ps file can be cut into shorter ones   *
 *             and double-sided documents can be separated into two     *
 *             .ps files for even-sided and odd-sided pages             *
 *                                                                      *
 *           The user can set up the programs for other purposes too    *
 *                    Copyright by Jingbai Wang August 1988             *
 ************************************************************************/

/*

   It is intended to have it adoptable to any systems. It is in my mind
   for VMS, MSDOS/PC-DOS and unix for the time being.
   
*/


#define STRSIZE 1024
#define FILEMAX 100
#define PROLENGTH 3600000


#include <string.h>
#include <math.h>
#include <stdio.h>

#define CLS fprintf(stderr, "\n\n\n\n");

/* Global variables */

char psfile[80]="",
     Prolog[PROLENGTH],
     outfile1[FILEMAX][80],
     outfile[80],
     evenfile[80],
     oddfile[80],
     prestring[80]="";
FILE *psfileptr, *Oddpage, *Evenpage, *Allpage;
int partnum=0,
    filestart[FILEMAX],
    fileend[FILEMAX],
    currentpage=0,
    file_flag=0;
long int prolength=0,
     pageend[1000];


char string[1024];
get_prolog()
{
int l;

	prolength = 0;
while(1){
       fgets(&Prolog[prolength], 1024, psfileptr);
       if( memcmp(&Prolog[prolength], "%%EndProlog", 11)==0)
       {while (Prolog[++prolength] != 0) ;
       return;
       }
       else while (Prolog[++prolength] != 0) ;

        }
}

main(argc, argv)
int argc;
char *argv[];
{

start_up();

  if (argc>1) {strcpy(psfile, argv[1]); file_flag=1;}

pro_info(); 
}


get_file()
{
int status, len, i, dot_check; 
dot_check=0;


if(file_flag==0)
       {CLS;        
        fprintf(stdout, "\n   PostScript file name (path and name)> ");
        scanf("%s", psfile);
       }


               len=strlen(psfile);
               for (i=0; i<len; i++)
               if (psfile[i]=='.') {dot_check=1;}

               if (dot_check==0) {strcat(psfile, ".ps");}

             
   if ( (psfileptr=fopen(psfile, "r"))==NULL)
      {fprintf(stderr, "  .ps file not found "); exit(-1);}


}

pro_info()
{
int yes, i, junk;

fflush(stdin);

start:

CLS; 

fprintf(stderr, "\n            1. Get page mapping information\n");
fprintf(stderr, "            2. Extract some pages from the document\n");
fprintf(stderr, "            3. Divide document into parts\n");
fprintf(stderr, "            4. Split document into even and odd pages\n");
fprintf(stderr, "            5. Reverse the page numbers \n");
fprintf(stderr, "            6. Merge a few .ps files together\n");
fprintf(stderr, "            7. Fix converted zeta.plt file\n");
fprintf(stderr, "            8. quit\n\n\n");

select:
fprintf(stderr, "                       Select a number from above ==> ");
fflush(stdin);
scanf("%d", &yes);
fflush(stdin);

 switch(yes)
  {
    case 1: get_file(); page_map(); break;
    case 2: partnum=1; get_file(); get_prolog(); extract(); break;
    case 3: get_file(); get_prolog();
            fprintf(stderr, "\n\n   How many parts to divide>");
            scanf("%d", &partnum);
            fflush(stdin); divide(); break;
    case 4: get_file(); get_prolog(); even_odd(); break;
    case 5: get_file(); get_prolog(); reverse_page(); break;
    case 6: merge(); break;
    case 7: get_file(); fix_zeta();break;
    case 8: exit(-1);
  default: fprintf(stderr, "%c", 7); goto select;
  }


#if unix|ultrix
scanf("%c", &junk);
fflush(stdin);
#endif
hit_continue();              
 clear_up();
goto start;

}


even_odd()
{
long int i;
int len;

  fprintf(stderr, "       Output file name odd pages > ");
        scanf("%s", oddfile);

  fprintf(stderr, "       Output file name even pages > ");
        scanf("%s", evenfile);

Evenpage=fopen(evenfile, "w");
Oddpage=fopen(oddfile, "w");

for (i=0; i<prolength; i++)
 { fprintf(Evenpage, "%c", Prolog[i]);
   fprintf(Oddpage, "%c", Prolog[i]);
 }

 while(1)
   {
     if( fgets(string, 1024, psfileptr)==NULL)
{
fclose(psfileptr);
fclose(Evenpage);
fclose(Oddpage);
return;
}

       fprintf(Oddpage, "%s", string);
     if (memcmp(string, "%%Page:", 7)==0) {
       len=strlen(string);  string[len-2]=0;     
      fprintf(stderr, "[%s]", &string[8]);
      }


     if( fgets(string, 1024, psfileptr)==NULL) 
{
fclose(psfileptr);
fclose(Evenpage);
fclose(Oddpage);
return;
}
     
       fprintf(Evenpage, "%s", string);
    if (memcmp(string, "%%Page:", 7)==0)
      {
       len=strlen(string);  string[len-2]=0;     
      fprintf(stderr, "[%s]", &string[8]);
      }
   }




}


extract()
{

  fprintf(stderr, "\n      Filename for output > ");
        scanf("%s", outfile);
  Allpage=fopen(outfile, "w");

    fprintf(stderr, "       Starting page >");
    scanf("%d", &filestart[0]);
    fflush(stdin);

  fprintf(stderr, "       End page >");
  scanf("%d", &fileend[0]);
  fflush(stdin);

     while(currentpage<filestart[0])
        {
         if(  (fgets(string, 1024, psfileptr))==NULL) 
            {fclose(Allpage); fclose(psfileptr);return;}
         if (memcmp(string, "%%Page:", 7)==0) currentpage++;
        }
          strcpy(prestring,string);


go(0); fclose(Allpage); fclose(psfileptr);

}



divide()
{
int i;

  for (i=0; i<partnum; i++)
 {
   fprintf(stderr, "\n      Filename for output part %d> ", i+1);
        scanf("%s", outfile1[i]);

  if (i==0)
    { fprintf(stderr, "       Part %d starts at page # >", i+1);
      scanf("%d", &filestart[i]);
      fflush(stdin);

    } 
    else filestart[i]=fileend[i-1]+1;

    fprintf(stderr, "       Part %d ends at page # >", i+1);
    scanf("%d", &fileend[i]);
    fflush(stdin);

 }


if (filestart[0]>1){
     while(currentpage<filestart[0])
        {
         if(  (fgets(string, 1024, psfileptr))==NULL) return;
         if (memcmp(string, "%%Page:", 7)==0) currentpage++;
        }
          strcpy(prestring,string);

     }



  for (i=0; i<partnum; i++)
 {
  fprintf(stdout, "\n%s:\n", outfile1[i]);
  Allpage=fopen(outfile1[i], "w");
  go(i); fclose(Allpage);
 }

fclose(psfileptr);
}

go(number)
int number;
{
int i;
int len;

for (i=0; i<prolength; i++)
  fprintf(Allpage, "%c", Prolog[i]);

  len=strlen(prestring);
    if (len>0) { fprintf(Allpage, "%s", prestring); 
      prestring[len-2]=0;
      fprintf(stderr, "[%s]", &prestring[8]);           }     


 while(1)
   {
 
     if( fgets(string, 1024, psfileptr)==NULL) 
      {
        return;
      }

     if (memcmp(string, "%%Page:", 7)==0) {currentpage++;
        if (currentpage>fileend[number]) {strcpy(prestring, string);
         return;} 
      len=strlen(string);  string[len-2]=0;     
      fprintf(stdout, "[%s]", &string[8]);  string[len-2]=32;     
      }

       fprintf(Allpage, "%s", string);

   }

}


page_map()
{
int count, len;

fprintf(stderr, "     Map file filename for output (2 <Return> for screen)-> ");
fflush(stdin);
scanf("%s", outfile);
if (outfile[0]=='2') Allpage=stdout;
else Allpage=fopen(outfile, "w");

fprintf(stderr , "\n\n");

while(1)
   {
     if( fgets(string, 1024, psfileptr)==NULL) 
      {
       fclose(psfileptr); 
       if (Allpage!=stdout) fclose(Allpage);
       fflush(stdin);
       return;
       }



     if (memcmp(string, "%%Page:", 7)==0) {currentpage++;
       len=strlen(string);  string[len-1]=0; count++;     
     if (count>10) {count=0; fprintf(Allpage, "\n");}      
      fprintf(Allpage, "[%s]", &string[8]);
      }


    }

}


reverse_page()
{
int i;
long int j;
 

fprintf(stderr, "     Filename for output file -> ");
fflush(stdin);
scanf("%s", outfile);
Allpage=fopen(outfile, "w");

for (i=0; i<prolength; i++)
  {fprintf(Allpage, "%c", Prolog[i]); Prolog[i]=0;}

prolength=0; currentpage=0;
       pageend[0]=0;

 while(1)
   {
     if( fgets(string, 1024, psfileptr)==NULL) 
      {
        fclose(psfileptr);
        goto out;
      }
       strcat(Prolog, string);
       
     if (memcmp(string, "%%Page:", 7)==0) {currentpage++;
         pageend[currentpage]=prolength;        
      }
       
       prolength += strlen(string);

   }

out:

         for (j=pageend[currentpage]; j<prolength; j++)
            fprintf(Allpage, "%c", Prolog[j]);


    for (i=currentpage; i>0; i--)
       {
         for (j=pageend[i-1]; j<pageend[i]; j++)
            fprintf(Allpage, "%c", Prolog[j]);
       }     

        fclose(Allpage);

}


start_up()

{
char junk;
CLS; 


fprintf(stderr, "               Welcome to Textformatter .ps File Manager\n");
fprintf(stderr, "                          by JB Wang, 1989\n\n");

fprintf(stderr, "     This utility program can be used to 1) extract certain pages to be\n\
     printed; 2) divide the .ps file into a few smaller files;  3) split \n\
     the document into two files for odd and even pages; 4) reverse the\n\
     page numbering; 5) Merge .ps files in intelligent way; 6) Fix a converted\n\
     zeta.plt PostScript file at Pitt\n\n");

fprintf(stderr, "\
     Text formatter .ps output file is composed of a prologue, a main body\n\
     of pages, and a trailer. Each page carries two page numbers,\n\
     that is, the physical page number (printed) and a counter number\n\
     that accumulates from 1 to the end. The program can provide the\n\
     mapping information between these two numbers in the following format\n\
     [page_number counter_number].\n\n");

fprintf(stderr, "     This program uses the counter number instead of the physical number.\n\
     Therefore, you are advised to get the mapping information before\n\
     you output files.\n\n\n");

fprintf(stderr, "                                Hit <Return> to continue -->");

scanf("%c", &junk);
fflush(stdin);

}


merge()
{
int i;

fprintf(stderr, "\n\n  How many files to merge? ");
scanf("%d", &partnum);
fflush(stdin);

if (file_flag==1) 
  {strcpy(outfile, psfile);
  fprintf(stderr, "\n      Filename for output > %s", outfile);
  }
else {
  fprintf(stderr, "\n      Filename for output > ");
        scanf("%s", outfile);
     }
  Allpage=fopen(outfile, "w");

  for (i=0; i<partnum; i++)
 {
again:
   fprintf(stderr, "       File %d  to merge >", i+1);
        scanf("%s", outfile1[i]);
   if ( (psfileptr=fopen(outfile1[i], "r"))==NULL)
      {fprintf(stderr, "  .ps file not found "); goto again;}
       fclose(psfileptr);
 }

  for (i=0; i<partnum; i++)
 {
   psfileptr=fopen(outfile1[i], "r");
   if (i>0)  get_prolog();
    while(fgets(string, 1024, psfileptr)!=NULL) 
    fprintf(Allpage, "%s", string);    
   fclose(psfileptr);
  }

}


fix_zeta()
{
int i;
char ch;

  fprintf(stderr, "\n      Filename for output > ");
        scanf("%s", outfile);

for (i=0; i<685; i++)
  fgetc(psfileptr);

if (fgetc(psfileptr)!='d') 
{ fclose(psfileptr); 
fprintf(stderr, "\n     Wrong version of converted .lps file");
return;
}

  fgetc(psfileptr);  fgetc(psfileptr); 
  Allpage=fopen(outfile, "w");

fprintf(Allpage, "%%!\n\
/s { 72 mul 300 div } def /steps { 72 mul 2032 div } def /d { count 0 gt  { s exch s exch moveto { count 0 gt \n\
{ s exch s exch lineto } { exit } ifelse } loop 0.3 setlinewidth stroke clear } if } def /g { count 0 gt  { s exch s exch moveto\n\
{ count 0 gt { s exch s exch lineto } { exit } ifelse } loop [3 5] 0 setdash 0.5 setlinewidth stroke clear [] 0 setdash } if } def\n\
/h { /Courier findfont 6 scalefont setfont  -6 -26  moveto } def /f { -6 -16 moveto } def\n\
 /n { d newpath } def /a0 { arc stroke } def  /a1 { arcn stroke } def /mr { moveto rotate } def\n\
 /cf { /Courier findfont } def /ss { scalefont setfont } def  /ur { rotate } def  /dd { [] 0 setdash } def d\n");


while ((ch=fgetc(psfileptr))!=EOF)
    fprintf(Allpage, "%c", ch);

fclose(psfileptr);
fclose(Allpage);
}


hit_continue()
{
char junk;

fprintf(stderr, "\n\n                           Hit <Return> to continue -->");

fflush(stdin);
fflush(stdin);
fflush(stdin);
scanf("%c", &junk);
fflush(stdin);              

}

clear_up()
{
long int i;

   partnum=0;
  for (i=0; i<prolength; i++)
    Prolog[i]=0;
  prolength=0;
  strcpy(prestring, "");
  currentpage=0;
  file_flag=0;
}

jgreely@oz.cis.ohio-state.edu (J Greely) (11/09/89)

>From: J Greely <jgreely@cis.ohio-state.edu>
>	print header, inserting '%%Pages: (atend)' as the second line.
>		If you don't do this, your output won't conform.

As a side note, NeXT users should also delete all other '%%Pages:'
comments in the header, since the version of Preview shipped with
release 1.0 doesn't ignore subsequent '%%Pages:' lines.
-=-
J Greely (jgreely@cis.ohio-state.edu; osu-cis!jgreely)