home *** CD-ROM | disk | FTP | other *** search
/ Mega Top 1 / os2_top1.zip / os2_top1 / APPS / TEKST / PSUTILS / PSNUP.C < prev    next >
C/C++ Source or Header  |  1993-11-29  |  9KB  |  323 lines

  1. /* psnup.c
  2.  * AJCD 4/6/93
  3.  * put multiple pages onto one physical sheet of paper
  4.  *
  5.  * Usage:
  6.  *      psnup [-q] [-w<dim>] [-h<dim>] [-ppaper] [-b<dim>] [-m<dim>]
  7.  *            [-l] [-c] [-f] [-sscale] [-d<wid>] [-nup] [in [out]]
  8.  *              -w<dim> sets the paper width
  9.  *              -h<dim> sets the paper height
  10.  *              -ppaper sets the paper size (width and height) by name
  11.  *              -m<dim> sets the margin around the paper
  12.  *              -b<dim> sets the border around each page
  13.  *              -sscale alters the scale at which the pages are displayed
  14.  *              -l      used if pages are in landscape orientation (rot left)
  15.  *              -r      used if pages are in seascape orientation (rot right)
  16.  *         -c    for column-major layout
  17.  *        -f    for flipped (wider than tall) pages
  18.  *         -d<wid>    to draw the page boundaries
  19.  */
  20.  
  21. #include "psutil.h"
  22. #include "psspec.h"
  23. #include "patchlev.h"
  24.  
  25. void usage()
  26. {
  27.    fprintf(stderr, "%s release %d patchlevel %d\n", prog, RELEASE, PATCHLEVEL);
  28.    fprintf(stderr, "Usage: %s [-q] [-wwidth] [-hheight] [-ppaper] [-l] [-r] [-c] [-f] [-mmargin] [-bborder] [-dlwidth] [-sscale] [-nup] [infile [outfile]]\n",
  29.        prog);
  30.    fflush(stderr);
  31.    exit(1);
  32. }
  33.  
  34. void argerror()
  35. {
  36.    fprintf(stderr, "%s: bad dimension\n", prog);
  37.    fflush(stderr);
  38.    exit(1);
  39. }
  40.  
  41. #define min(x,y) ((x) > (y) ? (y) : (x))
  42. #define max(x,y) ((x) > (y) ? (x) : (y))
  43.  
  44. /* return next larger exact divisor of number, or 0 if none. There is probably
  45.  * a much more efficient method of doing this, but the numbers involved are
  46.  * small, so it's not a big loss. */
  47. int nextdiv(n, m)
  48.      int n, m;
  49. {
  50.    while (++n <= m) {
  51.       if (m%n == 0)
  52.      return (n);
  53.    }
  54.    return (0);
  55. }
  56.  
  57. main(argc, argv)
  58.      int argc;
  59.      char *argv[];
  60. {
  61.    int horiz, vert, rotate, column, flip, leftright, topbottom;
  62.    int nup = 1;
  63.    double draw = 0;                /* draw page borders */
  64.    double scale;                /* page scale */
  65.    double uscale = 0;                /* user supplied scale */
  66.    double ppwid, pphgt;                /* paper dimensions */
  67.    double margin, border;            /* paper & page margins */
  68.    double vshift, hshift;            /* page centring shifts */
  69.    double tolerance = 100000;            /* layout tolerance */
  70.    struct papersize *paper;
  71.  
  72. #ifdef PAPER
  73.    if (paper = findpaper(PAPER)) {
  74.       width = (double)paper->width;
  75.       height = (double)paper->height;
  76.    }
  77. #endif
  78.  
  79.    margin = border = vshift = hshift = column = flip = 0;
  80.    leftright = topbottom = 1;
  81.  
  82.    infile = stdin;
  83.    outfile = stdout;
  84.    verbose = 1;
  85.    for (prog = *argv++; --argc; argv++) {
  86.       if (argv[0][0] == '-') {
  87.      switch (argv[0][1]) {
  88.      case 'q':    /* quiet */
  89.         verbose = 0;
  90.         break;
  91.      case 'd':    /* draw borders */
  92.         if (argv[0][2])
  93.            draw = singledimen(*argv+2);
  94.         else
  95.            draw = 1;
  96.         break;
  97.      case 'l':    /* landscape (rotated left) */
  98.         column = !column;
  99.         topbottom = !topbottom;
  100.         break;
  101.      case 'r':    /* seascape (rotated right) */
  102.         column = !column;
  103.         leftright = !leftright;
  104.         break;
  105.      case 'f':    /* flipped */
  106.         flip = 1;
  107.         break;
  108.      case 'c':    /* column major layout */
  109.         column = !column;
  110.         break;
  111.      case 'w':    /* page width */
  112.         width = singledimen(*argv+2);
  113.         break;
  114.      case 'h':    /* page height */
  115.         height = singledimen(*argv+2);
  116.         break;
  117.      case 'm':    /* margins around whole page */
  118.         margin = singledimen(*argv+2);
  119.         break;
  120.      case 'b':    /* border around individual pages */
  121.         border = singledimen(*argv+2);
  122.         break;
  123.      case 't':    /* layout tolerance */
  124.         tolerance = atof(*argv+2);
  125.         break;
  126.      case 's':    /* override scale */
  127.         uscale = atof(*argv+2);
  128.         break;
  129.      case 'p':    /* paper type */
  130.         if (paper = findpaper(*argv+2)) {
  131.            width = (double)paper->width;
  132.            height = (double)paper->height;
  133.         } else {
  134.            fprintf(stderr, "%s: paper size '%s' not recognised\n",
  135.                prog, *argv+2);
  136.            fflush(stderr);
  137.            exit(1);
  138.         }
  139.         break;
  140.      case 'n':    /* n-up, for compatibility with other psnups */
  141.         if (argc >= 2) {
  142.            argv++;
  143.            argc--;
  144.            if ((nup = atoi(*argv)) < 1) {
  145.           fprintf(stderr, "%s: -n %d too small\n", prog, nup);
  146.           fflush(stderr);
  147.           exit(1);
  148.            }
  149.         } else {
  150.            fprintf(stderr, "%s: argument expected for -n\n", prog);
  151.            fflush(stderr);
  152.            exit(1);
  153.         }
  154.         break;
  155.      case '1':
  156.      case '2':
  157.      case '3':
  158.      case '4':
  159.      case '5':
  160.      case '6':
  161.      case '7':
  162.      case '8':
  163.      case '9':
  164.         nup = atoi(*argv+1);
  165.         break;
  166.      case 'v':    /* version */
  167.      default:
  168.         usage();
  169.      }
  170.       } else if (infile == stdin) {
  171.      if ((infile = fopen(*argv, "r")) == NULL) {
  172.         fprintf(stderr, "%s: can't open input file %s\n", prog, *argv);
  173.         fflush(stderr);
  174.         exit(1);
  175.      }
  176.       } else if (outfile == stdout) {
  177.      if ((outfile = fopen(*argv, "w")) == NULL) {
  178.         fprintf(stderr, "%s: can't open output file %s\n", prog, *argv);
  179.         fflush(stderr);
  180.         exit(1);
  181.      }
  182.       } else usage();
  183.    }
  184.    if ((infile=seekable(infile))==NULL) {
  185.       fprintf(stderr, "%s: can't seek input\n", prog);
  186.       fflush(stderr);
  187.       exit(1);
  188.    }
  189.  
  190.    if (width <= 0 || height <= 0) {
  191.       fprintf(stderr, "%s: page width and height must be set\n", prog);
  192.       fflush(stderr);
  193.       exit(1);
  194.    }
  195.  
  196.    /* subtract paper margins from height & width */
  197.    ppwid = width - margin*2;
  198.    pphgt = height - margin*2;
  199.  
  200.    if (ppwid <= 0 || pphgt <= 0) {
  201.       fprintf(stderr, "%s: paper margins are too large\n", prog);
  202.       fflush(stderr);
  203.       exit(1);
  204.    }
  205.  
  206.    /* Finding the best layout is an optimisation problem. We try all of the
  207.     * combinations of width*height in both normal and rotated form, and
  208.     * minimise the wasted space. */
  209.    {
  210.       double best = tolerance;
  211.       int hor;
  212.       for (hor = 1; hor; hor = nextdiv(hor, nup)) {
  213.      int ver = nup/hor;
  214.      /* try normal orientation first */
  215.      double scl = min(pphgt/(height*ver), ppwid/(width*hor));
  216.      double optim = (ppwid-scl*width*hor)*(ppwid-scl*width*hor) +
  217.         (pphgt-scl*height*ver)*(pphgt-scl*height*ver);
  218.      if (optim < best) {
  219.         best = optim;
  220.         /* recalculate scale to allow for internal borders */
  221.         scale = min((pphgt-2*border*ver)/(height*ver),
  222.             (ppwid-2*border*hor)/(width*hor));
  223.         hshift = (ppwid/hor - width*scale)/2;
  224.         vshift = (pphgt/ver - height*scale)/2;
  225.         horiz = hor; vert = ver;
  226.         rotate = flip;
  227.      }
  228.      /* try rotated orientation */
  229.      scl = min(pphgt/(width*hor), ppwid/(height*ver));
  230.      optim = (pphgt-scl*width*hor)*(pphgt-scl*width*hor) +
  231.         (ppwid-scl*height*ver)*(ppwid-scl*height*ver);
  232.      if (optim < best) {
  233.         best = optim;
  234.         /* recalculate scale to allow for internal borders */
  235.         scale = min((pphgt-2*border*hor)/(width*hor),
  236.             (ppwid-2*border*ver)/(height*ver));
  237.         hshift = (ppwid/ver - height*scale)/2;
  238.         vshift = (pphgt/hor - width*scale)/2;
  239.         horiz = ver; vert = hor;
  240.         rotate = !flip;
  241.      }
  242.       }
  243.  
  244.       /* fail if nothing better than worst tolerance was found */
  245.       if (best == tolerance) {
  246.      fprintf(stderr, "%s: can't find acceptable layout for %d-up\n",
  247.          prog, nup);
  248.      fflush(stderr);
  249.      exit(1);
  250.       }
  251.    }
  252.  
  253.    if (flip) {    /* swap width & height for clipping */
  254.       double tmp = width;
  255.       width = height;
  256.       height = tmp;
  257.    }
  258.  
  259.    if (rotate) {    /* rotate leftright and topbottom orders */
  260.       int tmp = topbottom;
  261.       topbottom = !leftright;
  262.       leftright = tmp;
  263.       column = !column;
  264.    }
  265.  
  266.    /* now construct specification list and run page rearrangement procedure */
  267.    {
  268.       int page = 0;
  269.       struct pagespec *specs, *tail;
  270.  
  271.       tail = specs = newspec();
  272.  
  273.       while (page < nup) {
  274.      int up, across;        /* page index */
  275.  
  276.      if (column) {
  277.         if (leftright)        /* left to right */
  278.            across = page/vert;
  279.         else            /* right to left */
  280.            across = horiz-1-page/vert;
  281.         if (topbottom)        /* top to bottom */
  282.            up = vert-1-page%vert;
  283.         else            /* bottom to top */
  284.            up = page%vert;
  285.      } else {
  286.         if (leftright)        /* left to right */
  287.            across = page%horiz;
  288.         else            /* right to left */
  289.            across = horiz-1-page%horiz;
  290.         if (topbottom)        /* top to bottom */
  291.            up = vert-1-page/horiz;
  292.         else            /* bottom to top */
  293.            up = page/horiz;
  294.      }
  295.      if (rotate) {
  296.         tail->xoff = margin + (across+1)*ppwid/horiz - hshift;
  297.         tail->rotate = 90;
  298.         tail->flags |= ROTATE;
  299.      } else {
  300.         tail->xoff = margin + across*ppwid/horiz + hshift;
  301.      }
  302.      tail->pageno = page;
  303.      if (uscale > 0)
  304.         tail->scale = uscale;
  305.      else
  306.         tail->scale = scale;
  307.      tail->flags |= SCALE;
  308.      tail->yoff = margin + up*pphgt/vert + vshift;
  309.      tail->flags |= OFFSET;
  310.      if (++page < nup) {
  311.         tail->flags |= ADD_NEXT;
  312.         tail->next = newspec();
  313.         tail = tail->next;
  314.      }
  315.       }
  316.       
  317.       pstops(nup, 1, 0, specs, draw);        /* do page rearrangement */
  318.    }
  319.  
  320.    exit(0);
  321. }
  322.  
  323.