/* $XConsortium: x2jet.c,v 1.6 94/04/17 20:44:03 rws Exp $ */ /* -*-C-*- ******************************************************************************** * * File: x2jet.c * RCS: x2jet.c,v 1.23 89/07/17 12:02:51 lori Exp * Description: xpr support for HP LaserJet and PaintJet printers * Author: Larry Rupp, HP Graphics Technology Division * Created: Fri Jul 15 15:22:26 1988 * Modified: Thu Sep 15 11:59:34 1988 (Larry Rupp) ler@hpfcler * Tue Dec 6 10:04:43 PST 1988 (Marc Ayotte) marca@hp-pcd * Language: C * Package: N/A * Status: Released to MIT * * (c) Copyright 1988, Hewlett-Packard Company. * ******************************************************************************** */ /******************************************************** Copyright (c) 1988 by Hewlett-Packard Company Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that Hewlett-Packard not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. ********************************************************/ /* Copyright (c) 1988 X Consortium Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Except as contained in this notice, the name of the X Consortium shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from the X Consortium. */ #include #include #include #include "xpr.h" #ifdef NLS16 #ifndef NLS #define NLS #endif #endif #ifndef NLS #define catgets(i, sn,mn,s) (s) #else /* NLS */ #define NL_SETN 2 /* set number */ #include extern char *catgets(); extern nl_catd nlmsg_fd; #endif /* NLS */ #ifndef TRUE # define FALSE 0 # define TRUE 1 #endif /* default printable page area (inches) */ #define STDWIDTH 8.0 #define STDHEIGHT 10.5 /* header & trailer character cell size (centipoints) */ #define CHARWIDTH 720 #define CHARHEIGHT 1200 #define XWDHEADERSIZE (sizeof(XWDFileHeader)) #define XCOLORSIZE (sizeof(XColor)) typedef struct { long width, height; } Area; typedef struct { long x, y; } Location; static Area limit; /* image clip limits (dots) */ static Area page; /* printable page size (centipoints) */ static Location headerloc; /* centipoint location of header string */ static Location trailerloc; /* centipoint location of trailer string */ static Location imageloc; /* centipoint location of image */ static int headerlimit; /* number of chars which will printed for */ static int trailerlimit; /* the image's header/trailer strings */ static XWDFileHeader xwd_header; static XColor *xwd_colors; static char *xwd_image; static unsigned long Z_pixel_mask; static int true_scale; extern char *progname; void fatal_err(); void fatal_err2(); /* Computes the centipoint width of one printer dot. */ #define dot_centipoints(s,d) ((7200.0 * s) / d) void set_image_limits (scale, density, orient, print_area) int scale, density; enum orientation orient; Area print_area; { Area print_dots; double dotsize; /* Set dotsize to the centipoint width of one printer dot. */ dotsize = dot_centipoints(scale, density); if (orient == PORTRAIT) { print_dots.width = print_area.width / dotsize; print_dots.height = print_area.height / dotsize; } else { print_dots.height = print_area.width / dotsize; print_dots.width = print_area.height / dotsize; } limit.width = (print_dots.width < xwd_header.pixmap_width) ? print_dots.width : xwd_header.pixmap_width; limit.height = (print_dots.height < xwd_header.pixmap_height) ? print_dots.height : xwd_header.pixmap_height; if ((limit.width != xwd_header.pixmap_width) || (limit.height != xwd_header.pixmap_height)) fprintf(stderr,(catgets(nlmsg_fd,NL_SETN,1, "%s: Warning: %ld x %ld image clipped to %ld x %ld.\n")), progname, xwd_header.pixmap_width, xwd_header.pixmap_height, limit.width, limit.height); } void set_header_trailer_limits (header, trailer, printwidth) char *header, *trailer; long printwidth; { /* Determine the number of header and trailer characters * that will fit into the available printing area. */ headerlimit = header ? (((strlen(header) * CHARWIDTH) <= printwidth) ? strlen(header) : (printwidth / CHARWIDTH)) : 0; if (header && headerlimit != strlen(header)) { fprintf(stderr,(catgets(nlmsg_fd,NL_SETN,2, "%s: Warning: Header string clipped to %d characters.\n")), progname, headerlimit); header[headerlimit] = '\0'; } trailerlimit = trailer ? (((strlen(trailer) * CHARWIDTH) <= printwidth) ? strlen(trailer) : (printwidth / CHARWIDTH)) : 0; if (trailer && trailerlimit != strlen(trailer)) { fprintf(stderr,(catgets(nlmsg_fd,NL_SETN,3, "%s: Warning: Trailer string clipped to %d characters.\n")), progname, trailerlimit); trailer[headerlimit] = '\0'; } } void set_print_locations (scale, density, top, left, header, trailer, orient, position_on_page) int scale, density; int top, left; char *header, *trailer; enum orientation orient; int position_on_page; { Area image; double dotsize; /* Set dotsize to the centipoint width of one printer dot. */ dotsize = dot_centipoints(scale, density); /* Compute the centipoint size of the clipped image area. */ if (orient == PORTRAIT) { image.width = limit.width * dotsize; image.height = limit.height * dotsize; } else { image.height = limit.width * dotsize; image.width = limit.height * dotsize; } if (position_on_page) { /* set vertical positions */ imageloc.y = (top >= 0) ? top * 24 + ((header) ? CHARHEIGHT : 0) : ((page.height - ((header) ? CHARHEIGHT : 0) - image.height - ((trailer) ? CHARHEIGHT : 0)) / 2) + ((header) ? CHARHEIGHT : 0); headerloc.y = imageloc.y - CHARHEIGHT / 4; trailerloc.y = imageloc.y + image.height + (3 * CHARHEIGHT) / 4; /* set horizontal positions */ if (left >= 0) headerloc.x = imageloc.x = trailerloc.x = left * 24; else { headerloc.x = (page.width - headerlimit * CHARWIDTH) / 2; imageloc.x = (page.width - image.width) / 2; trailerloc.x = (page.width - trailerlimit * CHARWIDTH) / 2; } } } int scale_raster (density, orient, print_area) int density; enum orientation orient; Area print_area; { Area image; int h_scale, v_scale; /* Set the image dimensions to the number of centipoints that would be * required for printing at the selected density. */ if (orient == PORTRAIT) { image.width = xwd_header.pixmap_width * 7200 / density; image.height = xwd_header.pixmap_height * 7200 / density; } else { image.height = xwd_header.pixmap_width * 7200 / density; image.width = xwd_header.pixmap_height * 7200 / density; } /* Calculate the maximum image multiplier along * the horizontal and vertical dimensions. */ h_scale = print_area.width / image.width; v_scale = print_area.height / image.height; /* If the image can be expanded, return the lesser of the horizontal and * vertical multipliers. Otherwise, the image will not completely fit * the available print area, so just return 1 as the expansion factor. */ return (((h_scale > 0) && (v_scale > 0)) ? ((h_scale= 0) ? width * 24 : STDWIDTH * 7200; page.height = (height >= 0) ? height * 24 : STDHEIGHT * 7200; /* Paintjet Xl has a mechanical form feed, not a strip feed. It has * a slop of about 1/4 to 1/2 of an inch at the top and bottom. * deduct it from the page height. */ if (device == PJETXL) page.height = page.height - 7200; /* Determine the area usable for the image. This area will be smaller * than the total printable area if margins or header/trailer strings * have been specified. Margins, like width and height discussed above, * are expressed in 300ths of an inch and must be converted to centipoints. * Header and trailer strings each reduce the available image height * by 1/6 inch, or 1200 centipoints (aka CHARHEIGHT). */ usable.width = page.width - ((left > 0) ? (left * 24) : 0); usable.height = page.height - ((top > 0) ? (top * 24) : 0) - ((header) ? CHARHEIGHT : 0) - ((trailer) ? CHARHEIGHT : 0); /* Quit here if there is no usable image space. */ if ((usable.width <= 0) || (usable.height <= 0)) { fatal_err((catgets(nlmsg_fd,NL_SETN,4, "No space available on page for image."))); } /* Determine image orientation. The orientation will only be changed if * it was not specified by a command line option. Portrait mode will be * used if either the usable printing area or the image area are square. * Portrait mode will also be used if the long dimensions of the usable * printing area and the image area match, otherwise landscape mode is * used. Portrait mode really means "don't rotate" and landscape mode * means "rotate". */ if (*orient == UNSPECIFIED) { if ((usable.width == usable.height) || (xwd_header.pixmap_width == xwd_header.pixmap_height)) *orient = PORTRAIT; else *orient = ((usable.width < usable.height) == (xwd_header.pixmap_width < xwd_header.pixmap_height)) ? PORTRAIT : LANDSCAPE; } /* Set the dots-per-inch print density if it was not specified */ if (*density <= 0) { switch(device) { case LJET: *density = 300; break; case PJET: *density = 90; break; case PJETXL: *density = 180; break; } } /* Fit image to available area if scale was not specified */ if (*scale <= 0) *scale = scale_raster(*density, *orient, usable); /* Determine image clipping limits */ set_image_limits(*scale, *density, *orient, usable); /* Determine header/trailer string length clipping */ set_header_trailer_limits(header, trailer, usable.width); /* Calculate locations for page layout */ set_print_locations(*scale, *density, top, left, header, trailer, *orient, position_on_page); } unsigned short fullintensity; #define BLACK 1 #define WHITE 0 #define EMPTY -1 #define MAX_PJ_COLOR 16 #define RGBmatch(r,g,b,i) (r == i) && (g == i) && (b == i) /* Colormap array is used to map from the Xcolor array (xwd_colors) index * numbers into a pjcolor index number. This style of mapping is done when * interpreting non-Direct/TrueColor visual types. */ long *colormap; /* Pjcolor array is used to hold the scaled RGB triple values * programmed into the printer. */ long pjcolor[MAX_PJ_COLOR]; static int color_warning_given = FALSE; /* Global visual type indicator, used to select color interpretation method. */ char Direct_or_TrueColor; typedef struct { unsigned long Rmask, Gmask, Bmask; int Rshift, Gshift, Bshift; } RGBshiftmask; /* Color index element definition, these are linked into a circular list * for interpretation of DirectColor or TrueColor visual types. */ typedef struct colorindex { long index; long pjcolor_index; struct colorindex *next; } COLORINDEX; /* Global data for color interpretation. This structure serves as a home * for the color index lists (only used when processing DirectColor or * TrueColor visual types). It also holds color processing switches and a * pointer to the output file to reduce parameter passing overhead. */ struct { int PaintJet; int Invert; unsigned int CutOff; FILE *OutFile; COLORINDEX *indexchain, *freechain; RGBshiftmask sm; } color; void setup_RGBshiftmask (sm, rmask, gmask, bmask) RGBshiftmask *sm; unsigned long rmask, gmask, bmask; { sm->Rmask = rmask; sm->Gmask = gmask; sm->Bmask = bmask; sm->Rshift = 0; sm->Gshift = 0; sm->Bshift = 0; if (!rmask) fatal_err((catgets(nlmsg_fd,NL_SETN,5, "red mask for visual is zero."))); if (!gmask) fatal_err((catgets(nlmsg_fd,NL_SETN,6, "green mask for visual is zero."))); if (!bmask) fatal_err((catgets(nlmsg_fd,NL_SETN,7, "blue mask for visual is zero."))); for (; !(rmask & 1); sm->Rshift++) rmask >>= 1; for (; !(gmask & 1); sm->Gshift++) gmask >>= 1; for (; !(bmask & 1); sm->Bshift++) bmask >>= 1; } void swap_black_and_white () { /* Reverse black and white in the Xcolor structure array. */ XColor *color; int n; for (n=xwd_header.ncolors, color=xwd_colors; n>0; n--, color++) if (RGBmatch((color->red & fullintensity), (color->green & fullintensity), (color->blue & fullintensity), fullintensity)) color->red = color->green = color->blue = 0; else if (RGBmatch(color->red, color->green, color->blue, 0)) color->red = color->green = color->blue = fullintensity; } void reset_color_mapping () { int n; long *cmap; COLORINDEX *splice; for (n=0; nnext; color.indexchain->next = color.freechain; color.freechain = splice; color.indexchain = NULL; } } else if (color.PaintJet) for (n=xwd_header.ncolors, cmap=colormap; n>0; n--, cmap++) *cmap = EMPTY; } #define Intensity(r,g,b) ((r) * 0.30 + (g) * 0.59 + (b) * 0.11) void prepare_color_mapping (invert, paintjet, cutoff, out) int invert, paintjet; unsigned int cutoff; FILE *out; { int n; long *cmap; XColor *xcolor; for (n = xwd_header.bits_per_rgb, fullintensity = 0; n > 0; n--) fullintensity = (fullintensity << 1) | 1; for (n = sizeof(short) * 8 - xwd_header.bits_per_rgb; n > 0; n--) fullintensity = (fullintensity << 1); Direct_or_TrueColor = (xwd_header.visual_class == DirectColor || xwd_header.visual_class == TrueColor); color.PaintJet = paintjet; color.Invert = invert; color.CutOff = cutoff; color.OutFile = out; color.indexchain = NULL; color.freechain = NULL; if (Direct_or_TrueColor) setup_RGBshiftmask(&color.sm, xwd_header.red_mask, xwd_header.green_mask, xwd_header.blue_mask); else { if (!(colormap = (long *) malloc(xwd_header.ncolors * sizeof(long)))) fatal_err((catgets(nlmsg_fd,NL_SETN,24, "Could not allocate memory for X-to-printer colormap."))); /* For PaintJet, color map assignment will be done one line at a time. * So for now just interchange the Xcolor structure's black and white * if the -rv command line option was specified. */ if (paintjet && invert) swap_black_and_white(); /* For LaserJet, map each color to black or white based upon the * combined intensity of the RGB components. Note that the normal * non-reversed (-rv) LaserJet mapping will represent light areas * of the screen as black on the paper. */ if (!paintjet) for (n=xwd_header.ncolors, xcolor=xwd_colors, cmap=colormap; n>0; n--, xcolor++, cmap++) *cmap = (Intensity(xcolor->red, xcolor->green, xcolor->blue) < cutoff) ? (invert ? BLACK : WHITE) : (invert ? WHITE : BLACK); } reset_color_mapping(); } /* On a PaintJet printer, the programmable color intensity ranges are: * * red: 4..90 green: 4..88 blue: 6..85 * * The following macros map the 0..65535 intensity ranges of X colors * into the PaintJet's ranges. */ #define fixred(x) (x / 762 + 4) #define fixgreen(x) (x / 780 + 4) #define fixblue(x) (x / 829 + 6) #define is_grey(r,g,b) ((r == g) && (r == b)) void select_grey (level, r, g, b) int level, *r, *g, *b; { /* Forced selection of a grey. This is done since the PaintJet does * not do very well when picking greys, they tend to become pink! */ if (level > 66) { /* white */ *r = 90; *g = 88; *b = 85; } else if (level > 35) { *r = 43; *g = 43; *b = 45; } else if (level > 21) { *r = 25; *g = 25; *b = 33; } else if (level > 15) { *r = 15; *g = 16; *b = 18; } else if (level > 11) { *r = 14; *g = 14; *b = 18; } else if (level > 6) { *r = 6; *g = 7; *b = 8; } else { /* black */ *r = 4; *g = 4; *b = 6; } } long find_nearest_programmed_color (); int load_printer_color (index, nearmatch, device) /* for non Direct/TrueColor */ long index; int nearmatch; enum device device; { int n, red, blue, green, xred, xgreen, xblue; long compositeRGB; if (colormap[index] != EMPTY) /* printer has already been programmed for this color index */ return(1); /* "success" */ else { xred = xwd_colors[index].red; xgreen = xwd_colors[index].green; xblue = xwd_colors[index].blue; /* determine the scaled RGB PaintJet color values */ if (device == PJET) { red = fixred(xred); green = fixgreen(xgreen); blue = fixblue(xblue); if (is_grey(xred, xgreen, xblue)) /* assist grey selection */ select_grey(red, &red, &green, &blue); } compositeRGB = (red << 16) | (green << 8) | blue; /* search for a matching or unused PaintJet mapping entry */ for (n=0; nindex == i) { color.indexchain = current; return(current->pjcolor_index); /* found */ } current = current->next; } while (current != start); return(-1); /* not found */ } /* Calculate the individual and composite printer RGB values. (Only the * composite value is set for monochrome output.) */ void select_printer_color (index, red, green, blue, compositeRGB, device) long index; int *red, *green, *blue; long *compositeRGB; enum device device; { int xred, xgreen, xblue; xred = xwd_colors[((index & color.sm.Rmask) >> color.sm.Rshift)].red; xgreen = xwd_colors[((index & color.sm.Gmask) >> color.sm.Gshift)].green; xblue = xwd_colors[((index & color.sm.Bmask) >> color.sm.Bshift)].blue; if (color.PaintJet) { if (color.Invert) { if (RGBmatch((xred & fullintensity), (xgreen & fullintensity), (xblue & fullintensity), fullintensity)) xred = xgreen = xblue = 0; else if (RGBmatch(xred, xgreen, xblue, 0)) xred = xgreen = xblue = fullintensity; } /* determine the scaled RGB PaintJet color values */ if (device == PJET) { *red = fixred(xred); *green = fixgreen(xgreen); *blue = fixblue(xblue); if (is_grey(xred, xgreen, xblue)) /* assist grey selection */ select_grey(*red, red, green, blue); } if (device == PJETXL) { *red = xred >> 8; *green = xgreen >> 8; *blue = xblue >> 8; } *compositeRGB = (*red << 16) | (*green << 8) | *blue; } else /* monochrome */ *compositeRGB = (Intensity(xred, xgreen, xblue) < color.CutOff) ? (color.Invert ? BLACK : WHITE) : (color.Invert ? WHITE : BLACK); } /* Search for a color matching the compositeRGB value in the array of * colors already programmed into the printer. Returns 1 if found, * 0 otherwise. The matching array index is returned in pindex. */ int color_already_in_printer (compositeRGB, pindex) long compositeRGB, *pindex; { int n; for (n=0; n> 16 & 0xFF) - (y >> 16 & 0xFF); long g = (x >> 8 & 0xFF) - (y >> 8 & 0xFF); long b = (x & 0xFF) - (y & 0xFF); return(r*r + g*g + b*b); } long find_nearest_programmed_color (compositeRGB) long compositeRGB; { int n, nearest = 0; long neardiff = composite_diff(pjcolor[0], compositeRGB); long diff; for (n=1; nnext; } /* put index values in the new cell */ new->index = cindex; new->pjcolor_index = pindex; /* link the new cell into the chain */ if (color.indexchain == NULL) new->next = new; else { new->next = color.indexchain->next; color.indexchain->next = new; } /* leave head pointer at the new cell */ color.indexchain = new; } int load_printer_color_DT (index, nearmatch, device) /* for Direct/TrueColor */ long index; int nearmatch; enum device device; { int pjred, pjgreen, pjblue; long compositeRGB; long pindex; if (lookup_color_index(index) >= 0) return(1); /* "success" */ else { select_printer_color(index, &pjred, &pjgreen, &pjblue, &compositeRGB, device); if (color_already_in_printer(compositeRGB, &pindex)) { add_index_to_chain(index, pindex); return(1); /* success */ } else if (program_new_printer_color(pjred, pjgreen, pjblue, compositeRGB, &pindex)) { add_index_to_chain(index, pindex); return(1); /* success */ } else if (nearmatch) { add_index_to_chain(index, find_nearest_programmed_color(compositeRGB)); return(0); /* failure, sorta... */ } } return(0); /* failure */ } int load_line_colors (line, length, nearmatch, device) long *line; int length, nearmatch; enum device device; { int result = 1; /* initialized to "success" */ for (; length>0; length--, line++) { result &= Direct_or_TrueColor ? load_printer_color_DT(*line, nearmatch, device) : load_printer_color(*line, nearmatch, device); if (!(nearmatch || result)) break; } return(result); } void download_colors (line, length, device) long *line; int length; enum device device; { /* For the first attempt at loading the colors for a line only exact * color matches are accepted. If this fails, the closest colors are * accepted on the second attempt. * * Note: The first "if" test below bypasses the initial color loading * attempt for monochrome output (which will only come here for Direct * or TrueColor mono). This forces reset_color_mapping which is * necessary to keep the color index chain down to a tolerable length. */ if (!color.PaintJet || !load_line_colors(line, length, FALSE, device)) { reset_color_mapping(); if (!load_line_colors(line, length, TRUE, device) && !color_warning_given) { fprintf(stderr,(catgets(nlmsg_fd,NL_SETN,9, "%s: Warning: Cannot print all image colors.\n")), progname); color_warning_given = TRUE; } } } void validate_visual() { int depth = xwd_header.pixmap_depth; char *errmsg = catgets(nlmsg_fd,NL_SETN,25, "%d bit deep %s bitmap not supported.\n"); switch (xwd_header.visual_class) { case GrayScale: if (depth > 8) fatal_err2(errmsg, depth, "GrayScale"); break; case StaticGray: if (depth > 8) fatal_err2(errmsg, depth, "StaticGray"); break; case PseudoColor: if (depth > 8) fatal_err2(errmsg, depth, "PseudoColor"); break; case StaticColor: if (depth > 8) fatal_err2(errmsg, depth, "StaticColor"); break; case DirectColor: case TrueColor: if (depth != 12 && depth != 24) fatal_err2(errmsg, depth, (xwd_header.visual_class == DirectColor) ? "DirectColor" : "TrueColor"); break; default: fatal_err2((catgets(nlmsg_fd,NL_SETN,26, "visual class #%d not supported.\n")), xwd_header.visual_class); } } void read_xwd_data (in) FILE *in; { # define WINDOW_NAME_ALLOC 32 unsigned long swaptest = 1; int window_name_size; int image_size; int n; char window_name [WINDOW_NAME_ALLOC]; /* Read in XWDFileHeader structure */ if (fread((char*) &xwd_header, 1, XWDHEADERSIZE, in) != XWDHEADERSIZE) fatal_err((catgets(nlmsg_fd,NL_SETN,10, "Could not read xwd file's header."))); if (*(char *) &swaptest) _swaplong((char *) &xwd_header, XWDHEADERSIZE); validate_visual(); /* Skip over window name */ window_name_size = xwd_header.header_size - XWDHEADERSIZE; while (window_name_size > 0) { n = window_name_size > WINDOW_NAME_ALLOC ? WINDOW_NAME_ALLOC : window_name_size; if (fread(window_name, 1, n, in) != n) fatal_err((catgets(nlmsg_fd,NL_SETN,11, "Could not read xwd file's window name."))); window_name_size -= n; } /* Allocate space for xwd color structures */ if (!(xwd_colors = (XColor*) malloc(sizeof(XColor) * xwd_header.ncolors))) fatal_err((catgets(nlmsg_fd,NL_SETN,12, "Could not allocate memory for xwdfile color table."))); /* Read in xwd color structures */ for (n = 0; n < xwd_header.ncolors; n++) if (fread(&xwd_colors[n], 1, XCOLORSIZE, in) != XCOLORSIZE) fatal_err((catgets(nlmsg_fd,NL_SETN,13, "Could not read xwd file's color table."))); if (*(char *) &swaptest) { for (n = 0; n < xwd_header.ncolors; n++) { _swaplong((char *) &xwd_colors[n].pixel, sizeof(long)); _swapshort((char *) &xwd_colors[n].red, 3 * sizeof(short)); } } /* Allocate space for xwd image */ if (xwd_header.pixmap_format == ZPixmap) image_size = 1; else if (xwd_header.pixmap_format == XYPixmap) image_size = xwd_header.pixmap_depth; else fatal_err((catgets(nlmsg_fd,NL_SETN,14, "Image in xwd file is not in Z or XY pixmap format."))); image_size *= xwd_header.bytes_per_line * xwd_header.pixmap_height; if (!(xwd_image = malloc(image_size))) fatal_err((catgets(nlmsg_fd,NL_SETN,15, "Could not allocate memory for xwd file's image."))); /* Read in xwd image */ if (fread(xwd_image, 1, image_size, in) != image_size) fatal_err((catgets(nlmsg_fd,NL_SETN,16, "Could not read xwd file's image."))); } write_image_prefix (out, scale, density, header, device, position_on_page, initial_formfeed, orient, gamma, render, slide) FILE *out; int scale, density; char *header; enum device device; int position_on_page, initial_formfeed; enum orientation orient; float gamma; int render; int slide; { if (initial_formfeed) fprintf(out,"\014"); /* Write out header & positioning commands */ if (header) { if (position_on_page) fprintf(out,"\033&a%dH\033&a%dV", /* headerloc x & y are written in decipoints */ (int) headerloc.x / 10, (int) headerloc.y / 10); fprintf(out,"%s\n", header); } /* Prepare printer for raster graphics: */ /* Write image positioning commands */ if (position_on_page) fprintf(out,"\033&a%dH\033&a%dV", /* imageloc x & y are written in decipoints */ (int) imageloc.x / 10, (int) imageloc.y / 10); /* If doing transparencies, tell the printer before raster graphics */ if (slide && device != LJET) fprintf(out, "\033&k3W"); /* Set printer resolution */ fprintf(out,"\033*t%dR", density); /* * do device dependent escape sequences */ if (device == PJET) { /* Enable all four "planes" for PaintJet */ fprintf(out,"\033*r4U"); /* Set picture width for PaintJet */ fprintf(out,"\033*r%dS", ((int) (orient == PORTRAIT) ? limit.width : limit.height) * scale); } /* Enable various options for PaintJet XL */ if (device == PJETXL) { double dotsize; int n; /* Speed up printing by telling that there * will be no negative positioning */ fprintf(out, "\033&a1N"); if (gamma > 0.009) fprintf(out, "\033*t%.2fI", gamma); if (render > 0) fprintf(out, "\033*t%dJ", render); if (Direct_or_TrueColor) /* Enable direct by pixel for PaintJet XL */ fwrite("\033*v6W\000\003\010\010\010\010", 1, 11, out); else { /* Enable index by pixel for PaintJet XL */ fwrite("\033*v6W\000\001\010\010\010\010", 1, 11, out); /* Program the palette */ for (n = 0; n < xwd_header.ncolors; n++) { fprintf(out,"\033*v%dA", (xwd_colors[n].red >> 8)); fprintf(out,"\033*v%dB", (xwd_colors[n].green >> 8)); fprintf(out,"\033*v%dC", (xwd_colors[n].blue >> 8)); fprintf(out,"\033*v%dI", n); } } /**************************************** * * * PaintJet XL will do its own scaling * * * * Set picture width for PaintJet XL * ****************************************/ fprintf(out,"\033*r%dS", ((int) (orient == PORTRAIT) ? xwd_header.pixmap_width : xwd_header.pixmap_height)); fprintf(out,"\033*r%dT", ((int) (orient == PORTRAIT) ? xwd_header.pixmap_height : xwd_header.pixmap_width)); dotsize = dot_centipoints(scale, density); fprintf(out,"\033*t%dH", (int)(((orient == PORTRAIT) ? xwd_header.pixmap_width : xwd_header.pixmap_height) * dotsize / 10)); fprintf(out,"\033*t%dV", (int)(((orient == PORTRAIT) ? xwd_header.pixmap_height : xwd_header.pixmap_width) * dotsize / 10)); } /* Switch to raster graphics mode */ if (device != PJETXL) fprintf(out,"\033*r1A"); else fprintf(out,"\033*r3A"); } write_image_suffix (out, trailer, position_on_page, slide, render, device) FILE *out; char *trailer; int position_on_page; int slide, render; enum device device; { /* Exit raster graphics mode */ if (device == PJETXL) fprintf(out,"\033*rC"); else fprintf(out,"\033*rB"); /* If doing transparencies, tell it to stop */ if (slide && device != LJET) fprintf(out, "\033&k1W"); if (device == PJETXL) { /* If selected a rendering algorithm, tell it to stop */ if (render) fprintf(out, "\033*t3J"); fprintf(out, "\033&a0N"); } /* Write out trailer & positioning commands */ if (trailer) { if (position_on_page) fprintf(out,"\033&a%dH\033&a%dV", /* trailerloc x & y are written in decipoints */ (int) trailerloc.x / 10, (int) trailerloc.y / 10); fprintf(out,"%s\n", trailer); } } unsigned long Z_image_pixel (x, y) int x, y; { int pixel_bytes, offset; unsigned char *image; unsigned long pixel; pixel_bytes = xwd_header.bits_per_pixel >> 3; offset = ((xwd_header.bits_per_pixel == 4) ? (x / 2) : ((xwd_header.bits_per_pixel == 1) ? (x / 8) : (x * pixel_bytes))) + (y * xwd_header.bytes_per_line); image = (unsigned char *) &xwd_image[offset]; switch (pixel_bytes) { case 0: /* pixel per nibble or bit per pixel packing */ if (xwd_header.bits_per_pixel == 1) { if (xwd_header.byte_order == MSBFirst) pixel = *image >> (7 - (x % 8)); else pixel = *image >> (x % 8); } else { /* xwd_header.bits_per_pixel == 4 */ if (xwd_header.byte_order == MSBFirst) pixel = (x & 1) ? *image : (*image >> 4); else pixel = (x & 1) ? (*image >> 4) : *image; } break; case 1: pixel = *image; break; case 2: pixel = (xwd_header.byte_order == MSBFirst) ? ((unsigned long)*image << 8 | *(image + 1)) : (*image | (unsigned long)*(image + 1) << 8); break; case 3: pixel = (xwd_header.byte_order == MSBFirst) ? ((unsigned long)*image << 16 | (unsigned long)*(image + 1) << 8 | (unsigned long)*(image + 2)) : (*image | (unsigned long)*(image + 1) << 8 | (unsigned long)*(image + 2) << 16); break; case 4: pixel = (xwd_header.byte_order == MSBFirst) ? ((unsigned long)*image << 24 | (unsigned long)*(image+1) << 16 | (unsigned long)*(image+2) << 8 | *(image+3)) : (*image | (unsigned long)*(image+1) << 8 | (unsigned long)*(image+2) << 16 | (unsigned long)*(image+3) << 24); break; } return (pixel & Z_pixel_mask); } unsigned long XY_image_pixel (x, y) int x, y; { int plane_start, line_start, bytes_per_bitmap_unit, bitmap_unit_start, byte_within_bitmap_unit, offset, byte_mask; plane_start = (xwd_header.pixmap_depth - 1) * xwd_header.pixmap_height * xwd_header.bytes_per_line; line_start = xwd_header.bytes_per_line * y; bytes_per_bitmap_unit = xwd_header.bitmap_unit >> 3; bitmap_unit_start = (x / xwd_header.bitmap_unit) * bytes_per_bitmap_unit; byte_within_bitmap_unit = (xwd_header.byte_order == MSBFirst) ? (x % xwd_header.bitmap_unit) >> 3 : bytes_per_bitmap_unit - ((x % xwd_header.bitmap_unit) >> 3) - 1; offset = plane_start + line_start + bitmap_unit_start + byte_within_bitmap_unit; byte_mask = (xwd_header.bitmap_bit_order == MSBFirst) ? 0x80 >> (x % 8) : 0x01 << (x % 8); return(xwd_image[offset] & byte_mask ? 1 : 0); } void direct_by_pixel(out, line, length, device) FILE *out; long *line; int length; enum device device; { int red, green, blue; long compositeRGB; fprintf(out, "\033*b%dW", length * 3); for (; length>0; length--, line++) { select_printer_color(*line, &red, &green, &blue, &compositeRGB, device); fprintf(out, "%c%c%c", (char) red, (char) green, (char) blue); } } void index_by_pixel(out, line, length) FILE *out; long *line; int length; { register int n; long *lp; char *line_pixels; register char *lc; if (!(line_pixels = malloc(length))) fatal_err((catgets(nlmsg_fd,NL_SETN,17, "Could not allocate raster line memory."))); for (n=0, lc=line_pixels, lp=line; n 0) { bit = (*lc++ >> p) & 0x01; e = scale; while (e--) { byte = (byte << 1) | bit; bytebits++; if (bytebits == 8) { *rl++ = byte; bytebits = 0; } } } if (bytebits) *rl = byte << (8 - bytebits); } e = scale; while (e--) { for (p=0; p=0; y--) *lp++ = Z_image_pixel(x,y); write_raster_line(out, scale, device, line, width); } } void write_portrait_XY_image (out, scale, device) FILE *out; int scale; enum device device; { int x, y; int width = limit.width; int height = limit.height; long *line, *lp; if (!(line = (long *) malloc(width * sizeof(long)))) fatal_err((catgets(nlmsg_fd,NL_SETN,20, "Could not allocate memory for image line buffer."))); for (y=0; y=0; y--) *lp++ = XY_image_pixel(x,y); write_raster_line(out, scale, device, line, width); } } void write_Z_image (out, scale, orient, device) FILE *out; int scale; enum orientation orient; enum device device; { if (orient == PORTRAIT) { write_portrait_Z_image(out, scale, device); } else write_landscape_Z_image(out, scale, device); } void write_XY_image (out, scale, orient, device) FILE *out; int scale; enum orientation orient; enum device device; { if (xwd_header.pixmap_depth > 1) fatal_err((catgets(nlmsg_fd,NL_SETN,22, "XY format image, multiplane images must be Z format."))); if (orient == PORTRAIT) { write_portrait_XY_image(out, scale, device); } else write_landscape_XY_image(out, scale, device); } void write_image (out, scale, orient, device) FILE *out; int scale; enum orientation orient; enum device device; { switch (xwd_header.pixmap_format) { case XYPixmap: write_XY_image(out, scale, orient, device); break; case ZPixmap: write_Z_image(out, scale, orient, device); break; default: fatal_err((catgets(nlmsg_fd,NL_SETN,23, "image not in XY or Z format."))); } } void x2jet(in, out, scale, density, width, height, left, top, header, trailer, orient, invert, initial_formfeed, position_on_page, slide, device, cutoff, gamma, render) FILE *in, *out; int scale, density; int width, height, left, top; /* in 300ths of an inch */ char *header, *trailer; enum orientation orient; int invert, initial_formfeed, position_on_page, slide; enum device device; unsigned int cutoff; float gamma; int render; { int paintjet = FALSE; true_scale = scale; if (device != LJET) paintjet = TRUE; read_xwd_data(in); Z_pixel_mask = ~(0xFFFFFFFFL << xwd_header.pixmap_depth); prepare_color_mapping(invert, paintjet, cutoff, out); scale_and_orient_image(&scale, &density, width, height, left, top, header, trailer, &orient, position_on_page, device); write_image_prefix(out, scale, density, header, device, position_on_page, initial_formfeed, orient, gamma, render, slide); write_image(out, scale, orient, device); write_image_suffix(out, trailer, position_on_page, slide, render, device); fclose(out); } void fatal_err (s) char * s; { fprintf(stderr, "%s: %s\n", progname, s); exit(1); } void fatal_err2 (s, a1, a2, a3) char *s; char *a1, *a2, *a3; { fprintf(stderr, "%s: ", progname); fprintf(stderr, s, a1, a2, a3); exit(1); }