home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / X / mit / clients / xpr / x2jet.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-06-26  |  41.9 KB  |  1,549 lines

  1. /* $XConsortium: x2jet.c,v 1.5 91/06/26 13:59:00 rws Exp $ */
  2.  
  3. /* -*-C-*-
  4. ********************************************************************************
  5. *
  6. * File:         x2jet.c
  7. * RCS:          x2jet.c,v 1.23 89/07/17 12:02:51 lori Exp
  8. * Description:  xpr support for HP LaserJet and PaintJet printers
  9. * Author:       Larry Rupp, HP Graphics Technology Division
  10. * Created:      Fri Jul 15 15:22:26 1988
  11. * Modified:     Thu Sep 15 11:59:34 1988 (Larry Rupp) ler@hpfcler
  12. *               Tue Dec  6 10:04:43 PST 1988 (Marc Ayotte) marca@hp-pcd
  13. * Language:     C
  14. * Package:      N/A
  15. * Status:       Released to MIT
  16. *
  17. * (c) Copyright 1988, Hewlett-Packard Company.
  18. *
  19. ********************************************************************************
  20. */
  21.  
  22.  
  23.  
  24.  
  25.  
  26. /********************************************************
  27.  
  28. Copyright (c) 1988 by Hewlett-Packard Company
  29. Copyright (c) 1988 by the Massachusetts Institute of Technology
  30.  
  31. Permission to use, copy, modify, and distribute this software 
  32. and its documentation for any purpose and without fee is hereby 
  33. granted, provided that the above copyright notice appear in all 
  34. copies and that both that copyright notice and this permission 
  35. notice appear in supporting documentation, and that the names of 
  36. Hewlett-Packard or  M.I.T.  not be used in advertising or publicity 
  37. pertaining to distribution of the software without specific, written 
  38. prior permission.
  39.  
  40. ********************************************************/
  41.  
  42. #include <stdio.h>
  43. #include <X11/Xlib.h>
  44. #include <X11/XWDFile.h>
  45.  
  46. #include "xpr.h"
  47.  
  48. #ifdef  NLS16
  49. #ifndef NLS
  50. #define    NLS
  51. #endif
  52. #endif
  53.  
  54. #ifndef NLS
  55. #define catgets(i, sn,mn,s) (s)
  56. #else /* NLS */
  57. #define NL_SETN 2    /* set number */
  58. #include <nl_types.h>
  59.  
  60. extern  char *catgets();
  61. extern    nl_catd    nlmsg_fd;
  62.  
  63. #endif /* NLS */
  64.  
  65. #ifndef    TRUE
  66. #  define    FALSE    0
  67. #  define    TRUE    1
  68. #endif
  69.  
  70. /* default printable page area (inches) */
  71. #define STDWIDTH 8.0
  72. #define STDHEIGHT 10.5
  73.  
  74. /* header & trailer character cell size (centipoints) */
  75. #define CHARWIDTH 720
  76. #define CHARHEIGHT 1200
  77.  
  78. #define XWDHEADERSIZE    (sizeof(XWDFileHeader))
  79. #define XCOLORSIZE      (sizeof(XColor))
  80.  
  81.  
  82. typedef struct { long width, height; } Area;
  83. typedef struct { long x, y; } Location;
  84.  
  85.  
  86. static Area limit;    /* image clip limits (dots) */
  87. static Area page;    /* printable page size (centipoints) */
  88.  
  89. static Location headerloc;    /* centipoint location of header string */
  90. static Location trailerloc;    /* centipoint location of trailer string */
  91. static Location imageloc;    /* centipoint location of image */
  92.  
  93. static int headerlimit;        /* number of chars which will printed for */
  94. static int trailerlimit;    /*  the image's header/trailer strings    */
  95.  
  96. static XWDFileHeader xwd_header;
  97.  
  98. static XColor *xwd_colors;
  99.  
  100. static char *xwd_image;
  101.  
  102. static unsigned long Z_pixel_mask;
  103.  
  104. static int true_scale;
  105.  
  106. extern    char    *progname;
  107.  
  108. void fatal_err();
  109. void fatal_err2();
  110.  
  111. /* Computes the centipoint width of one printer dot. */
  112. #define dot_centipoints(s,d)    ((7200.0 * s) / d)
  113.  
  114.  
  115. void set_image_limits (scale, density, orient, print_area)
  116. int scale, density;
  117. enum orientation orient;
  118. Area print_area;
  119. {
  120.   Area print_dots;
  121.   double dotsize;
  122.  
  123.   /* Set dotsize to the centipoint width of one printer dot. */
  124.   dotsize = dot_centipoints(scale, density);
  125.  
  126.   if (orient == PORTRAIT) {
  127.     print_dots.width = print_area.width / dotsize;
  128.     print_dots.height = print_area.height / dotsize;
  129.   } else {
  130.     print_dots.height = print_area.width / dotsize;
  131.     print_dots.width = print_area.height / dotsize;
  132.   }
  133.  
  134.   limit.width = (print_dots.width < xwd_header.pixmap_width)
  135.         ? print_dots.width : xwd_header.pixmap_width;
  136.   limit.height = (print_dots.height < xwd_header.pixmap_height)
  137.         ? print_dots.height : xwd_header.pixmap_height;
  138.  
  139.   if ((limit.width != xwd_header.pixmap_width)
  140.       || (limit.height != xwd_header.pixmap_height))
  141.     fprintf(stderr,(catgets(nlmsg_fd,NL_SETN,1, "%s: Warning: %ld x %ld image clipped to %ld x %ld.\n")),
  142.         progname,
  143.         xwd_header.pixmap_width, xwd_header.pixmap_height,
  144.         limit.width, limit.height);
  145. }
  146.  
  147.  
  148.  
  149. void set_header_trailer_limits (header, trailer, printwidth)
  150. char *header, *trailer;
  151. long printwidth;
  152. {
  153.   /* Determine the number of header and trailer characters
  154.    * that will fit into the available printing area.
  155.    */
  156.   headerlimit = header ? (((strlen(header) * CHARWIDTH) <= printwidth)
  157.               ? strlen(header) : (printwidth / CHARWIDTH))
  158.                : 0;
  159.   if (header && headerlimit != strlen(header)) {
  160.     fprintf(stderr,(catgets(nlmsg_fd,NL_SETN,2,
  161.         "%s: Warning: Header string clipped to %d characters.\n")),
  162.         progname, headerlimit);
  163.     header[headerlimit] = '\0';
  164.   }
  165.  
  166.   trailerlimit = trailer ? (((strlen(trailer) * CHARWIDTH) <= printwidth)
  167.                 ? strlen(trailer) : (printwidth / CHARWIDTH))
  168.              : 0;
  169.   if (trailer && trailerlimit != strlen(trailer)) {
  170.     fprintf(stderr,(catgets(nlmsg_fd,NL_SETN,3,
  171.         "%s: Warning: Trailer string clipped to %d characters.\n")),
  172.         progname, trailerlimit);
  173.     trailer[headerlimit] = '\0';
  174.   }
  175. }
  176.  
  177.  
  178. void set_print_locations (scale, density, top, left,
  179.               header, trailer, orient, position_on_page)
  180. int scale, density;
  181. int top, left;
  182. char *header, *trailer;
  183. enum orientation orient;
  184. int position_on_page;
  185. {
  186.   Area image;
  187.   double dotsize;
  188.  
  189.   /* Set dotsize to the centipoint width of one printer dot. */
  190.   dotsize = dot_centipoints(scale, density);
  191.  
  192.   /* Compute the centipoint size of the clipped image area. */
  193.   if (orient == PORTRAIT) {
  194.     image.width = limit.width * dotsize;
  195.     image.height = limit.height * dotsize;
  196.   } else {
  197.     image.height = limit.width * dotsize;
  198.     image.width = limit.height * dotsize;
  199.   }
  200.  
  201.   if (position_on_page) {
  202.     /* set vertical positions */
  203.     imageloc.y = (top >= 0)
  204.           ? top * 24 + ((header) ? CHARHEIGHT : 0)
  205.           : ((page.height - ((header) ? CHARHEIGHT : 0)
  206.           - image.height - ((trailer) ? CHARHEIGHT : 0)) / 2)
  207.         + ((header) ? CHARHEIGHT : 0);
  208.     headerloc.y = imageloc.y - CHARHEIGHT / 4;
  209.     trailerloc.y = imageloc.y + image.height + (3 * CHARHEIGHT) / 4;
  210.  
  211.     /* set horizontal positions */
  212.     if (left >= 0)
  213.       headerloc.x = imageloc.x = trailerloc.x = left * 24;
  214.     else {
  215.       headerloc.x = (page.width - headerlimit * CHARWIDTH) / 2;
  216.       imageloc.x = (page.width - image.width) / 2;
  217.       trailerloc.x = (page.width - trailerlimit * CHARWIDTH) / 2;
  218.     }
  219.   }
  220. }
  221.  
  222.  
  223. int scale_raster (density, orient, print_area)
  224. int density;
  225. enum orientation orient;
  226. Area print_area;
  227. {
  228.   Area image;
  229.   int h_scale, v_scale;
  230.  
  231.   /* Set the image dimensions to the number of centipoints that would be
  232.    * required for printing at the selected density.
  233.    */
  234.   if (orient == PORTRAIT) {
  235.     image.width = xwd_header.pixmap_width * 7200 / density;
  236.     image.height = xwd_header.pixmap_height * 7200 / density;
  237.   } else {
  238.     image.height = xwd_header.pixmap_width * 7200 / density;
  239.     image.width = xwd_header.pixmap_height * 7200 / density;
  240.   }
  241.  
  242.   /* Calculate the maximum image multiplier along
  243.    * the horizontal and vertical dimensions.
  244.    */
  245.   h_scale = print_area.width / image.width;
  246.   v_scale = print_area.height / image.height;
  247.  
  248.   /* If the image can be expanded, return the lesser of the horizontal and
  249.    * vertical multipliers.  Otherwise, the image will not completely fit
  250.    * the available print area, so just return 1 as the expansion factor.
  251.    */
  252.   return (((h_scale > 0) && (v_scale > 0))
  253.       ? ((h_scale<v_scale) ? h_scale : v_scale)
  254.       : 1);
  255. }
  256.  
  257.  
  258. scale_and_orient_image (scale, density, width, height, left, top,
  259.             header, trailer,
  260.             orient, position_on_page, device)
  261. int *scale, *density;
  262. int width, height, left, top;  /* in 300ths of an inch */
  263. char *header, *trailer;
  264. enum orientation *orient;
  265. int position_on_page;
  266. enum device device;
  267. {
  268.   Area usable;
  269.  
  270.   /* Determine printable area expressed in centipoints.  There are 7200
  271.    * centipoints to the inch.  The width and height parameters passed in
  272.    * are expressed in 300ths of an inch, therefore a 24x conversion factor
  273.    * is used on the parameter values.  The default page dimensions STDWIDTH
  274.    * and STDHEIGHT are expressed in inches so must be multiplied by 7200
  275.    * to convert to centipoints.
  276.    */
  277.   page.width = (width >= 0) ? width * 24 : STDWIDTH * 7200;
  278.   page.height = (height >= 0) ? height * 24 : STDHEIGHT * 7200;
  279.  
  280.   /* Paintjet Xl has a mechanical form feed, not a strip feed. It has
  281.    * a slop of about 1/4 to 1/2 of an inch at the top and bottom.
  282.    * deduct it from the page height.
  283.    */
  284.   if (device == PJETXL)
  285.      page.height = page.height - 7200;
  286.  
  287.   /* Determine the area usable for the image.  This area will be smaller
  288.    * than the total printable area if margins or header/trailer strings
  289.    * have been specified.  Margins, like width and height discussed above,
  290.    * are expressed in 300ths of an inch and must be converted to centipoints.
  291.    * Header and trailer strings each reduce the available image height
  292.    * by 1/6 inch, or 1200 centipoints (aka CHARHEIGHT).
  293.    */
  294.   usable.width = page.width - ((left > 0) ? (left * 24) : 0);
  295.   usable.height = page.height - ((top > 0) ? (top * 24) : 0)
  296.           - ((header) ? CHARHEIGHT : 0)
  297.           - ((trailer) ? CHARHEIGHT : 0);
  298.  
  299.   /* Quit here if there is no usable image space. */
  300.   if ((usable.width <= 0) || (usable.height <= 0)) {
  301.     fatal_err((catgets(nlmsg_fd,NL_SETN,4,
  302.                 "No space available on page for image.")));
  303.   }
  304.  
  305.   /* Determine image orientation.  The orientation will only be changed if
  306.    * it was not specified by a command line option.  Portrait mode will be
  307.    * used if either the usable printing area or the image area are square.
  308.    * Portrait mode will also be used if the long dimensions of the usable
  309.    * printing area and the image area match, otherwise landscape mode is
  310.    * used.  Portrait mode really means "don't rotate" and landscape mode
  311.    * means "rotate".
  312.    */
  313.   if (*orient == UNSPECIFIED) {
  314.     if ((usable.width == usable.height)
  315.     || (xwd_header.pixmap_width == xwd_header.pixmap_height))
  316.       *orient = PORTRAIT;
  317.     else
  318.       *orient = ((usable.width < usable.height)
  319.          == (xwd_header.pixmap_width < xwd_header.pixmap_height))
  320.     ? PORTRAIT : LANDSCAPE;
  321.   }
  322.  
  323.   /* Set the dots-per-inch print density if it was not specified */
  324.   if (*density <= 0) {
  325.     switch(device) {
  326.        case   LJET: *density = 300;
  327.                     break;
  328.        case   PJET: *density = 90;
  329.                     break;
  330.        case PJETXL: *density = 180;
  331.                     break;
  332.     }
  333.   }
  334.  
  335.   /* Fit image to available area if scale was not specified */
  336.   if (*scale <= 0)
  337.     *scale = scale_raster(*density, *orient, usable);
  338.  
  339.   /* Determine image clipping limits */
  340.   set_image_limits(*scale, *density, *orient, usable);
  341.  
  342.   /* Determine header/trailer string length clipping */
  343.   set_header_trailer_limits(header, trailer, usable.width);
  344.  
  345.   /* Calculate locations for page layout */
  346.   set_print_locations(*scale, *density, top, left,
  347.               header, trailer, *orient, position_on_page);
  348.  
  349. }
  350.  
  351.  
  352. unsigned short fullintensity;
  353.  
  354. #define BLACK 1
  355. #define WHITE 0
  356. #define EMPTY -1
  357. #define MAX_PJ_COLOR 16
  358.  
  359. #define RGBmatch(r,g,b,i)    (r == i) && (g == i) && (b == i)
  360.  
  361.  
  362. /* Colormap array is used to map from the Xcolor array (xwd_colors) index
  363.  * numbers into a pjcolor index number.  This style of mapping is done when
  364.  * interpreting non-Direct/TrueColor visual types.
  365.  */
  366. long *colormap;
  367.  
  368.  
  369. /* Pjcolor array is used to hold the scaled RGB triple values 
  370.  * programmed into the printer.
  371.  */
  372. long pjcolor[MAX_PJ_COLOR];
  373.  
  374.  
  375. static int color_warning_given = FALSE;
  376.  
  377.  
  378. /* Global visual type indicator, used to select color interpretation method. */
  379. char Direct_or_TrueColor;
  380.  
  381.  
  382. typedef struct {
  383.   unsigned long Rmask, Gmask, Bmask;
  384.   int Rshift, Gshift, Bshift;
  385. } RGBshiftmask;
  386.  
  387.  
  388. /* Color index element definition, these are linked into a circular list
  389.  * for interpretation of DirectColor or TrueColor visual types.
  390.  */
  391. typedef struct colorindex {
  392.   long index;
  393.   long pjcolor_index;
  394.   struct colorindex *next;
  395. } COLORINDEX;
  396.  
  397.  
  398. /* Global data for color interpretation.  This structure serves as a home
  399.  * for the color index lists (only used when processing DirectColor or
  400.  * TrueColor visual types).  It also holds color processing switches and a    
  401.  * pointer to the output file to reduce parameter passing overhead.
  402.  */
  403. struct {
  404.   int PaintJet;
  405.   int Invert;
  406.   unsigned int CutOff;
  407.   FILE *OutFile;
  408.   COLORINDEX *indexchain, *freechain;
  409.   RGBshiftmask sm;
  410. } color;
  411.  
  412.  
  413. void setup_RGBshiftmask (sm, rmask, gmask, bmask)
  414. RGBshiftmask *sm;
  415. unsigned long rmask, gmask, bmask;
  416. {
  417.   sm->Rmask = rmask;  sm->Gmask = gmask;  sm->Bmask = bmask;
  418.   sm->Rshift = 0;     sm->Gshift = 0;     sm->Bshift = 0;
  419.  
  420.   if (!rmask)
  421.     fatal_err((catgets(nlmsg_fd,NL_SETN,5, "red mask for visual is zero.")));
  422.   if (!gmask)
  423.     fatal_err((catgets(nlmsg_fd,NL_SETN,6, "green mask for visual is zero.")));
  424.   if (!bmask)
  425.     fatal_err((catgets(nlmsg_fd,NL_SETN,7, "blue mask for visual is zero.")));
  426.  
  427.   for (; !(rmask & 1); sm->Rshift++)
  428.     rmask >>= 1;
  429.   for (; !(gmask & 1); sm->Gshift++)
  430.     gmask >>= 1;
  431.   for (; !(bmask & 1); sm->Bshift++)
  432.     bmask >>= 1;
  433. }
  434.  
  435.  
  436.  
  437. void swap_black_and_white ()
  438. {
  439.   /* Reverse black and white in the Xcolor structure array. */
  440.  
  441.   XColor *color;
  442.   int n;
  443.  
  444.   for (n=xwd_header.ncolors, color=xwd_colors;  n>0;  n--, color++)
  445.     if (RGBmatch((color->red & fullintensity), (color->green & fullintensity),
  446.                 (color->blue & fullintensity), fullintensity))
  447.       color->red = color->green = color->blue = 0;
  448.     else if (RGBmatch(color->red, color->green, color->blue, 0))
  449.       color->red = color->green = color->blue = fullintensity;
  450. }
  451.  
  452.  
  453. void reset_color_mapping ()
  454. {
  455.   int n;
  456.   long *cmap;
  457.   COLORINDEX *splice;
  458.  
  459.   for (n=0; n<MAX_PJ_COLOR; n++)
  460.     pjcolor[n] = EMPTY;
  461.  
  462.   if (!color.PaintJet) {
  463.     /* preload for monochrome output */
  464.     pjcolor[0] = WHITE;
  465.     pjcolor[1] = BLACK;
  466.   }    
  467.  
  468.   if (Direct_or_TrueColor) {
  469.     /* move color index chain cells onto the free list */
  470.     if (color.indexchain != NULL) {
  471.       splice = color.indexchain->next;
  472.       color.indexchain->next = color.freechain;
  473.       color.freechain = splice;
  474.       color.indexchain = NULL;
  475.     }
  476.   } else if (color.PaintJet)
  477.     for (n=xwd_header.ncolors, cmap=colormap;  n>0;  n--, cmap++)
  478.       *cmap = EMPTY;
  479. }
  480.  
  481.  
  482. #define Intensity(r,g,b)    ((r) * 0.30 + (g) * 0.59 + (b) * 0.11)
  483.  
  484.  
  485. void prepare_color_mapping (invert, paintjet, cutoff, out)
  486. int invert, paintjet;
  487. unsigned int cutoff;
  488. FILE *out;
  489. {
  490.   int n;
  491.   long *cmap;
  492.   XColor *xcolor;
  493.  
  494.   for (n = xwd_header.bits_per_rgb, fullintensity = 0; n > 0; n--)
  495.      fullintensity = (fullintensity << 1) | 1;
  496.   for (n = sizeof(short) * 8 - xwd_header.bits_per_rgb; n > 0; n--)
  497.      fullintensity = (fullintensity << 1);
  498.      
  499.   Direct_or_TrueColor =  (xwd_header.visual_class == DirectColor
  500.               || xwd_header.visual_class == TrueColor);
  501.   color.PaintJet = paintjet;
  502.   color.Invert = invert;
  503.   color.CutOff = cutoff;
  504.   color.OutFile = out;
  505.   color.indexchain = NULL;
  506.   color.freechain = NULL;
  507.  
  508.   if (Direct_or_TrueColor)
  509.     setup_RGBshiftmask(&color.sm, xwd_header.red_mask,
  510.                xwd_header.green_mask, xwd_header.blue_mask);
  511.   else {
  512.     if (!(colormap = (long *) malloc(xwd_header.ncolors * sizeof(long))))
  513.       fatal_err((catgets(nlmsg_fd,NL_SETN,24,
  514.         "Could not allocate memory for X-to-printer colormap.")));
  515.  
  516.     /* For PaintJet, color map assignment will be done one line at a time.
  517.      * So for now just interchange the Xcolor structure's black and white
  518.      * if the -rv command line option was specified.
  519.      */
  520.     if (paintjet && invert)
  521.       swap_black_and_white();
  522.  
  523.     /* For LaserJet, map each color to black or white based upon the
  524.      * combined intensity of the RGB components.  Note that the normal
  525.      * non-reversed (-rv) LaserJet mapping will represent light areas
  526.      * of the screen as black on the paper.
  527.      */
  528.     if (!paintjet)
  529.       for (n=xwd_header.ncolors, xcolor=xwd_colors, cmap=colormap;  n>0;
  530.        n--, xcolor++, cmap++)
  531.     *cmap = (Intensity(xcolor->red, xcolor->green, xcolor->blue) < cutoff)
  532.         ? (invert ? BLACK : WHITE)
  533.         : (invert ? WHITE : BLACK);
  534.   }
  535.   reset_color_mapping();
  536. }
  537.  
  538.  
  539. /* On a PaintJet printer, the programmable color intensity ranges are:
  540.  *
  541.  *    red:    4..90        green:    4..88        blue:    6..85
  542.  *
  543.  * The following macros map the 0..65535 intensity ranges of X colors
  544.  * into the PaintJet's ranges.
  545.  */
  546.  
  547. #define fixred(x)    (x / 762 + 4)
  548. #define fixgreen(x)    (x / 780 + 4)
  549. #define fixblue(x)    (x / 829 + 6)
  550.  
  551. #define is_grey(r,g,b)    ((r == g) && (r == b))
  552.  
  553.  
  554.  
  555. void select_grey (level, r, g, b)
  556. int level, *r, *g, *b;
  557. {
  558.   /* Forced selection of a grey.  This is done since the PaintJet does
  559.    * not do very well when picking greys, they tend to become pink!
  560.    */
  561.   if (level > 66) {  /* white */
  562.     *r = 90;    *g = 88;    *b = 85;
  563.   } else if (level > 35) {
  564.     *r = 43;    *g = 43;    *b = 45;
  565.   } else if (level > 21) {
  566.     *r = 25;    *g = 25;    *b = 33;
  567.   } else if (level > 15) {
  568.     *r = 15;    *g = 16;    *b = 18;
  569.   } else if (level > 11) {
  570.     *r = 14;    *g = 14;    *b = 18;
  571.   } else if (level > 6) {
  572.     *r =  6;    *g =  7;    *b =  8;
  573.   } else {  /* black */
  574.     *r =  4;    *g =  4;    *b =  6;
  575.   }
  576. }
  577.  
  578.  
  579. long find_nearest_programmed_color ();
  580.  
  581. int load_printer_color (index, nearmatch, device) /* for non Direct/TrueColor */
  582. long index;
  583. int nearmatch;
  584. enum device device;
  585. {
  586.   int n, red, blue, green, xred, xgreen, xblue;
  587.   long compositeRGB;
  588.     
  589.   if (colormap[index] != EMPTY)
  590.     /* printer has already been programmed for this color index */
  591.     return(1);    /* "success" */
  592.   else {
  593.     xred   = xwd_colors[index].red;
  594.     xgreen = xwd_colors[index].green;
  595.     xblue  = xwd_colors[index].blue;
  596.     /* determine the scaled RGB PaintJet color values */
  597.     if (device == PJET) {
  598.        red   = fixred(xred);
  599.        green = fixgreen(xgreen);
  600.        blue  = fixblue(xblue);
  601.        if (is_grey(xred, xgreen, xblue))  /* assist grey selection */
  602.           select_grey(red, &red, &green, &blue);
  603.     }
  604.     compositeRGB = (red << 16) | (green << 8) | blue;
  605.     /* search for a matching or unused PaintJet mapping entry */
  606.     for (n=0; n<MAX_PJ_COLOR; n++) {
  607.       if (pjcolor[n] == compositeRGB) {
  608.     /* record mapping for this index */
  609.     colormap[index] = n;
  610.     /* return "success" */
  611.     return(1);
  612.       } else if (pjcolor[n] == EMPTY) {
  613.     /* download color to printer */
  614.     fprintf(color.OutFile,"\033*v%dA", red);
  615.     fprintf(color.OutFile,"\033*v%dB", green);
  616.     fprintf(color.OutFile,"\033*v%dC", blue);
  617.     fprintf(color.OutFile,"\033*v%dI", n);
  618.     /* record that this is now programmed */
  619.     pjcolor[n] = compositeRGB;
  620.     colormap[index] = n;
  621.     /* return "success" */
  622.     return(1);
  623.       }
  624.     }
  625.     /* unable to find or program this color */
  626.     if (nearmatch)
  627.       colormap[index] = find_nearest_programmed_color(compositeRGB);
  628.   }
  629.   return(0);  /* "failure" */
  630. }
  631.  
  632.  
  633. /* Lookup the image color index on the color.indexchain list.  If found
  634.  * return the corresponding printer color index, otherwise -1.  The index
  635.  * chain is a singly linked circular list.  Its head pointer is left at
  636.  * the last cell matched on the theory that this will allow faster lookup
  637.  * for runs of color.
  638.  */
  639. int lookup_color_index (i)
  640. long i;
  641. {
  642.   COLORINDEX *start, *current;
  643.  
  644.   start = current = color.indexchain;
  645.  
  646.   if (current == NULL)
  647.     return(-1);  /* not found */
  648.  
  649.   do {
  650.     if (current->index == i) {
  651.       color.indexchain = current;
  652.       return(current->pjcolor_index);  /* found */
  653.     }
  654.     current = current->next;
  655.   } while (current != start);
  656.  
  657.   return(-1);  /* not found */
  658. }
  659.  
  660.  
  661. /* Calculate the individual and composite printer RGB values.  (Only the
  662.  * composite value is set for monochrome output.)
  663.  */
  664. void select_printer_color (index, red, green, blue, compositeRGB, device)
  665. long index;
  666. int *red, *green, *blue;
  667. long *compositeRGB;
  668. enum device device;
  669. {
  670.   int xred, xgreen, xblue;
  671.  
  672.   xred   = xwd_colors[((index & color.sm.Rmask) >> color.sm.Rshift)].red;
  673.   xgreen = xwd_colors[((index & color.sm.Gmask) >> color.sm.Gshift)].green;
  674.   xblue  = xwd_colors[((index & color.sm.Bmask) >> color.sm.Bshift)].blue;
  675.  
  676.   if (color.PaintJet) {
  677.     if (color.Invert) {
  678.       if (RGBmatch((xred & fullintensity), (xgreen & fullintensity),
  679.                 (xblue & fullintensity), fullintensity))
  680.     xred = xgreen = xblue = 0;
  681.       else if (RGBmatch(xred, xgreen, xblue, 0))
  682.     xred = xgreen = xblue = fullintensity;
  683.     }
  684.     /* determine the scaled RGB PaintJet color values */
  685.     if (device == PJET) {
  686.        *red   = fixred(xred);
  687.        *green = fixgreen(xgreen);
  688.        *blue  = fixblue(xblue);
  689.        if (is_grey(xred, xgreen, xblue))  /* assist grey selection */
  690.          select_grey(*red, red, green, blue);
  691.     }
  692.     if (device == PJETXL) {
  693.        *red   = xred >> 8;
  694.        *green = xgreen >> 8;
  695.        *blue  = xblue >> 8;
  696.     }
  697.     *compositeRGB = (*red << 16) | (*green << 8) | *blue;
  698.   } else  /* monochrome */
  699.     *compositeRGB = (Intensity(xred, xgreen, xblue) < color.CutOff)
  700.             ? (color.Invert ? BLACK : WHITE)
  701.             : (color.Invert ? WHITE : BLACK);
  702. }
  703.  
  704.  
  705.  
  706. /* Search for a color matching the compositeRGB value in the array of
  707.  * colors already programmed into the printer.  Returns 1 if found,
  708.  * 0 otherwise.  The matching array index is returned in pindex.
  709.  */
  710. int color_already_in_printer (compositeRGB, pindex)
  711. long compositeRGB, *pindex;
  712. {
  713.   int n;
  714.  
  715.   for (n=0; n<MAX_PJ_COLOR; n++)
  716.     if (pjcolor[n] == EMPTY)
  717.       return(0);  /* not found */
  718.     else if (pjcolor[n] == compositeRGB) {
  719.       *pindex = n;
  720.       return(1);  /* found */
  721.     }
  722.   return(0);  /* not found */
  723. }
  724.  
  725.  
  726. int program_new_printer_color (red, green, blue, compositeRGB, pindex)
  727. int red, green, blue;
  728. long compositeRGB;
  729. long *pindex;
  730. {
  731.   int n;
  732.  
  733.   for (n=0; n<MAX_PJ_COLOR; n++)
  734.     if (pjcolor[n] == EMPTY) {
  735.       /* download color to printer */
  736.       fprintf(color.OutFile,"\033*v%dA", red);
  737.       fprintf(color.OutFile,"\033*v%dB", green);
  738.       fprintf(color.OutFile,"\033*v%dC", blue);
  739.       fprintf(color.OutFile,"\033*v%dI", n);
  740.       /* record that this is now programmed */
  741.       pjcolor[n] = compositeRGB;
  742.       *pindex = n;
  743.       /* return "success" */
  744.       return(1);
  745.     }
  746.   /* unable to program this color, return "failure" */
  747.   return(0);
  748. }
  749.  
  750.  
  751.  
  752. long composite_diff (x, y)
  753. long x, y;
  754. {
  755.   long r = (x >> 16 & 0xFF) - (y >> 16 & 0xFF);
  756.   long g = (x >> 8 & 0xFF) - (y >> 8 & 0xFF);
  757.   long b = (x & 0xFF) - (y & 0xFF);
  758.  
  759.   return(r*r + g*g + b*b);
  760. }
  761.  
  762.  
  763.  
  764. long find_nearest_programmed_color (compositeRGB)
  765. long compositeRGB;
  766. {
  767.   int n, nearest = 0;
  768.   long neardiff = composite_diff(pjcolor[0], compositeRGB);
  769.   long diff;
  770.  
  771.   for (n=1; n<MAX_PJ_COLOR; n++) {
  772.     diff = composite_diff(pjcolor[n], compositeRGB);
  773.     if (diff < neardiff) {
  774.       neardiff = diff;
  775.       nearest = n;
  776.     }
  777.   }
  778.   return(nearest);
  779. }
  780.  
  781.  
  782. void add_index_to_chain (cindex, pindex)
  783. long cindex;
  784. long pindex;
  785. {
  786.   COLORINDEX *new;
  787.  
  788.   /* Get a new cell for the color index chain.  Take it from the free list
  789.    * if possible, otherwise malloc space.
  790.    */
  791.   if (color.freechain == NULL) {
  792.     if (!(new = (COLORINDEX *) malloc(sizeof(COLORINDEX))))
  793.       fatal_err((catgets(nlmsg_fd,NL_SETN,8,
  794.             "Could not allocate memory for color translation.")));
  795.   } else {
  796.     new = color.freechain;
  797.     color.freechain = color.freechain->next;
  798.   }
  799.  
  800.   /* put index values in the new cell */
  801.   new->index = cindex;
  802.   new->pjcolor_index = pindex;
  803.  
  804.   /* link the new cell into the chain */
  805.   if (color.indexchain == NULL)
  806.     new->next = new;
  807.   else {
  808.     new->next = color.indexchain->next;
  809.     color.indexchain->next = new;
  810.   }
  811.   /* leave head pointer at the new cell */
  812.   color.indexchain = new;
  813. }
  814.  
  815.  
  816.  
  817. int load_printer_color_DT (index, nearmatch, device) /* for Direct/TrueColor */
  818. long index;
  819. int nearmatch;
  820. enum device device;
  821. {
  822.   int pjred, pjgreen, pjblue;
  823.   long compositeRGB;
  824.   long pindex;
  825.  
  826.   if (lookup_color_index(index) >= 0)
  827.     return(1);    /* "success" */
  828.   else {
  829.     select_printer_color(index, &pjred, &pjgreen, &pjblue, &compositeRGB,
  830.                 device);
  831.     if (color_already_in_printer(compositeRGB, &pindex)) {
  832.       add_index_to_chain(index, pindex);
  833.       return(1);  /* success */
  834.     } else if (program_new_printer_color(pjred, pjgreen, pjblue,
  835.                      compositeRGB, &pindex)) {
  836.       add_index_to_chain(index, pindex);
  837.       return(1);  /* success */
  838.     } else if (nearmatch) {
  839.       add_index_to_chain(index, find_nearest_programmed_color(compositeRGB));
  840.       return(0);  /* failure, sorta... */
  841.     }
  842.   }
  843.   return(0); /* failure */
  844. }
  845.  
  846.  
  847. int load_line_colors (line, length, nearmatch, device)
  848. long *line;
  849. int length, nearmatch;
  850. enum device device;
  851. {
  852.   int result = 1;  /* initialized to "success" */
  853.  
  854.   for (; length>0; length--, line++) {
  855.     result &= Direct_or_TrueColor
  856.           ? load_printer_color_DT(*line, nearmatch, device)
  857.           : load_printer_color(*line, nearmatch, device);
  858.     if (!(nearmatch || result))
  859.       break;
  860.   }
  861.   return(result);
  862. }
  863.  
  864.  
  865.  
  866. void download_colors (line, length, device)
  867. long *line;
  868. int length;
  869. enum device device;
  870. {
  871.   /* For the first attempt at loading the colors for a line only exact
  872.    * color matches are accepted.  If this fails, the closest colors are
  873.    * accepted on the second attempt.
  874.    *
  875.    * Note: The first "if" test below bypasses the initial color loading
  876.    * attempt for monochrome output (which will only come here for Direct
  877.    * or TrueColor mono).  This forces reset_color_mapping which is
  878.    * necessary to keep the color index chain down to a tolerable length.
  879.    */
  880.   if (!color.PaintJet || !load_line_colors(line, length, FALSE, device)) {
  881.     reset_color_mapping();
  882.     if (!load_line_colors(line, length, TRUE, device) &&
  883.                     !color_warning_given) {
  884.       fprintf(stderr,(catgets(nlmsg_fd,NL_SETN,9,
  885.             "%s: Warning: Cannot print all image colors.\n")),
  886.         progname);
  887.       color_warning_given = TRUE;
  888.     }
  889.   }
  890. }
  891.  
  892.  
  893. void validate_visual()
  894. {
  895.   int depth = xwd_header.pixmap_depth;
  896.   char *errmsg = catgets(nlmsg_fd,NL_SETN,25,
  897.                 "%d bit deep %s bitmap not supported.\n");
  898.  
  899.   switch (xwd_header.visual_class) {
  900.   case GrayScale:
  901.     if (depth > 8)  fatal_err2(errmsg, depth, "GrayScale");    break;
  902.   case StaticGray:
  903.     if (depth > 8)  fatal_err2(errmsg, depth, "StaticGray");    break;
  904.   case PseudoColor:
  905.     if (depth > 8)  fatal_err2(errmsg, depth, "PseudoColor");    break;
  906.   case StaticColor:
  907.     if (depth > 8)  fatal_err2(errmsg, depth, "StaticColor");    break;
  908.   case DirectColor:
  909.   case TrueColor:
  910.     if (depth != 12 && depth != 24)
  911.        fatal_err2(errmsg, depth, (xwd_header.visual_class == DirectColor)
  912.                                ? "DirectColor" : "TrueColor");
  913.     break;
  914.   default:
  915.     fatal_err2((catgets(nlmsg_fd,NL_SETN,26,
  916.         "visual class #%d not supported.\n")), xwd_header.visual_class);
  917.   }
  918. }
  919.  
  920. void read_xwd_data (in)
  921. FILE *in;
  922. {
  923. #   define WINDOW_NAME_ALLOC    32
  924.     unsigned long swaptest = 1;
  925.     int window_name_size;
  926.     int image_size;
  927.     int n;
  928.     char window_name [WINDOW_NAME_ALLOC];
  929.  
  930.     /* Read in XWDFileHeader structure */
  931.     if (fread((char*) &xwd_header, 1, XWDHEADERSIZE, in) != XWDHEADERSIZE)
  932.         fatal_err((catgets(nlmsg_fd,NL_SETN,10,
  933.                 "Could not read xwd file's header.")));
  934.  
  935.     if (*(char *) &swaptest)
  936.         _swaplong((char *) &xwd_header, XWDHEADERSIZE);
  937.  
  938.     validate_visual();
  939.  
  940.     /* Skip over window name */
  941.     window_name_size = xwd_header.header_size - XWDHEADERSIZE;
  942.     while (window_name_size > 0) {
  943.         n = window_name_size > WINDOW_NAME_ALLOC
  944.             ? WINDOW_NAME_ALLOC : window_name_size;
  945.         if (fread(window_name, 1, n, in) != n)
  946.             fatal_err((catgets(nlmsg_fd,NL_SETN,11,
  947.                 "Could not read xwd file's window name.")));
  948.         window_name_size -= n;
  949.     }
  950.  
  951.     /* Allocate space for xwd color structures */
  952.     if (!(xwd_colors = (XColor*) malloc(sizeof(XColor) * xwd_header.ncolors)))
  953.         fatal_err((catgets(nlmsg_fd,NL_SETN,12,
  954.             "Could not allocate memory for xwdfile color table.")));
  955.  
  956.     /* Read in xwd color structures */
  957.     for (n = 0; n < xwd_header.ncolors; n++)
  958.         if (fread(&xwd_colors[n], 1, XCOLORSIZE, in) != XCOLORSIZE)
  959.             fatal_err((catgets(nlmsg_fd,NL_SETN,13,
  960.                 "Could not read xwd file's color table.")));
  961.  
  962.     if (*(char *) &swaptest) {
  963.         for (n = 0; n < xwd_header.ncolors; n++) {
  964.             _swaplong((char *) &xwd_colors[n].pixel, sizeof(long));
  965.             _swapshort((char *) &xwd_colors[n].red, 3 * sizeof(short));
  966.         }
  967.      }
  968.  
  969.     /* Allocate space for xwd image */
  970.     if (xwd_header.pixmap_format == ZPixmap)
  971.         image_size = 1;
  972.     else if (xwd_header.pixmap_format == XYPixmap)
  973.         image_size = xwd_header.pixmap_depth;
  974.     else
  975.         fatal_err((catgets(nlmsg_fd,NL_SETN,14,
  976.             "Image in xwd file is not in Z or XY pixmap format.")));
  977.     image_size *= xwd_header.bytes_per_line * xwd_header.pixmap_height;
  978.     if (!(xwd_image = malloc(image_size)))
  979.         fatal_err((catgets(nlmsg_fd,NL_SETN,15,
  980.             "Could not allocate memory for xwd file's image.")));
  981.  
  982.     /* Read in xwd image */
  983.     if (fread(xwd_image, 1, image_size, in) != image_size)
  984.         fatal_err((catgets(nlmsg_fd,NL_SETN,16,
  985.             "Could not read xwd file's image.")));
  986.  
  987. }
  988.  
  989.  
  990. write_image_prefix (out, scale, density, header, device, position_on_page,
  991.             initial_formfeed, orient, gamma, render, slide)
  992. FILE *out;
  993. int scale, density;
  994. char *header;
  995. enum device device;
  996. int position_on_page, initial_formfeed;
  997. enum orientation orient;
  998. float gamma;
  999. int render;
  1000. int slide;
  1001. {
  1002.   if (initial_formfeed)
  1003.     fprintf(out,"\014");
  1004.  
  1005.   /* Write out header & positioning commands */
  1006.   if (header) {
  1007.     if (position_on_page)
  1008.       fprintf(out,"\033&a%dH\033&a%dV",
  1009.           /* headerloc x & y are written in decipoints */
  1010.           (int) headerloc.x / 10, (int) headerloc.y / 10);
  1011.     fprintf(out,"%s\n", header);
  1012.   }
  1013.  
  1014.   /* Prepare printer for raster graphics: */
  1015.  
  1016.   /* Write image positioning commands */
  1017.   if (position_on_page)
  1018.     fprintf(out,"\033&a%dH\033&a%dV",
  1019.         /* imageloc x & y are written in decipoints */
  1020.         (int) imageloc.x / 10, (int) imageloc.y / 10);
  1021.   
  1022.   /* If doing transparencies, tell the printer before raster graphics */
  1023.   if (slide && device != LJET)
  1024.      fprintf(out, "\033&k3W");
  1025.  
  1026.   /* Set printer resolution */
  1027.   fprintf(out,"\033*t%dR", density);
  1028.  
  1029.   /*
  1030.    * do device dependent escape sequences
  1031.    */
  1032.   if (device == PJET) {
  1033.     /* Enable all four "planes" for PaintJet */
  1034.     fprintf(out,"\033*r4U");
  1035.  
  1036.     /* Set picture width for PaintJet */
  1037.     fprintf(out,"\033*r%dS",
  1038.         ((int) (orient == PORTRAIT) ? limit.width : limit.height)
  1039.         * scale);
  1040.   }
  1041.  
  1042.   /* Enable various options for PaintJet XL */
  1043.   if (device == PJETXL) {
  1044.     double dotsize;
  1045.     int n;
  1046.  
  1047.     /* Speed up printing by telling that there
  1048.      * will be no negative positioning
  1049.      */
  1050.     fprintf(out, "\033&a1N");
  1051.  
  1052.     if (gamma > 0.009)
  1053.        fprintf(out, "\033*t%.2fI", gamma);
  1054.  
  1055.     if (render > 0)
  1056.        fprintf(out, "\033*t%dJ", render);
  1057.  
  1058.     if (Direct_or_TrueColor)
  1059.        /* Enable direct by pixel for PaintJet XL */
  1060.        fwrite("\033*v6W\000\003\010\010\010\010", 1, 11, out);
  1061.     else {
  1062.        /* Enable index by pixel for PaintJet XL */
  1063.        fwrite("\033*v6W\000\001\010\010\010\010", 1, 11, out);
  1064.  
  1065.        /* Program the palette */
  1066.        for (n = 0; n < xwd_header.ncolors; n++) {
  1067.           fprintf(out,"\033*v%dA", (xwd_colors[n].red >> 8));
  1068.           fprintf(out,"\033*v%dB", (xwd_colors[n].green >> 8));
  1069.           fprintf(out,"\033*v%dC", (xwd_colors[n].blue >> 8));
  1070.           fprintf(out,"\033*v%dI", n);
  1071.        }
  1072.     }
  1073.  
  1074.     /****************************************
  1075.      *                                      *
  1076.      * PaintJet XL will do its own scaling  *
  1077.      *                                      *
  1078.      * Set picture width for PaintJet XL    *
  1079.      ****************************************/
  1080.     fprintf(out,"\033*r%dS",
  1081.         ((int) (orient == PORTRAIT) ? xwd_header.pixmap_width
  1082.                     : xwd_header.pixmap_height));
  1083.     fprintf(out,"\033*r%dT",
  1084.         ((int) (orient == PORTRAIT) ? xwd_header.pixmap_height
  1085.                     : xwd_header.pixmap_width));
  1086.  
  1087.     dotsize = dot_centipoints(scale, density);
  1088.  
  1089.     fprintf(out,"\033*t%dH",
  1090.         (int)(((orient == PORTRAIT) ? xwd_header.pixmap_width
  1091.                                         : xwd_header.pixmap_height)
  1092.                         * dotsize / 10));
  1093.  
  1094.     fprintf(out,"\033*t%dV",
  1095.         (int)(((orient == PORTRAIT) ? xwd_header.pixmap_height
  1096.                                         : xwd_header.pixmap_width)
  1097.                         * dotsize / 10));
  1098.   }
  1099.  
  1100.   /* Switch to raster graphics mode */
  1101.   if (device != PJETXL)
  1102.      fprintf(out,"\033*r1A");
  1103.   else
  1104.      fprintf(out,"\033*r3A");
  1105.  
  1106. }
  1107.  
  1108.  
  1109. write_image_suffix (out, trailer, position_on_page, slide, render, device)
  1110. FILE *out;
  1111. char *trailer;
  1112. int position_on_page;
  1113. int slide, render;
  1114. enum device device;
  1115. {
  1116.   /* Exit raster graphics mode */
  1117.   if (device == PJETXL)
  1118.      fprintf(out,"\033*rC");
  1119.   else
  1120.      fprintf(out,"\033*rB");
  1121.  
  1122.   /* If doing transparencies, tell it to stop */
  1123.   if (slide && device != LJET)
  1124.      fprintf(out, "\033&k1W");
  1125.  
  1126.   if (device == PJETXL) {
  1127.      /* If selected a rendering algorithm, tell it to stop */
  1128.      if (render)
  1129.         fprintf(out, "\033*t3J");
  1130.      fprintf(out, "\033&a0N");
  1131.   }
  1132.  
  1133.   /* Write out trailer & positioning commands */
  1134.   if (trailer) {
  1135.     if (position_on_page)
  1136.       fprintf(out,"\033&a%dH\033&a%dV",
  1137.           /* trailerloc x & y are written in decipoints */
  1138.           (int) trailerloc.x / 10, (int) trailerloc.y / 10);
  1139.     fprintf(out,"%s\n", trailer);
  1140.   }
  1141. }
  1142.  
  1143.  
  1144. unsigned long Z_image_pixel (x, y)
  1145. int x, y;
  1146. {
  1147.   int pixel_bytes, offset;
  1148.   unsigned char *image;
  1149.   unsigned long pixel;
  1150.  
  1151.   pixel_bytes = xwd_header.bits_per_pixel >> 3;
  1152.   offset = ((xwd_header.bits_per_pixel == 4) ? (x / 2)
  1153.             : ((xwd_header.bits_per_pixel == 1) ? (x / 8)
  1154.                : (x * pixel_bytes)))
  1155.            + (y * xwd_header.bytes_per_line);
  1156.  
  1157.   image = (unsigned char *) &xwd_image[offset];
  1158.  
  1159.   switch (pixel_bytes) {
  1160.   case 0:  /* pixel per nibble or bit per pixel packing */
  1161.     if (xwd_header.bits_per_pixel == 1) {
  1162.       if (xwd_header.byte_order == MSBFirst)
  1163.     pixel = *image >> (7 - (x % 8));
  1164.       else
  1165.     pixel = *image >> (x % 8);
  1166.     } else {  /* xwd_header.bits_per_pixel == 4 */
  1167.       if (xwd_header.byte_order == MSBFirst)
  1168.     pixel = (x & 1) ? *image : (*image >> 4);
  1169.       else
  1170.     pixel = (x & 1) ? (*image >> 4) : *image;
  1171.     }
  1172.     break;
  1173.   case 1:
  1174.     pixel = *image;
  1175.     break;
  1176.   case 2:
  1177.     pixel = (xwd_header.byte_order == MSBFirst)
  1178.          ? ((unsigned long)*image << 8 | *(image + 1))
  1179.          : (*image | (unsigned long)*(image + 1) << 8);
  1180.     break;
  1181.   case 3:
  1182.     pixel = (xwd_header.byte_order == MSBFirst)
  1183.          ? ((unsigned long)*image << 16 |
  1184.         (unsigned long)*(image + 1) << 8 |
  1185.         (unsigned long)*(image + 2))
  1186.          : (*image |
  1187.         (unsigned long)*(image + 1) << 8 |
  1188.         (unsigned long)*(image + 2) << 16);
  1189.     break;
  1190.   case 4:
  1191.     pixel = (xwd_header.byte_order == MSBFirst)
  1192.          ? ((unsigned long)*image << 24 |
  1193.         (unsigned long)*(image+1) << 16 |
  1194.         (unsigned long)*(image+2) << 8 |
  1195.         *(image+3))
  1196.          : (*image |
  1197.         (unsigned long)*(image+1) << 8 |
  1198.         (unsigned long)*(image+2) << 16 |
  1199.         (unsigned long)*(image+3) << 24);
  1200.     break;
  1201.   }
  1202.   return (pixel & Z_pixel_mask);
  1203. }
  1204.  
  1205.  
  1206. unsigned long XY_image_pixel (x, y)
  1207. int x, y;
  1208. {
  1209.   int plane_start, line_start, bytes_per_bitmap_unit, bitmap_unit_start,
  1210.       byte_within_bitmap_unit, offset, byte_mask;
  1211.  
  1212.   plane_start = (xwd_header.pixmap_depth - 1) * xwd_header.pixmap_height
  1213.         * xwd_header.bytes_per_line;
  1214.   line_start = xwd_header.bytes_per_line * y;
  1215.   bytes_per_bitmap_unit = xwd_header.bitmap_unit >> 3;
  1216.   bitmap_unit_start = (x / xwd_header.bitmap_unit) * bytes_per_bitmap_unit;
  1217.   byte_within_bitmap_unit = (xwd_header.byte_order == MSBFirst)
  1218.     ? (x % xwd_header.bitmap_unit) >> 3
  1219.     :  bytes_per_bitmap_unit - ((x % xwd_header.bitmap_unit) >> 3) - 1;
  1220.  
  1221.   offset = plane_start + line_start + bitmap_unit_start
  1222.        + byte_within_bitmap_unit;
  1223.  
  1224.   byte_mask = (xwd_header.bitmap_bit_order == MSBFirst)
  1225.       ? 0x80 >> (x % 8) : 0x01 << (x % 8);
  1226.  
  1227.   return(xwd_image[offset] & byte_mask ? 1 : 0);
  1228. }
  1229.  
  1230.  
  1231. void direct_by_pixel(out, line, length, device)
  1232. FILE *out;
  1233. long *line;
  1234. int length;
  1235. enum device device;
  1236. {
  1237.    int red, green, blue;
  1238.    long compositeRGB;
  1239.  
  1240.    fprintf(out, "\033*b%dW", length * 3);
  1241.    for (; length>0; length--, line++) {
  1242.       select_printer_color(*line, &red, &green, &blue, &compositeRGB, device);
  1243.       fprintf(out, "%c%c%c", (char) red, (char) green, (char) blue);
  1244.    }
  1245. }
  1246.  
  1247.  
  1248. void index_by_pixel(out, line, length)
  1249. FILE *out;
  1250. long *line;
  1251. int length;
  1252. {
  1253.    register int n;
  1254.    long *lp;
  1255.    char *line_pixels;
  1256.    register char *lc;
  1257.   
  1258.   if (!(line_pixels = malloc(length)))
  1259.     fatal_err((catgets(nlmsg_fd,NL_SETN,17,
  1260.             "Could not allocate raster line memory.")));
  1261.  
  1262.    for (n=0, lc=line_pixels, lp=line;  n<length;  n++)
  1263.       *lc++ = (char) *lp++;
  1264.  
  1265.    fprintf(out, "\033*b%dW", length);
  1266.    fwrite(line_pixels, 1, length, out);
  1267.  
  1268.    free(line_pixels);
  1269. }
  1270.  
  1271.  
  1272. void write_raster_line (out, scale, device, line, length)
  1273. FILE *out;
  1274. int scale;
  1275. enum device device;
  1276. long *line;
  1277. int length;
  1278. {
  1279.   int planes = (device == PJET) ? 4 : 1;
  1280.   int raster_bytes = (length * scale + 7) / 8;
  1281.   register int bytebits, n, p, e, bit;
  1282.   long *lp;
  1283.   char *line_colors, *raster_line;
  1284.   register char *lc, *rl, byte = 0;
  1285.   
  1286.   if (device == PJETXL) {
  1287.      if (Direct_or_TrueColor)
  1288.         direct_by_pixel(out, line, length, device);
  1289.      else
  1290.         index_by_pixel(out, line, length);
  1291.      return;
  1292.   }
  1293.  
  1294.   if (!(line_colors = malloc(length))
  1295.       || !(raster_line = malloc(raster_bytes * planes)))
  1296.     fatal_err((catgets(nlmsg_fd,NL_SETN,17,
  1297.             "Could not allocate raster line memory.")));
  1298.  
  1299.   if (device == PJET || Direct_or_TrueColor)
  1300.     download_colors(line, length, device);
  1301.  
  1302.   /* Map the line's colors into output color index numbers */
  1303.   if (Direct_or_TrueColor)
  1304.     for (n=0, lc=line_colors, lp=line;  n<length;  n++)
  1305.       *lc++ = (char) lookup_color_index(*lp++);
  1306.   else
  1307.     for (n=0, lc=line_colors, lp=line;  n<length;  n++)
  1308.       *lc++ = (char) colormap[*lp++];
  1309.  
  1310.   for (p=0;  p<planes;  p++) {
  1311.     bytebits = 0;
  1312.     n = length;
  1313.     lc = line_colors;
  1314.     rl = &raster_line[raster_bytes * p];
  1315.     while (n-- > 0) {
  1316.       bit = (*lc++ >> p) & 0x01;
  1317.       e = scale;
  1318.       while (e--) {
  1319.     byte = (byte << 1) | bit;
  1320.     bytebits++;
  1321.     if (bytebits == 8) {
  1322.       *rl++ = byte;
  1323.       bytebits = 0;
  1324.     }
  1325.       }
  1326.     }
  1327.     if (bytebits)
  1328.       *rl = byte << (8 - bytebits);
  1329.   }
  1330.  
  1331.   e = scale;
  1332.   while (e--) {
  1333.     for (p=0;  p<planes;  p++) {
  1334.       fprintf(out,"\033*b%d%c", raster_bytes, (p+1 == planes) ? 'W' : 'V');
  1335.       fwrite(&raster_line[raster_bytes * p], 1, raster_bytes, out);
  1336.     }
  1337.   }
  1338.  
  1339.   free(line_colors);
  1340.   free(raster_line);
  1341. }
  1342.  
  1343.  
  1344. void write_portrait_Z_image (out, scale, device)
  1345. FILE *out;
  1346. int scale;
  1347. enum device device;
  1348. {
  1349.   int x, y;
  1350.   int width = limit.width;
  1351.   int height = limit.height;
  1352.   long *line, *lp;
  1353.  
  1354.   if (!(line = (long *) malloc(width * sizeof(long))))
  1355.     fatal_err((catgets(nlmsg_fd,NL_SETN,18,
  1356.             "Could not allocate memory for image line buffer.")));
  1357.  
  1358.   for (y=0;  y<height;  y++) {
  1359.  
  1360.     for (x=0, lp=line;  x<width;  x++)
  1361.       *lp++ = Z_image_pixel(x,y);
  1362.  
  1363.     write_raster_line(out, scale, device, line, width);
  1364.   }
  1365. }
  1366.  
  1367.  
  1368.  
  1369. void write_landscape_Z_image (out, scale, device)
  1370. FILE *out;
  1371. int scale;
  1372. enum device device;
  1373. {
  1374.   int x, y;
  1375.   int width = limit.height;
  1376.   int height = limit.width;
  1377.   long *line, *lp;
  1378.  
  1379.   if (!(line = (long *) malloc(width * sizeof(long))))
  1380.     fatal_err((catgets(nlmsg_fd,NL_SETN,19,
  1381.             "Could not allocate memory for image line buffer.")));
  1382.  
  1383.   for (x=0;  x<height;  x++) {
  1384.  
  1385.     for (y=width-1, lp=line;  y>=0;  y--)
  1386.       *lp++ = Z_image_pixel(x,y);
  1387.  
  1388.     write_raster_line(out, scale, device, line, width);
  1389.   }
  1390. }
  1391.  
  1392.  
  1393. void write_portrait_XY_image (out, scale, device)
  1394. FILE *out;
  1395. int scale;
  1396. enum device device;
  1397. {
  1398.   int x, y;
  1399.   int width = limit.width;
  1400.   int height = limit.height;
  1401.   long *line, *lp;
  1402.  
  1403.   if (!(line = (long *) malloc(width * sizeof(long))))
  1404.     fatal_err((catgets(nlmsg_fd,NL_SETN,20,
  1405.             "Could not allocate memory for image line buffer.")));
  1406.  
  1407.   for (y=0;  y<height;  y++) {
  1408.  
  1409.     for (x=0, lp=line;  x<width;  x++)
  1410.       *lp++ = XY_image_pixel(x,y);
  1411.  
  1412.     write_raster_line(out, scale, device, line, width);
  1413.   }
  1414. }
  1415.  
  1416.  
  1417.  
  1418. void write_landscape_XY_image (out, scale, device)
  1419. FILE *out;
  1420. int scale;
  1421. enum device device;
  1422. {
  1423.   int x, y;
  1424.   int width = limit.height;
  1425.   int height = limit.width;
  1426.   long *line, *lp;
  1427.  
  1428.   if (!(line = (long *) malloc(width * sizeof(long))))
  1429.     fatal_err((catgets(nlmsg_fd,NL_SETN,21,
  1430.             "Could not allocate memory for image line buffer.")));
  1431.  
  1432.   for (x=0;  x<height;  x++) {
  1433.  
  1434.     for (y=width-1, lp=line;  y>=0;  y--)
  1435.       *lp++ = XY_image_pixel(x,y);
  1436.  
  1437.     write_raster_line(out, scale, device, line, width);
  1438.   }
  1439. }
  1440.  
  1441.  
  1442. void write_Z_image (out, scale, orient, device)
  1443. FILE *out;
  1444. int scale;
  1445. enum orientation orient;
  1446. enum device device;
  1447. {
  1448.   if (orient == PORTRAIT) {
  1449.     write_portrait_Z_image(out, scale, device);
  1450.   } else
  1451.     write_landscape_Z_image(out, scale, device);
  1452. }
  1453.  
  1454.  
  1455.  
  1456. void write_XY_image (out, scale, orient, device)
  1457. FILE *out;
  1458. int scale;
  1459. enum orientation orient;
  1460. enum device device;
  1461. {
  1462.   if (xwd_header.pixmap_depth > 1)
  1463.     fatal_err((catgets(nlmsg_fd,NL_SETN,22,
  1464.         "XY format image, multiplane images must be Z format.")));
  1465.  
  1466.   if (orient == PORTRAIT) {
  1467.     write_portrait_XY_image(out, scale, device);
  1468.   } else
  1469.     write_landscape_XY_image(out, scale, device);
  1470. }
  1471.  
  1472.  
  1473.  
  1474. void write_image (out, scale, orient, device)
  1475. FILE *out;
  1476. int scale;
  1477. enum orientation orient;
  1478. enum device device;
  1479. {
  1480.   switch (xwd_header.pixmap_format) {
  1481.   case XYPixmap:
  1482.     write_XY_image(out, scale, orient, device);  break;
  1483.   case  ZPixmap:
  1484.     write_Z_image(out, scale, orient, device);   break;
  1485.   default: 
  1486.     fatal_err((catgets(nlmsg_fd,NL_SETN,23, "image not in XY or Z format.")));
  1487.   }
  1488. }
  1489.  
  1490.  
  1491. void x2jet(in, out, scale, density, width, height, left, top,
  1492.        header, trailer, orient, invert,
  1493.        initial_formfeed, position_on_page, slide,
  1494.        device, cutoff, gamma, render)
  1495. FILE *in, *out;
  1496. int scale, density;
  1497. int width, height, left, top;  /* in 300ths of an inch */
  1498. char *header, *trailer;
  1499. enum orientation orient;
  1500. int invert, initial_formfeed, position_on_page, slide;
  1501. enum device device;
  1502. unsigned int cutoff;
  1503. float gamma;
  1504. int render;
  1505. {
  1506.   int paintjet = FALSE;
  1507.  
  1508.   true_scale = scale;
  1509.  
  1510.   if (device != LJET)
  1511.      paintjet = TRUE;
  1512.  
  1513.   read_xwd_data(in);
  1514.  
  1515.   Z_pixel_mask = ~(0xFFFFFFFFL << xwd_header.pixmap_depth);
  1516.  
  1517.   prepare_color_mapping(invert, paintjet, cutoff, out);
  1518.  
  1519.   scale_and_orient_image(&scale, &density, width, height, left, top,
  1520.              header, trailer,
  1521.              &orient, position_on_page, device);
  1522.  
  1523.   write_image_prefix(out, scale, density, header, device, position_on_page,
  1524.              initial_formfeed, orient, gamma, render, slide);
  1525.   
  1526.   write_image(out, scale, orient, device);
  1527.  
  1528.   write_image_suffix(out, trailer, position_on_page, slide, render, device);
  1529.  
  1530.   fclose(out);
  1531. }
  1532.  
  1533.  
  1534. void fatal_err (s)
  1535. char * s;
  1536. {
  1537.   fprintf(stderr, "%s: %s\n", progname, s);
  1538.   exit(1);
  1539. }
  1540.  
  1541. void fatal_err2 (s, a1, a2, a3)
  1542. char *s;
  1543. char *a1, *a2, *a3;
  1544. {
  1545.   fprintf(stderr, "%s: ", progname);
  1546.   fprintf(stderr, s, a1, a2, a3);
  1547.   exit(1);
  1548. }
  1549.