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