home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume12 / psf2 / part04 / psd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-05-19  |  10.5 KB  |  422 lines

  1. /* ta=4 */
  2.  
  3. /****************************************************************************
  4. *                p s d . c        v2.0                                        *
  5. *                                                                            *
  6. *    Filter a "single sided" document to become a "double sided document"    *
  7. *                                                                            *
  8. *    Tony Field.       tony@ajfcal                                              *
  9. *                                                                            *
  10. *    The basic algorithm for "print_book()"  was based on a routine written    *
  11. *    by Tom Neff (tneff@well.uucp) named "book" which printed 5.5x8.5         *
  12. *    double sided on an HP LaserJet.                                            *
  13. ****************************************************************************/
  14. /*
  15.     A number of comments could be made about psd:
  16.         1. it does work.
  17.         2. it could work a lot better
  18.         3. output is minimally conforming to postscript
  19.         4. input is "similar to" postscript
  20.  
  21.     the psf-generated control information is assumed to be at the
  22.     end of the postscript print file.  The postscript file must contain
  23.     a line like:
  24.                     %PsfPtr: 21118
  25.                     
  26.     If the %PsPtr line is missing, then the file is NOT a book format.
  27.     The format of this information is described in function read_control().
  28.                 
  29.     psd does little to normal double sided print other than to change
  30.     the order in which the pages are printed.  It also adjusts the
  31.     %%Pages: value to reflect the actual page count printed.
  32.     
  33.     psd re-inserts translation, rotation and scale information eliminated
  34.     by psf if the double sided print is to make an 8.5x5.5 "book".
  35.  
  36.     Of course, a bunch of "very ugly" logic is needed for the "book"
  37.     format to re-insert the postscript for page control - but it does work...
  38. */
  39.  
  40. #include <stdio.h>
  41. #include <string.h>
  42.  
  43. /*    If books are made by generating two print files with the -s side count
  44.     then set SIDECOUNT = 0  (i.e. no alternate paper hopper is available.
  45.     
  46.     If books are made by switching to the alternate print hopper for
  47.     the second side, then set SIDECOUNT = 3  (i.e. second hopper is available
  48. */
  49.  
  50. #define    SIDECOUNT    0
  51.  
  52. #define LONG_STR    1000
  53. #define MAX_PAGE    1000
  54.  
  55. static int nsheets, nhalves;
  56. static int row;
  57. static int lpage, rpage;
  58.  
  59. char    slots[4][100] = 
  60. {            "statusdict begin 1 setpapertray end",
  61.             "statusdict begin 2 setpapertray end",
  62.             "",
  63.             ""
  64. } ;
  65. int        nslots = 2;
  66.  
  67. char    line[LONG_STR + 1];
  68. char    scale[100];
  69. int        max_frame;
  70. int        landscape;
  71. int        real_width;
  72. int        height;
  73. int        width;
  74. int     dx_home[4];
  75. int     dy_home[4];
  76. int        npage;
  77. long    pg_loc[MAX_PAGE];
  78. long    trailer_loc;
  79. int        phys_page;
  80. int        side;
  81. int        bookwork;
  82. int        alternate_tray = 0;
  83. int        second_side = 0;
  84.  
  85. FILE    *input_fp;
  86. FILE    *output_fp;
  87.  
  88. char    *pgmname;
  89.  
  90. main(argc, argv)
  91. int        argc;
  92. char    *argv[];
  93. {    int        c;
  94.     extern char *optarg;
  95.     extern int    optind;
  96.     FILE    *pdef;
  97.     
  98.     side = SIDECOUNT;            /* print size 1, 2, or both = 3 */
  99.     
  100.     if ((pdef = fopen (PDEF, "r")) != NULL)
  101.     {    nslots = 0;
  102.         while (fgets (line, LONG_STR - 1, pdef) != NULL)
  103.         {    trim (line);
  104.             if (strncmp (line, "*slots", 6) == 0)
  105.             {    while (fgets (line, 90, pdef) != NULL)
  106.                 {    trim (line);
  107.                     if (strncmp (line, "*eof", 4) == 0)
  108.                         break;
  109.                     if (*line)
  110.                     {
  111.                         strcpy (slots[nslots], line);
  112.                         if (++nslots > 3)
  113.                             break;
  114.                     }
  115.                 }
  116.             }
  117.         }
  118.         fclose (pdef);
  119.     }
  120.  
  121.     pgmname = argv[0];
  122.     if (argc > 1  && strcmp (argv[1], "-") == 0)
  123.         usage ();
  124.         
  125.     while ((c = getopt(argc, argv, "123-")) != -1)
  126.     {    switch (c)
  127.         {
  128.         case '1':
  129.         case '2':
  130.         case '3':
  131.             side = c - '0';
  132.             break;
  133.  
  134.         default:
  135.             usage ();
  136.         }
  137.     }
  138.     if (side == 3  &&  nslots < 2)
  139.     {    fprintf (stderr, "Cannot use -3: only one output tray\n");
  140.         exit (1);
  141.     }
  142.     
  143.     if (side <= 0  ||  side >= 4)
  144.     {    fprintf (stderr, "Print side must be 1, 2, or 3\n");
  145.         exit (1);
  146.     }
  147.     if (optind >= argc)
  148.         usage ();
  149.  
  150.     output_fp = stdout;
  151.     
  152.     if ((input_fp = fopen(argv[optind], "r")) == NULL)
  153.     {
  154.         fprintf(stderr, "%s: Error opening %s!\n", pgmname, argv[1]);
  155.         exit (1);
  156.     }
  157.     read_control (input_fp);
  158.     get_prologue ();
  159.     if (bookwork)
  160.         print_book ();
  161.     else
  162.         print_double ();
  163.     get_trailer ();
  164.     exit (0);
  165. }
  166.  
  167. /****************************************************************************
  168. *    read_control()                                                            *
  169. *    Read the control information at the end of the file for the page         *
  170. *    dimensions and byte address of the start of each page.                    *
  171. *    Each of the parameter lines is a comment with the form %Psfxxxx: yyyy    *
  172. ****************************************************************************/
  173.  
  174. read_control (fp)
  175. FILE    *fp;
  176. {    char    tail[100];
  177.     int        i, j;
  178.     long    atol(), psfloc;
  179.     
  180.     /*    %PsfPtr: xxx  --> xxx is the pointer to the first %Psf... line
  181.         in the file.  Seek to the indicated byte position to begin
  182.         reading the Psf generated information which looks like:
  183.  
  184.                 %%Trailer                            <--- (a)
  185.                 %%DocumentFonts: Courier
  186.                 %%Pages: 8
  187.                 %PsfScale: 0.63194 0.79558 scale    <--- (b)
  188.                 %PsfMargin: 2 1 612 769 626
  189.                 %PsfHome: 0 0 0
  190.                 %PsfHome: 1 626 0
  191.                 %PsfHome: 2 0 0
  192.                 %PsfHome: 3 0 0
  193.                 %PsfPg: 0 405            <--- byte offsets to page
  194.                 %PsfPg: 1 3885
  195.                 %PsfPg: 2 7023
  196.                     ...
  197.                 %PsfPg: 9999 21072        <--- points to (a) above
  198.                 %PsfPtr: 21118            <--- points to (b) above
  199.                 <ctrl/d>
  200.     */
  201.     fseek (fp, -50L, 2);
  202.     fread (tail, 50, 1, fp);
  203.     if ((i = tscan (tail, "%PsfPtr:")) == -1)
  204.     {    fprintf (stderr, "%s: File is not in psf book format\n", pgmname);
  205.         exit (1);
  206.     }
  207.     psfloc = atol (tail + i + 9);        /*    beginning  of psf information */
  208.     fseek (fp, psfloc, 0);
  209.     
  210.     fgets (scale, 99, fp);
  211.     strcpy (tail, scale + 11);            /* get rid of the %psf comment */
  212.     strcpy (scale, tail);
  213.  
  214.     /*    fetch psf data.    */
  215.                                                         /*    %PsfMargin:    */
  216.     fscanf (fp, "%s %d %d %d %d %d", tail,
  217.                 &max_frame, &landscape, &real_width, &height, &width);
  218.  
  219.     bookwork = max_frame == 2  &&  landscape;
  220.     for (i = 0;  i < 4;  i++)                            /*    %PsfHome:    */
  221.         fscanf (fp, "%s %d %d %d",  tail, &j, &dx_home[i], &dy_home[i]);
  222.  
  223.     npage = 0;                                            /*    %PsfPg:        */
  224.     while (fscanf (fp, "%s %d %ld", tail, &i, &pg_loc[npage]) == 3)
  225.     {
  226.         if (i == 9999)
  227.         {    trailer_loc = pg_loc[npage];
  228.             break;
  229.         }
  230.         npage++;
  231.     }
  232.     fseek (fp, 0L, 0);
  233. }
  234.  
  235. /****************************************************************************
  236. *    get_prologue()                                                            *
  237. *    Read the prologue and pass it directly to the output                    *
  238. ****************************************************************************/
  239.  
  240. get_prologue ()
  241. {
  242.     fgets (line, LONG_STR, input_fp);        /*    skip the psf header     */
  243.     fprintf (output_fp, "%%!PS-Adobe-\n");    /*    write a valid header    */
  244.     while (fgets (line, LONG_STR, input_fp) != NULL)
  245.     {    if (strncmp (line, "%%Page:", 7) == 0)
  246.             break;
  247.         fputs (line, output_fp);
  248.     }
  249. }
  250.  
  251. /****************************************************************************
  252. *    get_trailer ()                                                            *
  253. *    Read the trailer and pass it to the output.  Modify the page count to    *
  254. *    reflect the number of physical pages printed.                            *
  255. *    Remove any reference to the %Psf... lines.                                *
  256. ****************************************************************************/
  257.  
  258. get_trailer ()
  259. {
  260.     if (phys_page == 0  ||  (bookwork  &&  second_side))
  261.         fprintf (output_fp, "showpage pg restore\n");
  262.     if (alternate_tray == 2)
  263.         fprintf (output_fp, "%s\n", slots[0]);
  264.     fseek (input_fp, trailer_loc, 0);
  265.     while (fgets (line, LONG_STR, input_fp) != NULL)
  266.     {    if (strncmp (line, "%%Pages:", 8) == 0)
  267.             fprintf (output_fp, "%%%%Pages: %d\n", phys_page);
  268.         else if (strncmp (line, "%Psf", 4) != 0)
  269.             fputs (line, output_fp);
  270.     }
  271. }
  272.  
  273. /****************************************************************************
  274. *    display_page()                                                            *
  275. *    Send all ouput that belongs to a specific page.  For 8.5x5.5 books,        *
  276. *    generate the scale, etc that was omitted by psf.  Also enable the        *
  277. *    alternate tray if it to be used.                                        *
  278. ****************************************************************************/
  279.  
  280. display_page  (pgno, n)
  281. int pgno;
  282. int    n;
  283. {    static need_showpage = 0;
  284.  
  285.     fseek (input_fp, pg_loc[pgno], 0);
  286.     fgets (line, LONG_STR, input_fp);
  287.     if (n == 0)
  288.     {
  289.         if ((phys_page  &&  bookwork)  ||  need_showpage)
  290.             fprintf (output_fp, "showpage pg restore\n");
  291.  
  292.         if (alternate_tray == 1)
  293.         {    alternate_tray = 2;
  294.             fprintf (output_fp, "%s\n", slots[1]);
  295.         }
  296.         fprintf (output_fp, "%%%%Page: ? %d\n", ++phys_page);
  297.         if ((bookwork  &&  max_frame == 2)  ||  pgno >= npage)
  298.         {    fprintf (output_fp, "/pg save def\n");
  299.         }
  300.         need_showpage = pgno >= npage;
  301.     }
  302.  
  303.     if (bookwork)
  304.     {    if (n == 0)
  305.         {
  306.             fprintf (output_fp, "90 rotate 0 %d translate\n", -real_width);
  307.             fprintf (output_fp, "%s", scale);
  308.         }
  309.         fprintf (output_fp, "%d %d translate\n", dx_home[n], dy_home[n]);
  310.     }
  311.  
  312.     if (pgno < npage)
  313.     {    while (fgets (line, LONG_STR, input_fp) != NULL)
  314.         {    if(strncmp (line, "%%", 2) == 0)
  315.                 break;
  316.             fputs (line, output_fp);
  317.         }
  318.     }
  319. }
  320.  
  321.  
  322. /****************************************************************************
  323. *    print_book()                                                            *
  324. *    print_book() is based on Tom Neff's (tneff@well.uucp) "book"             *
  325. *    for the HP LaserJet                                                     *
  326. *    Scan the text to ensure that the 8.5x.5.5 pages are constructed in        *
  327. *    such a way that a "book" is generated - simply staple in the middle    .    *
  328. ****************************************************************************/
  329.  
  330. print_book ()        
  331. {    int    done;
  332.  
  333.     nsheets = (npage+3)/4;
  334.     nhalves = nsheets*4;
  335.     phys_page = 0;
  336.  
  337.     if (side & 1)
  338.     {    for (rpage=0, lpage=nhalves-1;  rpage < lpage;  rpage+=2, lpage-=2)
  339.         {
  340.             display_page (lpage, 0);
  341.             display_page (rpage, 1);
  342.         }
  343.     }
  344.  
  345.     if (side == 3)
  346.         alternate_tray = 1;
  347.  
  348.     if ((side & 2)  &&  nhalves > 1)
  349.     {    second_side = 1;
  350.         for (rpage=nhalves/2, lpage=rpage-1; lpage >= 0; rpage+=2, lpage-=2)
  351.         {
  352.             display_page (lpage, 0);
  353.             display_page (rpage, 1);
  354.         }
  355.     }
  356. }
  357.  
  358. /****************************************************************************
  359. *    print double()                                                            *
  360. *    print double sided pages.  first odd numbered, then even numbered.        *
  361. ****************************************************************************/
  362.  
  363. print_double()
  364. {
  365.     nsheets = (npage+1)/2;
  366.     phys_page = 0;
  367.  
  368.     if (side & 1)
  369.     {    for (rpage=0;  rpage < nsheets;  rpage++)
  370.         {
  371.             display_page (rpage * 2, 0);
  372.         }
  373.     }
  374.  
  375.     if (side == 3)
  376.         alternate_tray = 1;
  377.  
  378.     if (side & 2  &&  npage > 1)
  379.     {    second_side = 1;
  380.         for (rpage=nsheets - 1;  rpage >= 0;  rpage--)
  381.         {
  382.             display_page (rpage * 2 + 1, 0);
  383.         }
  384.     }
  385. }
  386.  
  387.  
  388. tscan (s, t)        /* search for string t in s */
  389. char     s[], t[];
  390. {
  391.     int    i, j, k;
  392.     for (i = 0;  s[i] != '\0';  i++)
  393.     {    for (j = i, k=0;  t[k] != '\0'  &&  s[j] == t[k];  j++, k++)
  394.             ;
  395.         if (t[k] == '\0')
  396.             return (i);
  397.     }
  398.     return (-1);
  399. }
  400. usage ()
  401. {
  402.     printf ("Usage:  psd -n file\n");
  403.     printf ("  where:       n  = side number to print\n");
  404.     printf ("              -1 = print side 1 only\n");
  405.     printf ("              -2 = print side 2 only\n");
  406.     printf ("              -3 = print both sides in one pass\n");
  407.     printf ("           file   = print this file\n");
  408.     exit (0);
  409. }
  410.  
  411. trim (s)
  412. char    *s;
  413. {
  414.     while (*s)
  415.     {    if (*s < ' ')
  416.         {    *s = 0;
  417.             break;
  418.         }
  419.         s++;
  420.     }
  421. }
  422.