home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / general / fractal / kaos.lha / binsrclib / psraster.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-10-13  |  12.5 KB  |  490 lines

  1. /*
  2.  * Written by Leonid Rosenboim, Tel-Aviv University, Israel. This code is
  3.  * placed in Punlic Domain on Feb 1988. May be copied freely for any purpose.
  4.  */
  5.  
  6. static char     sccsid[] = "@(#)psraster.c    2.3   leonid@math.tau.ac.IL    88/06/16";
  7.  
  8. /*
  9.  * Standard rasterfile to PostScript filter.
  10.  */
  11.  
  12. #include <stdio.h>
  13. #include <math.h>
  14. #include <string.h>
  15. #include <sys/ioctl.h>
  16. #include <pixrect/pixrect_hs.h>
  17.  
  18. #define    INCH        * 72
  19. #define    PG_SIZE_X    ( 8.0 INCH )    /* Canvas is 7.5" x 9.5" area on a
  20.                      * 8x10.8" paper */
  21. #define    PG_SIZE_Y    ( 10.8 INCH )
  22. #define MAXBOX_X    ( 7.5 INCH )
  23. #define MAXBOX_Y    ( 9.0 INCH )
  24.  
  25. #ifndef DESTLIB
  26. #    define DESTLIB    "/usr/local/lib/ps"
  27. #endif    DESTLIB
  28.  
  29. #define PROLOGUE    "/psraster.ps"
  30. #define FALSE        0
  31. #define TRUE        !FALSE
  32.  
  33. #define    MAX_LINE    0x7f
  34. #define FLAG        0x80
  35. #define min(x,y)    (((x)<(y))?(x):(y))
  36. #define max(x,y)    (((x)<(y))?(y):(x))
  37.  
  38. #define    SERROR(err_message)    \
  39.     {(void)fprintf(stderr, "%s: %s\n", Progname, err_message); exit(1);}
  40.  
  41. #define ERR_RASTYPE    "Input raster has incorrect ras_type"
  42. #define ERR_MAPTYPE    "Input raster has incorrect ras_maptype"
  43. #define ERR_UNITS    "Unrecognized units code"
  44. #define MY_RAS_TYPE    RT_BYTE_ENCODED
  45.  
  46. struct box {            /* Bounding box structure, all in 1/72"
  47.                  * points */
  48.     short           size_x;
  49.     short           size_y;
  50.     short           off_x;
  51.     short           off_y;
  52. };
  53.  
  54. struct box      Canvas;        /* The drawing canvas, default almost the
  55.                  * whole page */
  56. struct box      Bounds;        /* The actual BoundingBox for image */
  57.  
  58. extern int      pr_load_colormap(), pr_load_header();
  59. extern struct pixrect *pr_load_std_image();
  60. extern double 
  61. atof(), strtod();
  62.  
  63. FILE           *infile, *outfile;
  64.  
  65. char           *file_name;    /* Input filename or stdin */
  66. char           *Progname;    /* Program Name for error message generation */
  67. unsigned char  *greymap;    /* Grey level map */
  68.  
  69. /* Program behaviour modifiers */
  70. int             flg_inverse = 0;/* Weather the program must perform negation */
  71. int             flg_square = 0;    /* Put the image in a sqare */
  72. int             flg_portrait = 0;    /* Force Posrtait Mode */
  73. int             flg_landscape = 0;    /* Force Landscape Mode */
  74. int             flg_noshow = 0;    /* Supress showpage */
  75. int             flg_nogrey = 0;    /* Supress grey level calculation */
  76. float           opt_scale = 0.;    /* Scaling Factor */
  77.  
  78. /*
  79.  * Translate a string from inches/centimeters/points to points.
  80.  */
  81. double
  82. points(s)
  83.     char           *s;
  84. {
  85.     double          v;
  86.     char           *p = s;
  87.  
  88.     v = strtod(s, &p);
  89.     if ((p == NULL))
  90.         return (v);
  91.     switch (*--p) {
  92.     case 'c':
  93.         v *= (1 / 2.54);
  94.     case 'i':
  95.         v *= 72;
  96.     case 'p':
  97.     case '\0':
  98.     case '0':
  99.         break;
  100.     default:
  101.         SERROR(ERR_UNITS);
  102.     }
  103.     return (v);
  104. }
  105.  
  106. main(argc, argv)
  107.     int             argc;
  108.     char          **argv;
  109. {
  110.     extern char    *optarg;
  111.     extern int      optind;
  112.     int             c;
  113.     /* Initialize default Canvas */
  114.     Canvas.size_x = MAXBOX_X;
  115.     Canvas.size_y = MAXBOX_Y;
  116.     Canvas.off_x = -1;
  117.     Canvas.off_y = -1;
  118.  
  119.  
  120.     for (; optind < argc; optind++) {
  121.  
  122.         /*
  123.          * Process argc/argv.
  124.          */
  125.         Progname = argv[0];
  126.         while ((c = getopt(argc, argv, "plisnx:y:X:Y:z:")) != EOF)
  127.             switch (c) {
  128.             case 'i':
  129.                 flg_inverse++;
  130.                 break;
  131.             case 's':
  132.                 flg_square++;
  133.                 break;
  134.             case 'p':
  135.                 flg_portrait++;
  136.                 break;
  137.             case 'l':
  138.                 flg_landscape++;
  139.                 break;
  140.             case 'n':
  141.                 flg_noshow++;
  142.                 break;
  143.             case 'z':
  144.                 opt_scale = atof(optarg);
  145.                 break;
  146.             case 'x':
  147.                 Canvas.off_x = points(optarg);
  148.                 break;
  149.             case 'y':
  150.                 Canvas.off_y = points(optarg);
  151.                 break;
  152.             case 'X':
  153.                 Canvas.size_x = points(optarg);
  154.                 break;
  155.             case 'Y':
  156.                 Canvas.size_y = points(optarg);
  157.                 break;
  158.             }
  159.  
  160.         /* Center the canvas on the page */
  161.         if (Canvas.off_x == -1)
  162.             Canvas.off_x = (PG_SIZE_X - Canvas.size_x) / 2;
  163.         if (Canvas.off_y == -1)
  164.             Canvas.off_y = (PG_SIZE_Y - Canvas.size_y) / 2;
  165.  
  166.         outfile = stdout;
  167.  
  168.         if (optind == argc) {
  169.             file_name = "Standard Input";
  170.             load(stdin);
  171.         } else {
  172.             if ((infile = fopen(argv[optind], "r")) == NULL) {
  173.                 perror(argv[optind]);
  174.                 continue;
  175.             }
  176.             file_name = argv[optind];
  177.             load(infile);
  178.         }
  179.         flg_square = flg_portrait = flg_landscape = flg_noshow = 0;
  180.         opt_scale = 0;
  181.         Canvas.size_x = MAXBOX_X;
  182.         Canvas.size_y = MAXBOX_Y;
  183.         Canvas.off_x = -1;
  184.         Canvas.off_y = -1;
  185.  
  186.     }
  187. }
  188.  
  189. /*
  190.  * Process each raster file passed as argument, but make sure that the
  191.  * prologue is written only once. Here we load the raster image and call
  192.  * another routine to do the job.
  193.  */
  194.  
  195. load(infile)
  196.     FILE           *infile;
  197. {
  198.     extern char    *malloc();
  199. #define    MALLOC(size)    (unsigned char *)malloc((unsigned int)(size))
  200.     struct pixrect *input_pr;
  201.     struct rasterfile rh;
  202.     colormap_t      colormap;
  203.  
  204.     /*
  205.      * Load the rasterfile header and the colormap (if there is one).
  206.      * Also perform a few sanity checks on the rasterfile.
  207.      */
  208.     if (pr_load_header(infile, &rh) == PIX_ERR)
  209.         SERROR(PR_IO_ERR_RASREAD);
  210.     switch (colormap.type = rh.ras_maptype) {
  211.     case RMT_NONE:
  212.         greymap = NULL;
  213.         break;
  214.     case RMT_EQUAL_RGB:
  215.         colormap.length = rh.ras_maplength / 3;
  216.         colormap.map[0] = MALLOC(colormap.length);
  217.         colormap.map[1] = MALLOC(colormap.length);
  218.         colormap.map[2] = MALLOC(colormap.length);
  219.         greymap = MALLOC(colormap.length);
  220.         if (pr_load_colormap(infile, &rh, &colormap) == PIX_ERR)
  221.             SERROR(PR_IO_ERR_RASREAD);
  222.         if (!flg_nogrey) {
  223.             register        i;
  224.             for (i = 0; i < colormap.length; i++)
  225.                 greymap[i] = (unsigned char)
  226.                     rint(sqrt((
  227.                       pow((double) colormap.map[0][i], 2.) +
  228.                       pow((double) colormap.map[1][i], 2.) +
  229.                 pow((double) colormap.map[2][i], 2.)) / 3.));
  230.         }
  231.         break;
  232.     default:
  233.         SERROR(ERR_MAPTYPE);
  234.     }
  235.     /*
  236.      * If the rasterfile is a standard type, use pr_load_std_image to
  237.      * read the image. If the rasterfile is non-standard type, use an
  238.      * appropriate routine to read the image (for RT_BYTE_ENCODED, this
  239.      * turns out to also be pr_load_std_image). In either case, transform
  240.      * the input to the other type and output it.
  241.      */
  242.     switch (rh.ras_type) {
  243.     case RT_STANDARD:
  244.         if ((input_pr = pr_load_std_image(infile, &rh)) == NULL)
  245.             SERROR(PR_IO_ERR_RASREAD);
  246.  
  247.         dump(input_pr);
  248.         break;
  249.     case MY_RAS_TYPE:
  250.         if ((input_pr = pr_load_std_image(infile, &rh)) == NULL)
  251.             SERROR(PR_IO_ERR_RASREAD);
  252.  
  253.         dump(input_pr);
  254.         break;
  255.     default:
  256.         SERROR(ERR_RASTYPE);
  257.     }
  258. }
  259.  
  260. /*
  261.  * This is the main procedure which dumps a raster it receives as argument on
  262.  * the output in PostScript format. Routimes below are used for assist
  263.  */
  264.  
  265. dump(pr)
  266.     struct pixrect *pr;
  267. {
  268.     register int    br, br1;/* Bytes per raw */
  269.     struct mpr_data *mpr = (struct mpr_data *) pr->pr_data;
  270.     register unsigned char *p;
  271.     register        x, y;
  272.  
  273.     /*
  274.      * Compute the number of bytes per row : Here we have a slight
  275.      * problem - rasterfile(5) number of bytes for each pixel row is
  276.      * rounded to short, but in PostScript it must be rounded to 1 byte.
  277.      * Hence, br is assigned the byte-pre-row from the input raster, and
  278.      * br1 will have the correct value for PostScript.
  279.      */
  280.  
  281.     br = mpr->md_linebytes;
  282.     br1 = (pr->pr_size.x * pr->pr_depth - 1) / 8 + 1;
  283.     if ((br != br1) && ((br - br1) != 1))
  284.         (void) fprintf(stderr, "Warning: Bytes per line %d -> %d\n", br, br1);
  285.  
  286.     put_prologue(pr, br1);
  287.  
  288.     /* Start of memory image itself */
  289.     p = (unsigned char *) mpr->md_image;
  290.  
  291.     for (y = 0; y < pr->pr_size.y; y++) {
  292.         if (greymap != NULL)
  293.             for (x = 0; x < br1; x++)
  294.                 p[x] = greymap[p[x]];
  295.         put_line(p, br1);
  296.         p += br;
  297.     }
  298.     if (!flg_noshow)
  299.         (void) fprintf(outfile, "showpage\n");
  300.     (void) fprintf(outfile, "grestore\n");
  301. }
  302.  
  303. /*
  304.  * Write the PostScript prologue, the constant and the variable parts. The
  305.  * variable part is output for each image, and the appropriate
  306.  * transformations are calculated.
  307.  */
  308.  
  309. put_prologue(pr, br)
  310.     struct pixrect *pr;
  311.     int             br;
  312. {
  313.     static int      count = 0;    /* Image counter */
  314.     float           cv_aspect, im_aspect;    /* Canvas and image aspect
  315.                          * ratios */
  316.     int             x_size, y_size;
  317.  
  318.     /* Write the constant prologue */
  319.     if (count == 0)
  320.         get_prologue();
  321.     count++;
  322.  
  323.     (void) fprintf(outfile, "gsave\n");
  324.     (void) fprintf(outfile, "%%Rasterfile Image: %s\n", file_name);
  325.     (void) fprintf(outfile, "%%Format:%d width %d hight %d depth\n",
  326.                pr->pr_size.x, pr->pr_size.y, pr->pr_depth);
  327.  
  328.     /* Calculate aspect ratios ( y / x ) */
  329.     cv_aspect = (float) Canvas.size_y / (float) Canvas.size_x;
  330.     im_aspect = (float) pr->pr_size.y / (float) pr->pr_size.x;
  331.  
  332.     /* Decide weather to use Portrait or Landscape mode */
  333.     if (flg_portrait == flg_landscape) {
  334.         /*
  335.          * Here we dont make any assumption as to the canvas
  336.          * dimentions since it may be arbitratily set by the user
  337.          */
  338.         if ((cv_aspect > 1) && (im_aspect > 1) ||
  339.             (cv_aspect < 1) && (im_aspect < 1))
  340.             flg_portrait = TRUE;
  341.         else
  342.             flg_portrait = FALSE;
  343.         flg_landscape = !flg_portrait;
  344.     }
  345.     if (flg_landscape) {
  346.         x_size = pr->pr_size.y;
  347.         y_size = pr->pr_size.x;
  348.     } else {
  349.         x_size = pr->pr_size.x;
  350.         y_size = pr->pr_size.y;
  351.     }
  352.  
  353.     /* Now we'll handle the scaling factor */
  354.  
  355.     if (opt_scale == 0.) {
  356.         opt_scale = min((float) Canvas.size_x / (float) x_size,
  357.                 (float) Canvas.size_y / (float) y_size);
  358.     }
  359.     /* Fill in the Bounds structure */
  360.     Bounds.size_x = (float) x_size *opt_scale;
  361.     Bounds.size_y = (float) y_size *opt_scale;
  362.     Bounds.off_x = Canvas.off_x + (Canvas.size_x - Bounds.size_x) / 2;
  363.     Bounds.off_y = Canvas.off_y + (Canvas.size_y - Bounds.size_y) / 2;
  364.  
  365.     if (flg_square) {    /* But if aspect ratio is to be ignored we'll
  366.                  * use a trivial formula */
  367.         Bounds = Canvas;
  368.     }
  369. #ifdef DEBUG
  370.     (void) fprintf(stderr, "Drawing %s in %s mode, with scaling of %f\n",
  371.        file_name, (flg_portrait) ? "portrait" : "landscape", opt_scale);
  372.     (void) fprintf(stderr, "Canvas size %d %d, offset %d %d\n",
  373.           Canvas.size_x, Canvas.size_y, Canvas.off_x, Canvas.off_y);
  374.     (void) fprintf(stderr, "Image size %d %d, offset %d %d\n",
  375.           Bounds.size_x, Bounds.size_y, Bounds.off_x, Bounds.off_y);
  376. #endif
  377.     (void) fprintf(outfile, "%%%%BoundingBox [ %d %d %d %d ]\n",
  378.                Bounds.off_x, Bounds.off_y,
  379.                Bounds.off_x + Bounds.size_x,
  380.                Bounds.off_y + Bounds.size_y);
  381.  
  382.     if (flg_portrait) {
  383.         (void) fprintf(outfile, "%%%% Using Portrait mode\n");
  384.         (void) fprintf(outfile, "%d %d translate %d %d scale\n",
  385.                    Bounds.off_x, Bounds.off_y,
  386.                    Bounds.size_x, Bounds.size_y);
  387.     } else {
  388.         (void) fprintf(outfile, "%%%% Using Landscape mode\n");
  389.         (void) fprintf(outfile, "%d %d translate -90 rotate %d %d scale\n",
  390.                    Bounds.off_x, Bounds.off_y + Bounds.size_y,
  391.                    Bounds.size_y, Bounds.size_x);
  392.     }
  393.  
  394.     if (flg_inverse)
  395.         (void) fprintf(outfile, "{1 exch sub} settransfer    ");
  396.  
  397.     (void) fprintf(outfile, "\n");
  398.     (void) fprintf(outfile, "/picst %d string def \n", br);
  399.     /* Dimensions */
  400.     (void) fprintf(outfile, "%d %d %d \n",
  401.                pr->pr_size.x, pr->pr_size.y, pr->pr_depth);
  402.     /* Unit array */
  403.     (void) fprintf(outfile, "[ %d 0 0 -%d 0 %d ]\n",
  404.                pr->pr_size.x, pr->pr_size.y, pr->pr_size.y);
  405.     /* Call Image */
  406.     (void) fprintf(outfile, "{GetImageRow} image\n");
  407. }
  408.  
  409. /*
  410.  * Output a single pixel row in the encoded hexa format. Here is the format
  411.  * description:
  412.  * 
  413.  * Each output line consistes of a record that starts with one hexa byte C and
  414.  * eands with a newline. if C > 0, then following will be C hexa bytes of
  415.  * data. if C < 0, if will be followed by one hexa byte which must be
  416.  * repeated (-C) times.
  417.  */
  418. put_line(p, br)
  419.     unsigned char  *p;
  420.     int             br;
  421. {
  422.     register        i;
  423.     register unsigned char *q;
  424.  
  425.     while (br) {
  426.         for (q = p, i = 0; i < min(MAX_LINE, br); i++, q++)
  427.             if (rep_count(q, (int) 6) > 5)
  428.                 break;
  429.  
  430.         if (i != 0) {
  431.             br -= i;
  432.             (void) fprintf(outfile, "%02x", (unsigned char) i);
  433.             for (; i; i--)
  434.                 (void) fprintf(outfile, "%02x", (unsigned char) *p++);
  435.         } else {
  436.             i = rep_count(p, br);
  437.             i = min(i, min(MAX_LINE, br));
  438.             (void) fprintf(outfile, "%02x", (unsigned char) (i | FLAG));
  439.             (void) fprintf(outfile, "%02x", (unsigned char) *p);
  440.             p += i;
  441.             br -= i;
  442.         }
  443.         (void) fprintf(outfile, "\n");
  444.     }
  445. }
  446.  
  447. /*
  448.  * Count the number of repeated bytes starting at *p. Search is mimmited to n
  449.  * subsequent bytes.
  450.  */
  451. int
  452. rep_count(p, n)
  453.     unsigned char  *p;
  454.     int             n;
  455. {
  456.     register        i;
  457.     register char unsigned  c;
  458.     if (((c = *p) != *(p + 1)) || (c != *(p + 2)))
  459.         return (0);
  460.     for (i = 0; (c == *p) && (i < n); i++, p++);
  461.     return (i);
  462. }
  463.  
  464. /*
  465.  * Print the invariable part of the PostScript prologue.
  466.  */
  467. get_prologue()
  468. {
  469.     FILE           *pro;
  470.     char            buffer[BUFSIZ];
  471.     int             c;
  472.  
  473.     (void) strcpy(buffer, DESTLIB);
  474.     (void) strcat(buffer, PROLOGUE);
  475.  
  476.     pro = fopen(buffer, "r");
  477.     if (pro == NULL) {
  478.         perror(buffer);
  479.         exit(1);
  480.     }
  481.     (void) fprintf(outfile, "%%!\n%%%%Generated by %s version %s\n",
  482.                Progname, sccsid);
  483.  
  484.     c = fread(buffer, 1, sizeof(buffer), pro);
  485.     for (; c > 0;) {
  486.         (void) fwrite(buffer, 1, c, outfile);
  487.         c = fread(buffer, 1, sizeof(buffer), pro);
  488.     }
  489. }
  490.