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