diff options
author | Roland Mainz <roland.mainz@nrubsig.org> | 2004-10-31 02:14:06 +0000 |
---|---|---|
committer | Roland Mainz <roland.mainz@nrubsig.org> | 2004-10-31 02:14:06 +0000 |
commit | 9a961d11bea6be64c6f51b4f0829ff4fe2999c4a (patch) | |
tree | 57cfce3fd2b08d2e200ea4566f36021b93b607ff |
Fix for https://freedesktop.org/bugzilla/show_bug.cgi?id=631 - Uploading
"xpr" and "pclcomp" as they are needed for the RASTER and PCL drivers
on some platforms.
-rw-r--r-- | lncmd.h | 52 | ||||
-rw-r--r-- | pmp.h | 66 | ||||
-rw-r--r-- | x2jet.c | 1577 | ||||
-rw-r--r-- | x2pmp.c | 363 | ||||
-rw-r--r-- | xdpr.man | 137 | ||||
-rw-r--r-- | xdpr.script | 166 | ||||
-rw-r--r-- | xpr.c | 1915 | ||||
-rw-r--r-- | xpr.h | 33 | ||||
-rw-r--r-- | xpr.man | 338 |
9 files changed, 4647 insertions, 0 deletions
@@ -0,0 +1,52 @@ +/* $XConsortium: lncmd.h,v 10.8 94/04/17 20:44:03 rws Exp $ */ +/* + +Copyright (c) 1985 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. + +*/ + + +/* lncmd.h - Command sequences DEC printers, in particular LN0x laser + printers */ + +/* +#define LN_RIS "\033c" Obsolete; causes LN03+ problems +*/ +#define LN_STR "\033[!p" +#define LN_SSU "\033[%d I" +#define LN_PUM_SET "\033[11h" +#define LN_PFS "\033[%s J" +#define LN_DECSLRM "\033[%d;%ds" +#define LN_HPA "\033[%d`" +#define LN_VPA "\033[%dd" +#define LN_SIXEL_GRAPHICS "\033P%d;%d;%dq" +#define LN_ST "\033\\" +#define LN_DECOPM_SET "\033[?52h" +#define LN_DECOPM_RESET "\033[?52I" +#define LN_SGR "\033[1%dm" +#define LN_PUM "\033[11I" +#define LN_LNM "\033[20h" @@ -0,0 +1,66 @@ +/* + * $XConsortium: pmp.h,v 1.5 91/02/19 22:13:33 converse Exp $ + */ + +/* Written by Jose' J. Capo' */ +/* (jjc@comet.lcs.mit.edu), June 1987 */ + +/* WARNING!!!: Include this header after the standard headers (like */ + /* <stdio.h>) of the following might cause another header to */ + /* redefine BUFSIZ */ +#ifndef BUFSIZ +#define BUFSIZ 1024 +#endif + +#define MAX_FRAME_LEN 512 +#define MAX_VECTOR_LEN 65535 + +#define DBG(cond) if (dbg cond) +#define DEBUG(cond) if (debug cond) +#define min(a,b) ((a) < (b)? (a) : (b)) + +#define pel2inch(pels) ((float) ((pels) / PPI)) +#define ppmask(rounded,thickness) (0x20 * (rounded) + (thickness)) + + +#define min(a,b) ((a) < (b)? (a) : (b)) +#define lo(x) ((x) & 0xFF) +#define hi(x) (((x) & 0xFF00) >>8) +#define hi2(x) (((x) & 0xFF0000) >>16) +#define p_wput(w, f) {\ + (void) putc(hi(w), (f)); \ + (void) putc(lo(w), (f));\ + } +#define PMP(f, len) { fprintf(f, "\033[C"); \ + p_putlh(f, len);\ + } +#define p_putlh(f, w) {\ + (void) putc(lo(w), (f));\ + (void) putc(hi(w), (f)); \ + } + +/* hi-lo 2-byte integer */ +/* int hl2int(unsigned char *) */ +#define hl2int(hl2) ((int) (0x100 * *(hl2) + *((hl2)+1))) + +/* putlh2(FILE *, int) */ +#define puthl2(i, f) { (void) putc(hi((i)), (f));\ + (void) putc(lo((i)), (f));\ + } + +/* hi-lo 3-byte integer */ +/* long hl3long(unsigned char *) */ +#define hl3long(hl3) ((long) (0x10000 * *(hl3) + \ + 0x100 * *((hl3)+1) + *((hl3)+2))) + +/* puthl3(FILE *, long) */ +#define puthl3(l, f) { (void) putc(hi2((l)), (f));\ + (void) putc(hi((l)), (f));\ + (void) putc(lo((l)), (f));\ + } + +/* int int2sgn(int) */ +#define int2sgn(i) (((i) > 0x8000 - 1)? (i)- 0x10000: (i)) + +/* int long3sgn(long) */ +#define long3sgn(l) (((l) > 0x800000 - 1)? (l) - 0x1000000 : (l)) @@ -0,0 +1,1577 @@ +/* $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 <stdio.h> +#include <X11/Xlib.h> +#include <X11/XWDFile.h> + +#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 <nl_types.h> + +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<v_scale) ? h_scale : v_scale) + : 1); +} + + +scale_and_orient_image (scale, density, width, height, left, top, + header, trailer, + orient, position_on_page, device) +int *scale, *density; +int width, height, left, top; /* in 300ths of an inch */ +char *header, *trailer; +enum orientation *orient; +int position_on_page; +enum device device; +{ + Area usable; + + /* Determine printable area expressed in centipoints. There are 7200 + * centipoints to the inch. The width and height parameters passed in + * are expressed in 300ths of an inch, therefore a 24x conversion factor + * is used on the parameter values. The default page dimensions STDWIDTH + * and STDHEIGHT are expressed in inches so must be multiplied by 7200 + * to convert to centipoints. + */ + page.width = (width >= 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; n<MAX_PJ_COLOR; n++) + pjcolor[n] = EMPTY; + + if (!color.PaintJet) { + /* preload for monochrome output */ + pjcolor[0] = WHITE; + pjcolor[1] = BLACK; + } + + if (Direct_or_TrueColor) { + /* move color index chain cells onto the free list */ + if (color.indexchain != NULL) { + splice = color.indexchain->next; + 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; n<MAX_PJ_COLOR; n++) { + if (pjcolor[n] == compositeRGB) { + /* record mapping for this index */ + colormap[index] = n; + /* return "success" */ + return(1); + } else if (pjcolor[n] == EMPTY) { + /* download color to printer */ + fprintf(color.OutFile,"\033*v%dA", red); + fprintf(color.OutFile,"\033*v%dB", green); + fprintf(color.OutFile,"\033*v%dC", blue); + fprintf(color.OutFile,"\033*v%dI", n); + /* record that this is now programmed */ + pjcolor[n] = compositeRGB; + colormap[index] = n; + /* return "success" */ + return(1); + } + } + /* unable to find or program this color */ + if (nearmatch) + colormap[index] = find_nearest_programmed_color(compositeRGB); + } + return(0); /* "failure" */ +} + + +/* Lookup the image color index on the color.indexchain list. If found + * return the corresponding printer color index, otherwise -1. The index + * chain is a singly linked circular list. Its head pointer is left at + * the last cell matched on the theory that this will allow faster lookup + * for runs of color. + */ +int lookup_color_index (i) +long i; +{ + COLORINDEX *start, *current; + + start = current = color.indexchain; + + if (current == NULL) + return(-1); /* not found */ + + do { + if (current->index == 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<MAX_PJ_COLOR; n++) + if (pjcolor[n] == EMPTY) + return(0); /* not found */ + else if (pjcolor[n] == compositeRGB) { + *pindex = n; + return(1); /* found */ + } + return(0); /* not found */ +} + + +int program_new_printer_color (red, green, blue, compositeRGB, pindex) +int red, green, blue; +long compositeRGB; +long *pindex; +{ + int n; + + for (n=0; n<MAX_PJ_COLOR; n++) + if (pjcolor[n] == EMPTY) { + /* download color to printer */ + fprintf(color.OutFile,"\033*v%dA", red); + fprintf(color.OutFile,"\033*v%dB", green); + fprintf(color.OutFile,"\033*v%dC", blue); + fprintf(color.OutFile,"\033*v%dI", n); + /* record that this is now programmed */ + pjcolor[n] = compositeRGB; + *pindex = n; + /* return "success" */ + return(1); + } + /* unable to program this color, return "failure" */ + return(0); +} + + + +long composite_diff (x, y) +long x, y; +{ + long r = (x >> 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; n<MAX_PJ_COLOR; n++) { + diff = composite_diff(pjcolor[n], compositeRGB); + if (diff < neardiff) { + neardiff = diff; + nearest = n; + } + } + return(nearest); +} + + +void add_index_to_chain (cindex, pindex) +long cindex; +long pindex; +{ + COLORINDEX *new; + + /* Get a new cell for the color index chain. Take it from the free list + * if possible, otherwise malloc space. + */ + if (color.freechain == NULL) { + if (!(new = (COLORINDEX *) malloc(sizeof(COLORINDEX)))) + fatal_err((catgets(nlmsg_fd,NL_SETN,8, + "Could not allocate memory for color translation."))); + } else { + new = color.freechain; + color.freechain = color.freechain->next; + } + + /* 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<length; n++) + *lc++ = (char) *lp++; + + fprintf(out, "\033*b%dW", length); + fwrite(line_pixels, 1, length, out); + + free(line_pixels); +} + + +void write_raster_line (out, scale, device, line, length) +FILE *out; +int scale; +enum device device; +long *line; +int length; +{ + int planes = (device == PJET) ? 4 : 1; + int raster_bytes = (length * scale + 7) / 8; + register int bytebits, n, p, e, bit; + long *lp; + char *line_colors, *raster_line; + register char *lc, *rl, byte = 0; + + if (device == PJETXL) { + if (Direct_or_TrueColor) + direct_by_pixel(out, line, length, device); + else + index_by_pixel(out, line, length); + return; + } + + if (!(line_colors = malloc(length)) + || !(raster_line = malloc(raster_bytes * planes))) + fatal_err((catgets(nlmsg_fd,NL_SETN,17, + "Could not allocate raster line memory."))); + + if (device == PJET || Direct_or_TrueColor) + download_colors(line, length, device); + + /* Map the line's colors into output color index numbers */ + if (Direct_or_TrueColor) + for (n=0, lc=line_colors, lp=line; n<length; n++) + *lc++ = (char) lookup_color_index(*lp++); + else + for (n=0, lc=line_colors, lp=line; n<length; n++) + *lc++ = (char) colormap[*lp++]; + + for (p=0; p<planes; p++) { + bytebits = 0; + n = length; + lc = line_colors; + rl = &raster_line[raster_bytes * p]; + while (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<planes; p++) { + fprintf(out,"\033*b%d%c", raster_bytes, (p+1 == planes) ? 'W' : 'V'); + fwrite(&raster_line[raster_bytes * p], 1, raster_bytes, out); + } + } + + free(line_colors); + free(raster_line); +} + + +void write_portrait_Z_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,18, + "Could not allocate memory for image line buffer."))); + + for (y=0; y<height; y++) { + + for (x=0, lp=line; x<width; x++) + *lp++ = Z_image_pixel(x,y); + + write_raster_line(out, scale, device, line, width); + } +} + + + +void write_landscape_Z_image (out, scale, device) +FILE *out; +int scale; +enum device device; +{ + int x, y; + int width = limit.height; + int height = limit.width; + long *line, *lp; + + if (!(line = (long *) malloc(width * sizeof(long)))) + fatal_err((catgets(nlmsg_fd,NL_SETN,19, + "Could not allocate memory for image line buffer."))); + + for (x=0; x<height; x++) { + + for (y=width-1, lp=line; y>=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<height; y++) { + + for (x=0, lp=line; x<width; x++) + *lp++ = XY_image_pixel(x,y); + + write_raster_line(out, scale, device, line, width); + } +} + + + +void write_landscape_XY_image (out, scale, device) +FILE *out; +int scale; +enum device device; +{ + int x, y; + int width = limit.height; + int height = limit.width; + long *line, *lp; + + if (!(line = (long *) malloc(width * sizeof(long)))) + fatal_err((catgets(nlmsg_fd,NL_SETN,21, + "Could not allocate memory for image line buffer."))); + + for (x=0; x<height; x++) { + + for (y=width-1, lp=line; 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); +} @@ -0,0 +1,363 @@ +/* + * $XConsortium: x2pmp.c,v 1.13 91/07/25 17:56:32 rws Exp $ + */ + +/* x2pmp.c: Translate xwd window dump format into PMP format for the + * IBM 3812 PagePrinter. + */ +#include <stdio.h> +#include <math.h> +#include <X11/Xlib.h> +#include <X11/XWDFile.h> +#include <X11/Xfuncs.h> +#include <errno.h> + +#include "pmp.h" +#include "xpr.h" + +#define max_(a, b) (a) > (b) ? (a) : (b) +#define min_(a, b) (a) < (b) ? (a) : (b) +#define abs_(a) (a) < 0 ? -(a) : (a) + +static void leave(); +static bits_set(); +static unsigned char *magnification_table(); + +/* global variables set by main() and used by x2pmp() */ +extern char *progname; +extern int debug; + +static plane = 0; +#define FONT_HEIGHT 40 +#define FONT_HEIGHT_PIXELS (FONT_HEIGHT*75/PPI) +#define FONT_WIDTH 24 + +void x2pmp(in, out, scale, p_width, p_length, x_pos, y_pos, + head, foot, orient, invert) +FILE *in, *out; +int scale; +int p_width, p_length, x_pos, y_pos; /* in pels (units of PPI) */ +char *head, *foot; +enum orientation orient; +int invert; +{ + unsigned char *buffer, *win_name; + unsigned int win_name_size, width, height, ncolors; + unsigned int buffer_size, one_plane_size, byte_width, fixed_width; + int no_of_bits; + unsigned long swaptest = 1; + XWDFileHeader header; + + /* Read header from file */ + if (fread((char *)&header, sizeof(header), 1, in) != 1) + if (feof(in)) + return; + else + leave("fread"); + if (*(char *) &swaptest) + _swaplong((char *) &header, sizeof(header)); + + if (header.file_version != XWD_FILE_VERSION) { + fprintf(stderr,"%s: file format version %d, not %d\n", progname, + header.file_version, XWD_FILE_VERSION); + } + + win_name_size = abs_(header.header_size - sizeof(header)); + if ((win_name = (unsigned char *) + calloc(win_name_size, (unsigned) sizeof(char))) == NULL) + leave("Can't calloc window name storage."); + + /* Read window name from file */ + if (fread((char *) win_name, sizeof(char), (int) win_name_size, in) != + win_name_size) + leave("Unable to read window name from dump file."); + DEBUG(>= 1) + fprintf(stderr,"win_name =%s\n", win_name); + + width = header.pixmap_width; + height = header.pixmap_height; + fixed_width = 8 * (byte_width = header.bytes_per_line); + one_plane_size = byte_width * height; + buffer_size = one_plane_size * + ((header.pixmap_format == ZPixmap)? header.pixmap_depth: 1); + + /* Determine orientation and scale if not specified */ + if (orient == UNSPECIFIED) + orient = (fixed_width <= height)? PORTRAIT: LANDSCAPE; + if (scale <= 0) { + int real_height = height; + if (head) real_height += FONT_HEIGHT_PIXELS << 1; + if (foot) real_height += FONT_HEIGHT_PIXELS << 1; + switch(orient) { + case PORTRAIT: + case UPSIDE_DOWN: + scale = min_((p_width - 2*x_pos) / fixed_width, + (p_length - 2*y_pos) / real_height); + break; + case LANDSCAPE: + case LANDSCAPE_LEFT: + scale = min_((p_length - 2*y_pos) / fixed_width, + (p_width - 2*x_pos) / real_height); + break; + } + if (scale <= 0) + leave("PixMap doesn't fit on page."); + else DEBUG(>1) + fprintf(stderr, "scaling by %d to yield %d x %d image\n", + scale, fixed_width*scale, height*scale); + } + + ncolors = header.ncolors; + if (ncolors) { + int i; + XColor *colors = (XColor *)malloc((unsigned) (header.ncolors * sizeof(XColor))); + + if (fread((char *)colors, sizeof(XColor), ncolors, in) != ncolors) + leave("Unable to read colormap from dump file."); + + if (*(char *) &swaptest) { + for (i = 0; i < ncolors; i++) { + _swaplong((char *) &colors[i].pixel, (long)sizeof(long)); + _swapshort((char *) &colors[i].red, (long) (3 * sizeof(short))); + } + } + if (ncolors == 2 && INTENSITY(&colors[0]) > INTENSITY(&colors[1])) + invert = !invert; + free( colors ); + } + + invert = !invert; /* 3812 puts ink (i.e. black) on 1-bits */ + + if ((buffer = (unsigned char *) calloc(buffer_size, 1)) == NULL) + leave("Can't calloc data buffer."); + bzero((char *) buffer, (int) buffer_size); + + /* Read bitmap from file */ + if (fread((char *) buffer, sizeof(char), (int) buffer_size, in) + != buffer_size) + leave("Unable to read pixmap from dump file."); + + if (header.bitmap_bit_order == LSBFirst) + { + unsigned char bitswap[256], *bp; + int c; + for(c = 256; c--;) { + bitswap[c] = ((c & 01) << 7) + ((c & 02) << 5) + ((c & 04) << 3) + + ((c & 010) << 1) + ((c & 020) >> 1) + ((c & 040) >> 3) + + ((c & 0100) >> 5) + ((c & 0200) >> 7); + if (invert) + bitswap[c] = ~bitswap[c]; + } + /* Here's where we do the bitswapping. */ + for(bp = buffer+buffer_size; bp-- > buffer;) + *bp = bitswap[*bp]; + } + else if (invert) { + unsigned char *bp; + for(bp = buffer+buffer_size; bp-- > buffer;) + *bp = ~*bp; + } + + /* we don't want the last bits up to the byte/word alignment set */ + if (no_of_bits = fixed_width - width) { + int i, j, mask = ~bits_set(no_of_bits % 8); + for(i = 0; i < height; i++) { + unsigned char *s = buffer + (i+1) * byte_width ; + + for(j = no_of_bits / 8; j--;) + *--s = 0; + *--s &= mask; + } + } + + DEBUG(>= 1) + fprintf(stderr,"read %d bytes for a %d (%d bytes) x %d image\n", + buffer_size, (int) width, byte_width, (int) height); + /* Scale the bitmap */ + if (scale > 1) { + unsigned char *tbl = magnification_table(scale); + unsigned char *scale_buf; + int i, j, k; + + if ((scale_buf = (unsigned char *) + calloc((unsigned) (buffer_size *= scale*scale), sizeof(char))) + == NULL) + leave("Can't calloc scaled buffer."); + for(i = 0; i < height; i++) { + unsigned char *src, *ss; + src = buffer + i * byte_width ; + ss = scale_buf + i * scale * scale * byte_width; + for(j = 0; j < byte_width; j++) { + unsigned char *dst = ss+j*scale; + unsigned char *expansion = tbl+scale*src[j]; + for(k = 0; k < scale; k++, dst += byte_width*scale) { + bcopy((char *) expansion, (char *) dst, scale); + } + } + } + free((char *) buffer); + free((char *) tbl); + buffer = scale_buf; + byte_width *= scale; + width *= scale; + fixed_width *= scale; + height *= scale; + one_plane_size *= scale*scale; + } + DEBUG(==3) { + int i, j, k; + unsigned char *s; + + fprintf(stderr, "dumping %d x %d grid\n", fixed_width, height); + for(i = 0; i < height; i++) { + s = buffer + i * byte_width ; + for(j = 0; j < byte_width; j++) + for(k = 8; k--;) + (void) putc((s[j] & 1<<k)? '*': '-', stderr); + (void) putc('\n', stderr); + } + } + p_set_orientation(out, orient); + p_restore_cursor(out, 0); + p_save_cursor(out, 3); + if (head != NULL) { + p_move_abs( out, x_pos + (width - strlen(foot)*FONT_WIDTH) >> 1, + y_pos - FONT_HEIGHT ); + fprintf(out, "%s\n", head); + } + if (foot != NULL) { + p_move_abs( out, x_pos + (width - strlen(foot)*FONT_WIDTH) >> 1, + y_pos + height + (FONT_HEIGHT << 1) ); + fprintf(out, "%s\n", foot); + } + p_move_abs(out, x_pos, y_pos); + p_bitmap(out, height, fixed_width, (unsigned long) one_plane_size, + buffer + plane * one_plane_size); + free((char *) win_name); + free((char *) buffer); +} + +static unsigned char *magnification_table(scale) +int scale; +{ + unsigned char *tbl; + int c; + + if ((tbl = (unsigned char *) + calloc((unsigned) (scale*256), sizeof(char))) == NULL) + leave("Can't calloc magnification table."); + bzero((char *) tbl, scale*256); + for(c = 256; c--;) { + int b = c, bit; + unsigned char *entry = tbl+c*scale; + + while (b) { + int i, last, mask; + bit = 1; + mask = b; + while (! (mask & 1)) { + bit++; + mask = mask >> 1; + } + last = scale*(bit-1); + for(i = scale*bit; i-- > last ;) + entry[(scale - 1) - i / 8] |= 1 << (i % 8); + b &= ~(1 << bit-1); + } + } + return tbl; +} + +/* returns 2^n-1, i.e. a number with bits n-1 through 0 set. + * (zero for n == 0) */ +static bits_set(n) +int n; +{ + int ans = 0; + while(n--) + ans |= 1 << n; + return ans; +} + +static void leave(s) +char *s; +{ + extern int errno; + + fprintf(stderr, "\n%s: ", progname); + if (errno != 0) + perror(s); + else + fprintf(stderr, "%s", s); + fprintf(stderr, "\n"); + exit(1); +} + +/* move to coordinates x, y (in pels) */ +p_move_abs(p, x, y) +FILE *p; +int x, y; +{ + if (x >= 0) { + PMP(p, 3); + (void) putc('\340', p); + p_wput(x, p); + } + if (y >= 0) { + PMP(p, 3); + (void) putc('\341', p); + p_wput(y, p); + } +} + +/* save current cursor position into (printer) register reg */ +p_save_cursor(p, reg) +FILE *p; +int reg; +{ + PMP(p, 1); + (void) putc(reg + '\200', p); +} + +/* restore current cursor position from (printer) register reg */ +p_restore_cursor(p, reg) +FILE *p; +int reg; +{ + PMP(p, 1); + (void) putc(reg + '\220', p); +} + +/* set the page orientation to orient (see pmp.h) */ +p_set_orientation(p, orient) +FILE *p; +enum orientation orient; +{ + PMP(p, 2); + fprintf(p, "\322%c", (int) orient); +} + +/* generate bitmap */ +p_bitmap(p, h, w, buflen, buf) +FILE *p; +unsigned int h, w; +unsigned long buflen; +unsigned char *buf; +{ + PMP(p, 9); + (void) fwrite("\365\0", 1, 2, p); + puthl2(h, p); + puthl2(w, p); + puthl3(buflen, p); + + while(buflen) { + int len; + + len = min(buflen, MAX_VECTOR_LEN); + PMP(p, len); + (void) fwrite((char *) buf, 1, len, p); + buf += len; + buflen -= len; + } + (void) fflush(p); +} diff --git a/xdpr.man b/xdpr.man new file mode 100644 index 0000000..79a5844 --- /dev/null +++ b/xdpr.man @@ -0,0 +1,137 @@ +.\" $XConsortium: xdpr.man,v 1.15 94/04/17 20:44:04 gildea Exp $ +.TH XDPR 1 "Release 6" "X Version 11" +.SH NAME +xdpr \- dump an X window directly to a printer +.SH SYNOPSIS +.B xdpr +[ +.I filename +] +[ +.B \-display +.I host:display +] +[ +.B \-P\fIprinter\fP +] +[ +.B \-device +.I devtype +] +[ +.I option +\&.\|.\|. +] + +.SH DESCRIPTION +.I Xdpr +uses the commands +.I xwd, +.I xpr, +and +.I lpr +or +.I lp +to dump an X window, process it for a particular printer type, and +print it out on the printer of your choice. This is the easiest way +to get a printout of a window. \fIXdpr\fP by default will print the +largest possible representation of the window on the output page. +.PP +The options for \fIxdpr\fP are the same as those for \fIxpr\fP, +\fIxwd\fP, and \fIlpr\fP or \fIlp\fP. +The most commonly-used options are described +below; see the manual pages for these commands for +more detailed descriptions of the many options available. +.SH OPTIONS +.TP +.I filename +Specifies a file containing a window dump (created by \fIxwd\fP) to be +printed instead of selecting an X window. +.TP +.B \-P\fIprinter\fP +Specifies a printer to send the output to. If a printer name is not +specified here, \fIxdpr\fP (really, \fIlpr\fP or \fIlp\fP) +will send your output to the +printer specified by the \fIPRINTER\fP environment variable. +Be sure that type of the printer matches the type specified +with the \fI\-device\fP option. +.TP +.B \-display \fIhost:display\fP[\fI.screen\fP] +.cm .IB host : display +Normally, +.I xdpr +gets the host and display number to use from the environment +variable ``DISPLAY.'' +One can, however, specify them explicitly; see \fIX\fP(1). +.TP +.B \-device \fIdevtype\fP +Specifies the device on which the file will be printed. Currently supported: +.RS 12 +.PD 0 +.TP +.B la100 +Digital LA100 +.TP +.B ljet +\s-1HP\s+1 LaserJet series and other monochrome PCL devices +such as ThinkJet, QuietJet, RuggedWriter, \s-1HP\s+12560 series, +and \s-1HP\s+12930 series printers +.TP +.B ln03 +Digital LN03 +.TP +.B pjet +HP PaintJet (color mode) +.TP +.B pjetxl +HP HP PaintJet XL Color Graphics Printer (color mode) +.TP +.B pp +IBM PP3812 +.TP +.B ps +PostScript printer +.PD +.RE +.IP +The default is PostScript. +\fB\-device lw\fP (LaserWriter) is equivalent to \fB\-device ps\fP and is +provided only for backwards compatibility. +.TP +.B \-help +This option displays the list of options known to +.I xdpr. +.PP +Any other arguments +will be passed to the +.I xwd, +.I xpr, +and +.I lpr +or +.I lp +commands as appropriate for each. +.SH SEE ALSO +.IR xwd (1), +.IR xpr (1), +.IR lpr (1), +.IR lp (1), +.IR xwud (1), +.IR X (1) +.SH ENVIRONMENT +.TP 10 +DISPLAY +which display to use by default. +.TP 10 +PRINTER +which printer to use by default. +.SH COPYRIGHT +Copyright ([\d,\s]*) X Consortium +.br +See \fIX(1)\fP for a full statement of rights and permissions. +.SH AUTHORS +Paul Boutin, MIT Project Athena +.br +Michael R. Gretzinger, MIT Project Athena +.br +Jim Gettys, MIT Project Athena diff --git a/xdpr.script b/xdpr.script new file mode 100644 index 0000000..3ca4eb2 --- /dev/null +++ b/xdpr.script @@ -0,0 +1,166 @@ +#! /bin/sh +# Copyright 1985,1988 Massacusetts Institute of Technology. +# $XConsortium: xdpr.script /main/10 1995/12/08 11:10:59 swick $ +# origin: William Kucharski, Solbourne Computer, Inc. 3/24/90 +# translated from csh script xdpr.script "paul 4/12/88" + +# initialize variables + +display="$DISPLAY" +header= +bsdlprv= +lprv= +out= +svlprv= +trailer= +xprv= +xwdv= + +usage="Usage: xdpr [filename] [-out filename ] \ +[-display host:display] [[-Pprinter] | [-dprinter]] [-device devtype] \ +[{-root | -id <id> | -name <name>}] [-nobdrs] [-xy] \ +[-scale scale] [-height inches] [-width inches] [-left inches] \ +[-top inches] [-split n] [-header string] [-trailer string] \ +[-landscape] [-portrait] [-rv] [-compact] [-noff] [-frame] \ +[-plane number] [-gray number] [-psfig] [-density dpi] \ +[-cutoff level] [-noposition] [-gamma correction] [-render algorithm] \ +[-slide] [-add value] [-help]" + +# Guess if we are BSD or System V + +if [ -x /usr/ucb/lpr -o -x /usr/bin/lpr -o -x /bin/lpr -o -x /usr/bsd/lpr ] +then + LP=lpr + BSD=1 +elif [ -x /usr/bin/lp -o -x /bin/lp ] +then + LP=lp + BSD=0 +else + LP=lpr + BSD=1 +fi + +# parse arguments... + +while [ $1 ]; do + case "$1" in + +# ...arguments interpreted by xdpr itself... + + -help) + echo $usage; + exit 0;; + +# ...arguments to xwd... + + -nobdrs|-root|-xy|-frame) + xwdv="$xwdv $1";; + -display) + display=$2 + xwdv="$xwdv $1 $2"; + shift;; + -id|-name) + xwdv="$xwdv $1 $2"; + shift;; + -out|-add) + out=true + xwdv="$xwdv $1 $2"; + shift;; + +# ...arguments to xpr... + + -scale|-height|-width|-left|-top|-split|-device) + xprv="$xprv $1 $2"; + shift;; + -plane|-gray|-density|-cutoff|-gamma|-render) + xprv="$xprv $1 $2"; + shift;; + -header) + shift; + header="$1";; + -trailer) + shift; + trailer="$1";; + -landscape|-portrait|-rv|-compact|-noff|-psfig|-noposition|-slide) + xprv="$xprv $1";; + +# ...arguments to lp[r]... + + -P*|-#?*|-C?*|-J?*|-h|-m) + bsdlprv="$lprv $1";; + + -d*|-H*|-q*|-n*|-o*|-w) + svlprv="$svlprv $1";; + +# ...disallow other arguments; print usage message + + -*) + echo "xdpr: Unknown option $1"; + echo $usage; + exit 1;; + +# ...input filename... + + *) + if [ ! "$infile" ]; then + infile=true + xprv="$xprv $1" + else + echo "xdpr: Invalid argument "$1"" + echo $usage + exit 1 + fi + esac + shift +done + +# quit if there is no DISPLAY specified + +if [ ! "$display" ]; then + echo "xdpr: DISPLAY variable must be set or a display specified." + exit +fi + +# Command lines: + +# Set up lp[r] options... + +if [ $BSD -eq 0 ] +then + lprv=$svlprv +else + lprv=$bsdlprv +fi + +# disallow concurrent input and -out arguments +if [ "$out" -a "$infile" ]; then + echo "xdpr: -out <filename> cannot be used if an input file is also specified." + exit 0 +fi + +# dump only +if [ "$out" ]; then + if [ "$xprv" -o "$lprv" ]; then + echo "xdpr: The following arguments will be ignored:" + echo $xprv $lprv + fi + xwd $xwdv + exit 0 +fi + +# print only +if [ "$infile" ]; then + if [ "$xwdv" ]; then + echo "xdpr: The following arguments will be ignored:" + echo $xwdv + fi + xpr -header "$header" -trailer "$trailer" $xprv | $LP $lprv + exit 0 +fi + +# dump & print (default) +xwd $xwdv | xpr -header "$header" -trailer "$trailer" $xprv | $LP $lprv +exit 0 + +# EOF @@ -0,0 +1,1915 @@ +/* $XConsortium: xpr.c,v 1.59 94/10/14 21:22:08 kaleb Exp $ */ +/* + +Copyright (c) 1985 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. + +*/ + +/* + * XPR - process xwd(1) files for various printers + * + * Author: Michael R. Gretzinger, MIT Project Athena + * + * Modified by Marvin Solomon, Univeristy of Wisconsin, to handle Apple + * Laserwriter (PostScript) devices (-device ps). + * Also accepts the -compact flag that produces more compact output + * by using run-length encoding on white (1) pixels. + * This version does not (yet) support the following options + * -append -dump -noff -nosixopt -split + * + * Changes + * Copyright 1986 by Marvin Solomon and the University of Wisconsin + * + * 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 the names of Marvin Solomon and + * the University of Wisconsin not be used in + * advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. + * Neither Marvin Solomon nor the University of Wisconsin + * makes any representations about the suitability of + * this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + * Modified by Bob Scheifler for 2x2 grayscale, then ... + * Modified by Angela Bock and E. Mike Durbin, Rich Inc., to produce output + * using 2x2, 3x3, or 4x4 grayscales. This version modifies the grayscale + * conversion option of -gray to accept an input of 2, 3, or 4 to signify + * the gray level desired. The output is produced, using 5, 10, or 17-level + * gray scales, respectively. + * + * Modifications by Larry Rupp, Hewlett-Packard Company, to support HP + * LaserJet, PaintJet, and other PCL printers. Added "ljet" and "pjet" + * to devices recognized. Also added -density, -cutoff, and -noposition + * command line options. + * + */ + +#include <X11/Xos.h> +#include <X11/Xfuncs.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <stdio.h> +#ifndef WIN32 +#include <pwd.h> +#endif +#include "lncmd.h" +#include "xpr.h" +#include <X11/XWDFile.h> +#include <X11/Xmu/SysUtil.h> +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +#ifdef NLS16 +#ifndef NLS +#define NLS +#endif +#endif + +#ifndef NLS +#define catgets(i, sn,mn,s) (s) +#else /* NLS */ +#define NL_SETN 1 /* set number */ +#include <nl_types.h> + +nl_catd nlmsg_fd; +#endif /* NLS */ + +int debug = 0; + +#define W_MAX 2400 +#define H_MAX 3150 +#define W_MARGIN 75 +#define H_MARGIN 37 +#define W_PAGE 2550 +#define H_PAGE 3225 + +#ifdef NOINLINE +#define min(x,y) (((x)<(y))?(x):(y)) +#endif /* NOINLINE */ + +#define F_PORTRAIT 1 +#define F_LANDSCAPE 2 +#define F_DUMP 4 +#define F_NOSIXOPT 8 +#define F_APPEND 16 +#define F_NOFF 32 +#define F_REPORT 64 +#define F_COMPACT 128 +#define F_INVERT 256 +#define F_GRAY 512 +#define F_NPOSITION 1024 +#define F_SLIDE 2048 + +#define DEFAULT_CUTOFF ((unsigned int) (0xFFFF * 0.50)) + +char *infilename = NULL; +char *progname; + +char *convert_data(); + +typedef struct _grayRec { + int level; + int sizeX, sizeY; /* 2x2, 3x3, 4x4 */ + unsigned long *grayscales; /* pointer to the encoded pixels */ +} GrayRec, *GrayPtr; + +unsigned long grayscale2x2[] = + {0, 1, 9, 11, 15}; +unsigned long grayscale3x3[] = + {0, 16, 68, 81, 325, 341, 349, 381, 383, 511}; +unsigned long grayscale4x4[] = + {0, 64, 4160, 4161, 20545, 21057, 23105, + 23113, 23145, 24169, 24171, 56939, 55275, 55279, + 57327, 65519, 65535}; + +GrayRec gray2x2 = {sizeof(grayscale2x2)/sizeof(long), 2, 2, grayscale2x2}; +GrayRec gray3x3 = {sizeof(grayscale3x3)/sizeof(long), 3, 3, grayscale3x3}; +GrayRec gray4x4 = {sizeof(grayscale4x4)/sizeof(long), 4, 4, grayscale4x4}; + +main(argc, argv) +char **argv; +{ + unsigned long swaptest = 1; + XWDFileHeader win; + register unsigned char (*sixmap)[]; + register int i; + register int iw; + register int ih; + register int sixel_count; + char *w_name; + int scale, width, height, flags, split; + int left, top; + int top_margin, left_margin; + int hpad; + char *header, *trailer; + int plane; + int density, render; + unsigned int cutoff; + float gamma; + GrayPtr gray; + char *data; + long size; + enum orientation orientation; + enum device device; + XColor *colors = (XColor *)NULL; + + if (!(progname = argv[0])) + progname = "xpr"; +#ifdef NLS + nlmsg_fd = catopen("xpr", 0); +#endif + parse_args (argc, argv, &scale, &width, &height, &left, &top, &device, + &flags, &split, &header, &trailer, &plane, &gray, + &density, &cutoff, &gamma, &render); + + if (device == PP) { + x2pmp(stdin, stdout, scale, + width >= 0? inch2pel((float)width/300.0): X_MAX_PELS, + height >= 0? inch2pel((float)height/300.0): Y_MAX_PELS, + left >= 0? inch2pel((float)left/300.0): inch2pel(0.60), + top >= 0? inch2pel((float)top/300.0): inch2pel(0.70), + header, trailer, + (flags & F_PORTRAIT)? PORTRAIT: + ((flags & F_LANDSCAPE)? LANDSCAPE: UNSPECIFIED), + (flags & F_INVERT)); + exit(0); + } else if ((device == LJET) || (device == PJET) || (device == PJETXL)) { + x2jet(stdin, stdout, scale, density, width, height, left, top, + header, trailer, + (flags & F_PORTRAIT)? PORTRAIT: + ((flags & F_LANDSCAPE)? LANDSCAPE: UNSPECIFIED), + (flags & F_INVERT), + ((flags & F_APPEND) && !(flags & F_NOFF)), + !(flags & F_NPOSITION), + (flags & F_SLIDE), + device, cutoff, gamma, render); + exit(0); + } + + /* read in window header */ + fullread(0, (char *)&win, sizeof win); + if (*(char *) &swaptest) + _swaplong((char *) &win, (long)sizeof(win)); + + if (win.file_version != XWD_FILE_VERSION) { + fprintf(stderr,"xpr: file format version missmatch.\n"); + exit(1); + } + if (win.header_size < sizeof(win)) { + fprintf(stderr,"xpr: header size is too small.\n"); + exit(1); + } + + w_name = malloc((unsigned)(win.header_size - sizeof win)); + fullread(0, w_name, (int) (win.header_size - sizeof win)); + + if(win.ncolors) { + XWDColor xwdcolor; + colors = (XColor *)malloc((unsigned) (win.ncolors * sizeof(XColor))); + for (i = 0; i < win.ncolors; i++) { + fullread(0, (char*)&xwdcolor, (int) sizeof xwdcolor); + colors[i].pixel = xwdcolor.pixel; + colors[i].red = xwdcolor.red; + colors[i].green = xwdcolor.green; + colors[i].blue = xwdcolor.blue; + colors[i].flags = xwdcolor.flags; + } + if (*(char *) &swaptest) { + for (i = 0; i < win.ncolors; i++) { + _swaplong((char *) &colors[i].pixel, (long)sizeof(long)); + _swapshort((char *) &colors[i].red, (long) (3 * sizeof(short))); + } + } + if ((win.ncolors == 2) && + (INTENSITY(&colors[0]) > INTENSITY(&colors[1]))) + flags ^= F_INVERT; + } + if (plane >= (long)win.pixmap_depth) { + fprintf(stderr,"xpr: plane number exceeds image depth\n"); + exit(1); + } + size = win.bytes_per_line * win.pixmap_height; + if (win.pixmap_format == XYPixmap) + size *= win.pixmap_depth; + data = malloc((unsigned)size); + fullread(0, data, (int)size); + if ((win.pixmap_depth > 1) || (win.byte_order != win.bitmap_bit_order)) { + data = convert_data(&win, data, plane, gray, colors, flags); + size = win.bytes_per_line * win.pixmap_height; + } + if (win.bitmap_bit_order == MSBFirst) { + _swapbits((unsigned char *)data, size); + win.bitmap_bit_order = LSBFirst; + } + if (flags & F_INVERT) + _invbits((unsigned char *)data, size); + + /* calculate orientation and scale */ + setup_layout(device, (int) win.pixmap_width, (int) win.pixmap_height, + flags, width, height, header, trailer, &scale, &orientation); + + if (device == PS) { + iw = win.pixmap_width; + ih = win.pixmap_height; + } else { + /* calculate w and h cell count */ + iw = win.pixmap_width; + ih = (win.pixmap_height + 5) / 6; + hpad = (ih * 6) - win.pixmap_height; + + /* build pixcells from input file */ + sixel_count = iw * ih; + sixmap = (unsigned char (*)[])malloc((unsigned)sixel_count); + build_sixmap(iw, ih, sixmap, hpad, &win, data); + } + + /* output commands and sixel graphics */ + if (device == LN03) { +/* ln03_grind_fonts(sixmap, iw, ih, scale, &pixmap); */ + ln03_setup(iw, ih, orientation, scale, left, top, + &left_margin, &top_margin, flags, header, trailer); + ln03_output_sixels(sixmap, iw, ih, (flags & F_NOSIXOPT), split, + scale, top_margin, left_margin); + ln03_finish(); + } else if (device == LA100) { + la100_setup(iw, ih, scale); + la100_output_sixels(sixmap, iw, ih, (flags & F_NOSIXOPT)); + la100_finish(); + } else if (device == PS) { + ps_setup(iw, ih, orientation, scale, left, top, + flags, header, trailer, w_name); + ps_output_bits(iw, ih, flags, orientation, &win, data); + ps_finish(); + } else { + fprintf(stderr, "xpr: device not supported\n"); + } + + /* print some statistics */ + if (flags & F_REPORT) { + fprintf(stderr, "Name: %s\n", w_name); + fprintf(stderr, "Width: %d, Height: %d\n", win.pixmap_width, + win.pixmap_height); + fprintf(stderr, "Orientation: %s, Scale: %d\n", + (orientation==PORTRAIT) ? "Portrait" : "Landscape", scale); + } + if (((device == LN03) || (device == LA100)) && (flags & F_DUMP)) + dump_sixmap(sixmap, iw, ih); + exit(0); +} + +usage() +{ + fprintf(stderr, "usage: %s [options] [file]\n", progname); + fprintf(stderr, " -append <file> -noff -output <file>\n"); + fprintf(stderr, " -compact\n"); + fprintf(stderr, " -device {ln03 | la100 | ps | lw | pp | ljet | pjet | pjetxl}\n"); + fprintf(stderr, " -dump\n"); + fprintf(stderr, " -gamma <correction>\n"); + fprintf(stderr, " -gray {2 | 3 | 4}\n"); + fprintf(stderr, " -height <inches> -width <inches>\n"); + fprintf(stderr, " -header <string> -trailer <string>\n"); + fprintf(stderr, " -landscape -portrait\n"); + fprintf(stderr, " -left <inches> -top <inches>\n"); + fprintf(stderr, " -noposition\n"); + fprintf(stderr, " -nosixopt\n"); + fprintf(stderr, " -plane <n>\n"); + fprintf(stderr, " -psfig\n"); + fprintf(stderr, " -render <type>\n"); + fprintf(stderr, " -report\n"); + fprintf(stderr, " -rv\n"); + fprintf(stderr, " -scale <scale>\n"); + fprintf(stderr, " -slide\n"); + fprintf(stderr, " -split <n-pages>\n"); + exit(1); +} + +parse_args(argc, argv, scale, width, height, left, top, device, flags, + split, header, trailer, plane, gray, density, cutoff, gamma, render) +register int argc; +register char **argv; +int *scale; +int *width; +int *height; +int *left; +int *top; +enum device *device; +int *flags; +int *split; +char **header; +char **trailer; +int *plane; +GrayPtr *gray; +int *density; +unsigned int *cutoff; +float *gamma; +int *render; +{ + register char *output_filename; + register int f; + register int len; + register int pos; +#ifdef X_NOT_STDC_ENV + double atof(); + int atoi(); +#endif + + output_filename = NULL; + *device = PS; /* default */ + *flags = 0; + *scale = 0; + *split = 1; + *width = -1; + *height = -1; + *top = -1; + *left = -1; + *header = NULL; + *trailer = NULL; + *plane = -1; + *gray = (GrayPtr)NULL; + *density = 0; + *cutoff = DEFAULT_CUTOFF; + *gamma = -1.0; + *render = 0; + + for (argc--, argv++; argc > 0; argc--, argv++) { + if (argv[0][0] != '-') { + infilename = *argv; + continue; + } + len = strlen(*argv); + switch (argv[0][1]) { + case 'a': /* -append <filename> */ + if (!bcmp(*argv, "-append", len)) { + argc--; argv++; + if (argc == 0) usage(); + output_filename = *argv; + *flags |= F_APPEND; + } else + usage(); + break; + + case 'c': /* -compact | -cutoff <intensity> */ + if (len <= 2 ) + usage(); + if (!bcmp(*argv, "-compact", len)) { + *flags |= F_COMPACT; + } else if (!bcmp(*argv, "-cutoff", len)) { + argc--; argv++; + if (argc == 0) usage(); + *cutoff = min((atof(*argv) / 100.0 * 0xFFFF), 0xFFFF); + } else + usage(); + break; + + case 'd': /* -density <num> | -device <dev> | -dump */ + if (len <= 2) + usage(); + if (!bcmp(*argv, "-dump", len)) { + *flags |= F_DUMP; + } else if (len <= 3) { + usage(); + } else if (!bcmp(*argv, "-density", len)) { + argc--; argv++; + if (argc == 0) usage(); + *density = atoi(*argv); + } else if (!bcmp(*argv, "-device", len)) { + argc--; argv++; + if (argc == 0) usage(); + len = strlen(*argv); + if (len < 2) + usage(); + if (!bcmp(*argv, "ln03", len)) { + *device = LN03; + } else if (!bcmp(*argv, "la100", len)) { + *device = LA100; + } else if (!bcmp(*argv, "ps", len)) { + *device = PS; + } else if (!bcmp(*argv, "lw", len)) { + *device = PS; + } else if (!bcmp(*argv, "pp", len)) { + *device = PP; + } else if (!bcmp(*argv, "ljet", len)) { + *device = LJET; + } else if (!bcmp(*argv, "pjet", len)) { + *device = PJET; + } else if (!bcmp(*argv, "pjetxl", len)) { + *device = PJETXL; + } else + usage(); + } else + usage(); + break; + + case 'g': /* -gamma <float> | -gray <num> */ + if (len <= 2) + usage(); + if (!bcmp(*argv, "-gamma", len)) { + argc--; argv++; + if (argc == 0) usage(); + *gamma = atof(*argv); + } else if (!bcmp(*argv, "-gray", len) || + !bcmp(*argv, "-grey", len)) { + argc--; argv++; + if (argc == 0) usage(); + switch (atoi(*argv)) { + case 2: + *gray = &gray2x2; + break; + case 3: + *gray = &gray3x3; + break; + case 4: + *gray = &gray4x4; + break; + default: + usage(); + } + *flags |= F_GRAY; + } else + usage(); + break; + + case 'h': /* -height <inches> | -header <string> */ + if (len <= 3) + usage(); + if (!bcmp(*argv, "-height", len)) { + argc--; argv++; + if (argc == 0) usage(); + *height = (int)(300.0 * atof(*argv)); + } else if (!bcmp(*argv, "-header", len)) { + argc--; argv++; + if (argc == 0) usage(); + *header = *argv; + } else + usage(); + break; + + case 'l': /* -landscape | -left <inches> */ + if (len <= 2) + usage(); + if (!bcmp(*argv, "-landscape", len)) { + *flags |= F_LANDSCAPE; + } else if (!bcmp(*argv, "-left", len)) { + argc--; argv++; + if (argc == 0) usage(); + *left = (int)(300.0 * atof(*argv)); + } else + usage(); + break; + + case 'n': /* -nosixopt | -noff | -noposition */ + if (len <= 3) + usage(); + if (!bcmp(*argv, "-nosixopt", len)) { + *flags |= F_NOSIXOPT; + } else if (!bcmp(*argv, "-noff", len)) { + *flags |= F_NOFF; + } else if (!bcmp(*argv, "-noposition", len)) { + *flags |= F_NPOSITION; + } else + usage(); + break; + + case 'o': /* -output <filename> */ + if (!bcmp(*argv, "-output", len)) { + argc--; argv++; + if (argc == 0) usage(); + output_filename = *argv; + } else + usage(); + break; + + case 'p': /* -portrait | -plane <n> */ + if (len <= 2) + usage(); + if (!bcmp(*argv, "-portrait", len)) { + *flags |= F_PORTRAIT; + } else if (!bcmp(*argv, "-plane", len)) { + argc--; argv++; + if (argc == 0) usage(); + *plane = atoi(*argv); + } else if (!bcmp(*argv, "-psfig", len)) { + *flags |= F_NPOSITION; + } else + usage(); + break; + + case 'r': /* -render <type> | -report | -rv */ + if (len <= 2) + usage(); + if (!bcmp(*argv, "-rv", len)) { + *flags |= F_INVERT; + } else if (len <= 3) { + usage(); + } else if (!bcmp(*argv, "-render", len)) { + argc--; argv++; + if (argc == 0) usage(); + *render = atoi(*argv); + } else if (!bcmp(*argv, "-report", len)) { + *flags |= F_REPORT; + } else + usage(); + break; + + case 's': /* -scale <scale> | -slide | -split <n-pages> */ + if (len <= 2) + usage(); + if (!bcmp(*argv, "-scale", len)) { + argc--; argv++; + if (argc == 0) usage(); + *scale = atoi(*argv); + } else if (!bcmp(*argv, "-slide", len)) { + *flags |= F_SLIDE; + } else if (!bcmp(*argv, "-split", len)) { + argc--; argv++; + if (argc == 0) usage(); + *split = atoi(*argv); + } else + usage(); + break; + + case 't': /* -top <inches> | -trailer <string> */ + if (len <= 2) + usage(); + if (!bcmp(*argv, "-top", len)) { + argc--; argv++; + if (argc == 0) usage(); + *top = (int)(300.0 * atof(*argv)); + } else if (!bcmp(*argv, "-trailer", len)) { + argc--; argv++; + if (argc == 0) usage(); + *trailer = *argv; + } else + usage(); + break; + + case 'w': /* -width <inches> */ + if (!bcmp(*argv, "-width", len)) { + argc--; argv++; + if (argc == 0) usage(); + *width = (int)(300.0 * atof(*argv)); + } else + usage(); + break; + + default: + usage(); + break; + } + } + + if (infilename) { + f = open(infilename, O_RDONLY|O_BINARY, 0); + if (f < 0) { + fprintf(stderr, "xpr: error opening \"%s\" for input\n", + infilename); + perror(""); + exit(1); + } + dup2(f, 0); + close(f); + } else + infilename = "stdin"; + + if (output_filename != NULL) { + if (!(*flags & F_APPEND)) { + f = open(output_filename, O_CREAT|O_WRONLY|O_TRUNC, 0664); + } else { + f = open(output_filename, O_WRONLY, 0); + } + if (f < 0) { + fprintf(stderr, "xpr: error opening \"%s\" for output\n", + output_filename); + perror("xpr"); + exit(1); + } + if (*flags & F_APPEND) { + pos = lseek(f, 0, 2); /* get eof position */ + if ((*flags & F_NOFF) && + !(*device == LJET || *device == PJET || *device == PJETXL)) + pos -= 3; /* set position before trailing */ + /* formfeed and reset */ + lseek(f, pos, 0); /* set pointer */ + } + dup2(f, 1); + close(f); + } +} + +setup_layout(device, win_width, win_height, flags, width, height, + header, trailer, scale, orientation) +enum device device; +int win_width; +int win_height; +int flags; +int width; +int height; +char *header; +char *trailer; +int *scale; +enum orientation *orientation; +{ + register int w_scale; + register int h_scale; + register int iscale = *scale; + register int w_max; + register int h_max; + + if (header != NULL) win_height += 75; + if (trailer != NULL) win_height += 75; + + /* check maximum width and height; set orientation and scale*/ + if (device == LN03 || device == PS) { + if ((win_width < win_height || (flags & F_PORTRAIT)) && + !(flags & F_LANDSCAPE)) { + *orientation = PORTRAIT; + w_max = (width > 0)? width : W_MAX; + h_max = (height > 0)? height : H_MAX; + w_scale = w_max / win_width; + h_scale = h_max / win_height; + *scale = min(w_scale, h_scale); + } else { + *orientation = LANDSCAPE; + w_max = (width > 0)? width : H_MAX; + h_max = (height > 0)? height : W_MAX; + w_scale = w_max / win_width; + h_scale = h_max / win_height; + *scale = min(w_scale, h_scale); + } + } else { /* device == LA100 */ + *orientation = PORTRAIT; + *scale = W_MAX / win_width; + } + if (*scale == 0) *scale = 1; + if (*scale > 6) *scale = 6; + if (iscale > 0 && iscale < *scale) *scale = iscale; +} + +char * +convert_data(win, data, plane, gray, colors, flags) + register XWDFileHeader *win; + char *data; + int plane; + register GrayPtr gray; + XColor *colors; + int flags; +{ + XImage in_image_struct, out_image_struct; + register XImage *in_image, *out_image; + register int x, y; + + if ((win->pixmap_format == XYPixmap) && (plane >= 0)) { + data += win->bytes_per_line * win->pixmap_height * + (win->pixmap_depth - (plane + 1)); + win->pixmap_format = XYBitmap; + win->pixmap_depth = 1; + return data; + } + + /* initialize the input image */ + + in_image = &in_image_struct; + in_image->byte_order = win->byte_order; + in_image->bitmap_unit = win->bitmap_unit; + in_image->bitmap_bit_order = win->bitmap_bit_order; + in_image->depth = win->pixmap_depth; + in_image->bits_per_pixel = win->bits_per_pixel; + in_image->format = win->pixmap_format, + in_image->xoffset = win->xoffset, + in_image->data = data; + in_image->width = win->pixmap_width; + in_image->height = win->pixmap_height; + in_image->bitmap_pad = win->bitmap_pad; + in_image->bytes_per_line = win->bytes_per_line; + in_image->red_mask = win->red_mask; + in_image->green_mask = win->green_mask; + in_image->blue_mask = win->blue_mask; + in_image->obdata = NULL; + if (!XInitImage(in_image)) { + fprintf(stderr,"xpr: bad input image header data.\n"); + exit(1); + } + if ((flags & F_GRAY) && (in_image->depth > 1) && (plane < 0)) { + win->pixmap_width *= gray->sizeX; + win->pixmap_height *= gray->sizeY; + } + win->xoffset = 0; + win->pixmap_format = XYBitmap; + win->byte_order = LSBFirst; + win->bitmap_unit = 8; + win->bitmap_bit_order = LSBFirst; + win->bitmap_pad = 8; + win->pixmap_depth = 1; + win->bits_per_pixel = 1; + win->bytes_per_line = (win->pixmap_width + 7) >> 3; + + out_image = &out_image_struct; + out_image->byte_order = win->byte_order; + out_image->bitmap_unit = win->bitmap_unit; + out_image->bitmap_bit_order = win->bitmap_bit_order; + out_image->depth = win->pixmap_depth; + out_image->bits_per_pixel = win->bits_per_pixel; + out_image->format = win->pixmap_format; + out_image->xoffset = win->xoffset, + out_image->width = win->pixmap_width; + out_image->height = win->pixmap_height; + out_image->bitmap_pad = win->bitmap_pad; + out_image->bytes_per_line = win->bytes_per_line; + out_image->red_mask = 0; + out_image->green_mask = 0; + out_image->blue_mask = 0; + out_image->obdata = NULL; + out_image->data = malloc((unsigned)out_image->bytes_per_line * + out_image->height); + if (!XInitImage(out_image)) { + fprintf(stderr,"xpr: bad output image header data.\n"); + exit(1); + } + + if ((in_image->depth > 1) && (plane > 0)) { + for (y = 0; y < in_image->height; y++) + for (x = 0; x < in_image->width; x++) + XPutPixel(out_image, x, y, + (XGetPixel(in_image, x, y) >> plane) & 1); + } else if (plane == 0) { + for (y = 0; y < in_image->height; y++) + for (x = 0; x < in_image->width; x++) + XPutPixel(out_image, x, y, XGetPixel(in_image, x, y)); + } else if ((in_image->depth > 1) && + ((win->visual_class == TrueColor) || + (win->visual_class == DirectColor))) { + XColor color; + int direct = 0; + unsigned long rmask, gmask, bmask; + int rshift = 0, gshift = 0, bshift = 0; + + rmask = win->red_mask; + while (!(rmask & 1)) { + rmask >>= 1; + rshift++; + } + gmask = win->green_mask; + while (!(gmask & 1)) { + gmask >>= 1; + gshift++; + } + bmask = win->blue_mask; + while (!(bmask & 1)) { + bmask >>= 1; + bshift++; + } + if ((win->ncolors == 0) || (win->visual_class == DirectColor)) + direct = 1; + if (flags & F_GRAY) { + register int ox, oy; + int ix, iy; + unsigned long bits; + for (y = 0, oy = 0; y < in_image->height; y++, oy += gray->sizeY) + for (x = 0, ox = 0; x < in_image->width; x++, ox += gray->sizeX) + { + color.pixel = XGetPixel(in_image, x, y); + color.red = (color.pixel >> rshift) & rmask; + color.green = (color.pixel >> gshift) & gmask; + color.blue = (color.pixel >> bshift) & bmask; + if (!direct) { + color.red = colors[color.red].red; + color.green = colors[color.green].green; + color.blue = colors[color.blue].blue; + } + bits = gray->grayscales[(int)(gray->level * + INTENSITY(&color)) / + (INTENSITYPER(100) + 1)]; + for (iy = 0; iy < gray->sizeY; iy++) + for (ix = 0; ix < gray->sizeX; ix++, bits >>= 1) + XPutPixel(out_image, ox + ix, oy + iy, bits); + } + } else { + for (y = 0; y < in_image->height; y++) + for (x = 0; x < in_image->width; x++) { + color.pixel = XGetPixel(in_image, x, y); + color.red = (color.pixel >> rshift) & rmask; + color.green = (color.pixel >> gshift) & gmask; + color.blue = (color.pixel >> bshift) & bmask; + if (!direct) { + color.red = colors[color.red].red; + color.green = colors[color.green].green; + color.blue = colors[color.blue].blue; + } + XPutPixel(out_image, x, y, + INTENSITY(&color) > HALFINTENSITY); + } + } + } else if (flags & F_GRAY) { + register int ox, oy; + int ix, iy; + unsigned long bits; + + if (win->ncolors == 0) { + fprintf(stderr, "no colors in data, can't remap\n"); + exit(1); + } + for (x = 0; x < win->ncolors; x++) { + register XColor *color = &colors[x]; + + color->pixel = gray->grayscales[(gray->level * INTENSITY(color)) / + (INTENSITYPER(100) + 1)]; + } + for (y = 0, oy = 0; y < in_image->height; y++, oy += gray->sizeY) + for (x = 0, ox = 0; x < in_image->width; x++, ox += gray->sizeX) { + bits = colors[XGetPixel(in_image, x, y)].pixel; + for (iy = 0; iy < gray->sizeY; iy++) + for (ix = 0; ix < gray->sizeX; ix++, bits >>= 1) + XPutPixel(out_image, ox + ix, oy + iy, bits); + } + } else { + if (win->ncolors == 0) { + fprintf(stderr, "no colors in data, can't remap\n"); + exit(1); + } + for (x = 0; x < win->ncolors; x++) { + register XColor *color = &colors[x]; + color->pixel = (INTENSITY(color) > HALFINTENSITY); + } + for (y = 0; y < in_image->height; y++) + for (x = 0; x < in_image->width; x++) + XPutPixel(out_image, x, y, + colors[XGetPixel(in_image, x, y)].pixel); + } + free(data); + return (out_image->data); +} + +dump_sixmap(sixmap, iw, ih) +register unsigned char (*sixmap)[]; +int iw; +int ih; +{ + register int i, j; + register unsigned char *c; + + c = (unsigned char *)sixmap; + fprintf(stderr, "Sixmap:\n"); + for (i = 0; i < ih; i++) { + for (j = 0; j < iw; j++) { + fprintf(stderr, "%02X ", *c++); + } + fprintf(stderr, "\n\n"); + } +} + +build_sixmap(iw, ih, sixmap, hpad, win, data) +int ih; +int iw; +unsigned char (*sixmap)[]; +int hpad; +XWDFileHeader *win; +char *data; +{ + int iwb = win->bytes_per_line; + unsigned char *line[6]; + register unsigned char *c; + register int i, j; +#ifdef NOINLINE + register int w; +#endif + register int sixel; + unsigned char *buffer = (unsigned char *)data; + + c = (unsigned char *)sixmap; + + + while (--ih >= 0) { + for (i = 0; i <= 5; i++) { + line[i] = buffer; + buffer += iwb; + } + if ((ih == 0) && (hpad > 0)) { + unsigned char *ffbuf; + + ffbuf = (unsigned char *)malloc((unsigned)iwb); + for (j = 0; j < iwb; j++) + ffbuf[j] = 0xFF; + for (; --hpad >= 0; i--) + line[i] = ffbuf; + } + +#ifndef NOINLINE + for (i = 0; i < iw; i++) { + sixel = extzv(line[0], i, 1); + sixel |= extzv(line[1], i, 1) << 1; + sixel |= extzv(line[2], i, 1) << 2; + sixel |= extzv(line[3], i, 1) << 3; + sixel |= extzv(line[4], i, 1) << 4; + sixel |= extzv(line[5], i, 1) << 5; + *c++ = sixel; + } +#else + for (i = 0, w = iw; w > 0; i++) { + for (j = 0; j <= 7; j++) { + sixel = ((line[0][i] >> j) & 1); + sixel |= ((line[1][i] >> j) & 1) << 1; + sixel |= ((line[2][i] >> j) & 1) << 2; + sixel |= ((line[3][i] >> j) & 1) << 3; + sixel |= ((line[4][i] >> j) & 1) << 4; + sixel |= ((line[5][i] >> j) & 1) << 5; + *c++ = sixel; + if (--w == 0) break; + } + } +#endif + } +} + +build_output_filename(name, device, oname) +register char *name, *oname; +enum device device; +{ + while (*name && *name != '.') *oname++ = *name++; + switch (device) { + case LN03: bcopy(".ln03", oname, 6); break; + case LA100: bcopy(".la100", oname, 7); break; + } +} + +/* +ln03_grind_fonts(sixmap, iw, ih, scale, pixmap) +unsigned char (*sixmap)[]; +int iw; +int ih; +int scale; +struct pixmap (**pixmap)[]; +{ +} +*/ + +ln03_setup(iw, ih, orientation, scale, left, top, left_margin, top_margin, + flags, header, trailer) +int iw; +int ih; +enum orientation orientation; +int scale; +int left; +int top; +int *left_margin; +int *top_margin; +int flags; +char *header; +char *trailer; +{ + register int i; + register int lm, tm, xm; + char buf[256]; + register char *bp = buf; + + if (!(flags & F_APPEND)) { + sprintf(bp, LN_STR); bp += 4; + sprintf(bp, LN_SSU, 7); bp += 5; + sprintf(bp, LN_PUM_SET); bp += sizeof LN_PUM_SET - 1; + } + + if (orientation == PORTRAIT) { + lm = (left > 0)? left : (((W_MAX - scale * iw) / 2) + W_MARGIN); + tm = (top > 0)? top : (((H_MAX - scale * ih * 6) / 2) + H_MARGIN); + sprintf(bp, LN_PFS, "?20"); bp += 7; + sprintf(bp, LN_DECOPM_SET); bp += sizeof LN_DECOPM_SET - 1; + sprintf(bp, LN_DECSLRM, lm, W_PAGE - lm); bp += strlen(bp); + } else { + lm = (left > 0)? left : (((H_MAX - scale * iw) / 2) + H_MARGIN); + tm = (top > 0)? top : (((W_MAX - scale * ih * 6) / 2) + W_MARGIN); + sprintf(bp, LN_PFS, "?21"); bp += 7; + sprintf(bp, LN_DECOPM_SET); bp += sizeof LN_DECOPM_SET - 1; + sprintf(bp, LN_DECSLRM, lm, H_PAGE - lm); bp += strlen(bp); + } + + if (header != NULL) { + sprintf(bp, LN_VPA, tm - 100); bp += strlen(bp); + i = strlen(header); + xm = (((scale * iw) - (i * 30)) / 2) + lm; + sprintf(bp, LN_HPA, xm); bp += strlen(bp); + sprintf(bp, LN_SGR, 3); bp += strlen(bp); + bcopy(header, bp, i); + bp += i; + } + if (trailer != NULL) { + sprintf(bp, LN_VPA, tm + (scale * ih * 6) + 75); bp += strlen(bp); + i = strlen(trailer); + xm = (((scale * iw) - (i * 30)) / 2) + lm; + sprintf(bp, LN_HPA, xm); bp += strlen(bp); + sprintf(bp, LN_SGR, 3); bp += strlen(bp); + bcopy(trailer, bp, i); + bp += i; + } + + sprintf(bp, LN_HPA, lm); bp += strlen(bp); + sprintf(bp, LN_VPA, tm); bp += strlen(bp); + sprintf(bp, LN_SIXEL_GRAPHICS, 9, 0, scale); bp += strlen(bp); + sprintf(bp, "\"1;1"); bp += 4; /* Pixel aspect ratio */ + write(1, buf, bp-buf); + *top_margin = tm; + *left_margin = lm; +} + + +ln03_finish() +{ + char buf[256]; + register char *bp = buf; + + sprintf(bp, LN_DECOPM_RESET); bp += sizeof LN_DECOPM_SET - 1; + sprintf(bp, LN_LNM); bp += 5; + sprintf(bp, LN_PUM); bp += 5; + sprintf(bp, LN_PFS, "?20"); bp += 7; + sprintf(bp, LN_SGR, 0); bp += strlen(bp); + sprintf(bp, LN_HPA, 1); bp += strlen(bp); + sprintf(bp, LN_VPA, 1); bp += strlen(bp); + + + write(1, buf, bp-buf); + +} + +/*ARGSUSED*/ +la100_setup(iw, ih, scale) +{ + char buf[256]; + register char *bp; + int lm, tm; + + bp = buf; + lm = ((80 - (int)((double)iw / 6.6)) / 2) - 1; + if (lm < 1) lm = 1; + tm = ((66 - (int)((double)ih / 2)) / 2) - 1; + if (tm < 1) tm = 1; + sprintf(bp, "\033[%d;%ds", lm, 81-lm); bp += strlen(bp); + sprintf(bp, "\033[?7l"); bp += 5; + sprintf(bp, "\033[%dd", tm); bp += strlen(bp); + sprintf(bp, "\033[%d`", lm); bp += strlen(bp); + sprintf(bp, "\033P0q"); bp += 4; + write(1, buf, bp-buf); +} + +#define LA100_RESET "\033[1;80s\033[?7h" + +la100_finish() +{ + write(1, LA100_RESET, sizeof LA100_RESET - 1); +} + +#define COMMENTVERSION "PS-Adobe-1.0" + +#ifdef XPROLOG +/* for debugging, get the prolog from a file */ +dump_prolog(flags) { + char *fname=(flags & F_COMPACT) ? "prolog.compact" : "prolog"; + FILE *fi = fopen(fname,"r"); + char buf[1024]; + + if (fi==NULL) { + perror(fname); + exit(1); + } + while (fgets(buf,1024,fi)) fputs(buf,stdout); + fclose(fi); +} + +#else /* XPROLOG */ +/* postscript "programs" to unpack and print the bitmaps being sent */ + +char *ps_prolog_compact[] = { + "%%Pages: 1", + "%%EndProlog", + "%%Page: 1 1", + "", + "/bitgen", + " {", + " /nextpos 0 def", + " currentfile bufspace readhexstring pop % get a chunk of input", + " % interpret each byte of the input", + " {", + " flag { % if the previous byte was FF", + " /len exch def % this byte is a count", + " result", + " nextpos", + " FFstring 0 len getinterval % grap a chunk of FF's", + " putinterval % and stuff them into the result", + " /nextpos nextpos len add def", + " /flag false def", + " }{ % otherwise", + " dup 255 eq { % if this byte is FF", + " /flag true def % just set the flag", + " pop % and toss the FF", + " }{ % otherwise", + " % move this byte to the result", + " result nextpos", + " 3 -1 roll % roll the current byte back to the top", + " put", + " /nextpos nextpos 1 add def", + " } ifelse", + " } ifelse", + " } forall", + " % trim unused space from end of result", + " result 0 nextpos getinterval", + " } def", + "", + "", + "/bitdump % stk: width, height, iscale", + " % dump a bit image with lower left corner at current origin,", + " % scaling by iscale (iscale=1 means 1/300 inch per pixel)", + " {", + " % read arguments", + " /iscale exch def", + " /height exch def", + " /width exch def", + "", + " % scale appropriately", + " width iscale mul height iscale mul scale", + "", + " % data structures:", + "", + " % allocate space for one line of input", + " /bufspace 36 string def", + "", + " % string of FF's", + " /FFstring 256 string def", + " % for all i FFstring[i]=255", + " 0 1 255 { FFstring exch 255 put } for", + "", + " % 'escape' flag", + " /flag false def", + "", + " % space for a chunk of generated bits", + " /result 4590 string def", + "", + " % read and dump the image", + " width height 1 [width 0 0 height neg 0 height]", + " { bitgen }", + " image", + " } def", + 0 +}; + +char *ps_prolog[] = { + "%%Pages: 1", + "%%EndProlog", + "%%Page: 1 1", + "", + "/bitdump % stk: width, height, iscale", + "% dump a bit image with lower left corner at current origin,", + "% scaling by iscale (iscale=1 means 1/300 inch per pixel)", + "{", + " % read arguments", + " /iscale exch def", + " /height exch def", + " /width exch def", + "", + " % scale appropriately", + " width iscale mul height iscale mul scale", + "", + " % allocate space for one scanline of input", + " /picstr % picstr holds one scan line", + " width 7 add 8 idiv % width of image in bytes = ceiling(width/8)", + " string", + " def", + "", + " % read and dump the image", + " width height 1 [width 0 0 height neg 0 height]", + " { currentfile picstr readhexstring pop }", + " image", + "} def", + 0 +}; + +dump_prolog(flags) { + char **p = (flags & F_COMPACT) ? ps_prolog_compact : ps_prolog; + while (*p) printf("%s\n",*p++); +} +#endif /* XPROLOG */ + +#define PAPER_WIDTH 85*30 /* 8.5 inches */ +#define PAPER_LENGTH 11*300 /* 11 inches */ + +static int +points(n) +{ + /* scale n from pixels (1/300 inch) to points (1/72 inch) */ + n *= 72; + return n/300; +} + +static char * +escape(s) +char *s; +{ + /* make a version of s in which control characters are deleted and + * special characters are escaped. + */ + static char buf[200]; + char *p = buf; + + for (;*s;s++) { + if (*s < ' ' || *s > 0176) continue; + if (*s==')' || *s=='(' || *s == '\\') { + sprintf(p,"\\%03o",*s); + p += 4; + } + else *p++ = *s; + } + *p = 0; + return buf; +} + +ps_setup(iw, ih, orientation, scale, left, top, + flags, header, trailer, name) +int iw; +int ih; +enum orientation orientation; +int scale; +int left; +int top; +int flags; +char *header; +char *trailer; +char *name; +{ + char hostname[256]; +#ifdef WIN32 + char *username; +#else + struct passwd *pswd; +#endif + long clock; + int lm, bm; /* left (bottom) margin */ + + /* calculate margins */ + if (orientation==PORTRAIT) { + lm = (left > 0)? left : ((PAPER_WIDTH - scale * iw) / 2); + bm = (top > 0)? (PAPER_LENGTH - top - scale * ih) + : ((PAPER_LENGTH - scale * ih) / 2); + } else { /* orientation == LANDSCAPE */ + lm = (top > 0)? (PAPER_WIDTH - top - scale * ih) + : ((PAPER_WIDTH - scale * ih) / 2); + bm = (left > 0)? (PAPER_LENGTH - left - scale * iw) + : ((PAPER_LENGTH - scale * iw) / 2); + } + printf ("%%!%s\n", COMMENTVERSION); + printf ("%%%%BoundingBox: %d %d %d %d\n", + (flags & F_NPOSITION) ? points(lm) : 0, + (flags & F_NPOSITION) ? points(bm) : 0, + points(iw * scale), points(ih * scale)); + (void) XmuGetHostname (hostname, sizeof hostname); +#ifdef WIN32 + username = getenv("USERNAME"); + printf ("%%%%Creator: %s:%s\n", hostname, + username ? username : "unknown"); +#else + pswd = getpwuid (getuid ()); + printf ("%%%%Creator: %s:%s (%s)\n", hostname, + pswd->pw_name, pswd->pw_gecos); +#endif + printf ("%%%%Title: %s (%s)\n", infilename,name); + printf ("%%%%CreationDate: %s", + (time (&clock), ctime (&clock))); + printf ("%%%%EndComments\n"); + + dump_prolog(flags); + + if (orientation==PORTRAIT) { + if (header || trailer) { + printf("gsave\n"); + printf("/Times-Roman findfont 15 scalefont setfont\n"); + /* origin at bottom left corner of image */ + printf("%d %d translate\n",points(lm),points(bm)); + if (header) { + char *label = escape(header); + printf("%d (%s) stringwidth pop sub 2 div %d moveto\n", + points(iw*scale), label, points(ih*scale) + 10); + printf("(%s) show\n",label); + } + if (trailer) { + char *label = escape(trailer); + printf("%d (%s) stringwidth pop sub 2 div -20 moveto\n", + points(iw*scale), label); + printf("(%s) show\n",label); + } + printf("grestore\n"); + } + /* set resolution to device units (300/inch) */ + printf("72 300 div dup scale\n"); + /* move to lower left corner of image */ + if (!(flags & F_NPOSITION)) + printf("%d %d translate\n",lm,bm); + /* dump the bitmap */ + printf("%d %d %d bitdump\n",iw,ih,scale); + } else { /* orientation == LANDSCAPE */ + if (header || trailer) { + printf("gsave\n"); + printf("/Times-Roman findfont 15 scalefont setfont\n"); + /* origin at top left corner of image */ + printf("%d %d translate\n",points(lm),points(bm + scale * iw)); + /* rotate to print the titles */ + printf("-90 rotate\n"); + if (header) { + char *label = escape(header); + printf("%d (%s) stringwidth pop sub 2 div %d moveto\n", + points(iw*scale), label, points(ih*scale) + 10); + printf("(%s) show\n",label); + } + if (trailer) { + char *label = escape(trailer); + printf("%d (%s) stringwidth pop sub 2 div -20 moveto\n", + points(iw*scale), label); + printf("(%s) show\n",label); + } + printf("grestore\n"); + } + /* set resolution to device units (300/inch) */ + printf("72 300 div dup scale\n"); + /* move to lower left corner of image */ + if (!(flags & F_NPOSITION)) + printf("%d %d translate\n",lm,bm); + /* dump the bitmap */ + printf("%d %d %d bitdump\n",ih,iw,scale); + } +} + +char *ps_epilog[] = { + "", + "showpage", + "%%Trailer", + 0 +}; + +ps_finish() +{ + char **p = ps_epilog; + + while (*p) printf("%s\n",*p++); +} + +ln03_alter_background(sixmap, iw, ih) +unsigned char (*sixmap)[]; +int iw; +int ih; +{ + register unsigned char *c, *stopc; + register unsigned char *startc; + register int n; + + c = (unsigned char *)sixmap; + stopc = c + (iw * ih); + n = 0; + while (c < stopc) { + switch (*c) { + case 0x08: case 0x11: case 0x04: case 0x22: + case 0x20: case 0x21: case 0x24: case 0x00: + if (n == 0) startc = c; + n++; + break; + + default: + if (n >= 2) { + while (n-- > 0) *startc++ = 0x00; + } else { + n = 0; + } + break; + } + c++; + } +} + +ln03_output_sixels(sixmap, iw, ih, nosixopt, split, scale, top_margin, + left_margin) +unsigned char (*sixmap)[]; +int iw; +int ih; +int nosixopt; +int split; +int top_margin; +int left_margin; +{ + unsigned char *buf; + register unsigned char *bp; + int i; + int j; + register int k; + register unsigned char *c; + register int lastc; + register int count; + char snum[6]; + register char *snp; + + bp = (unsigned char *)malloc((unsigned)(iw*ih+512)); + buf = bp; + count = 0; + lastc = -1; + c = (unsigned char *)sixmap; + split = ih / split; /* number of lines per page */ + + iw--; /* optimization */ + for (i = 0; i < ih; i++) { + for (j = 0; j <= iw; j++) { + if (!nosixopt) { + if (*c == lastc && j < iw) { + count++; + c++; + continue; + } + if (count >= 3) { + bp--; + count++; + *bp++ = '!'; + snp = snum; + while (count > 0) { + k = count / 10; + *snp++ = count - (k * 10) + '0'; + count = k; + } + while (--snp >= snum) *bp++ = *snp; + *bp++ = (~lastc & 0x3F) + 0x3F; + } else if (count > 0) { + lastc = (~lastc & 0x3F) + 0x3F; + do { + *bp++ = lastc; + } while (--count > 0); + } + } + lastc = *c++; + *bp++ = (~lastc & 0x3F) + 0x3F; + } + *bp++ = '-'; /* New line */ + lastc = -1; + if ((i % split) == 0 && i != 0) { + sprintf((char *)bp, LN_ST); bp += sizeof LN_ST - 1; + *bp++ = '\f'; + sprintf((char *)bp, LN_VPA, top_margin + (i * 6 * scale)); + bp += strlen((char *)bp); + sprintf((char *)bp, LN_HPA, left_margin); + bp += strlen((char *)bp); + sprintf((char *)bp, LN_SIXEL_GRAPHICS, 9, 0, scale); + bp += strlen((char *)bp); + sprintf((char *)bp, "\"1;1"); bp += 4; + } + } + + sprintf((char *)bp, LN_ST); bp += sizeof LN_ST - 1; + write(1, (char *)buf, bp-buf); +} + +/*ARGSUSED*/ +la100_output_sixels(sixmap, iw, ih, nosixopt) +unsigned char (*sixmap)[]; +int iw; +int ih; +int nosixopt; +{ + unsigned char *buf; + register unsigned char *bp; + int i; + register int j, k; + register unsigned char *c; + register int lastc; + register int count; + char snum[6]; + + bp = (unsigned char *)malloc((unsigned)(iw*ih+512)); + buf = bp; + count = 0; + lastc = -1; + c = (unsigned char *)sixmap; + + for (i = 0; i < ih; i++) { + for (j = 0; j < iw; j++) { + if (*c == lastc && (j+1) < iw) { + count++; + c++; + continue; + } + if (count >= 2) { + bp -= 2; + count = 2 * (count + 1); + *bp++ = '!'; + k = 0; + while (count > 0) { + snum[k++] = (count % 10) + '0'; + count /= 10; + } + while (--k >= 0) *bp++ = snum[k]; + *bp++ = (~lastc & 0x3F) + 0x3F; + count = 0; + } else if (count > 0) { + lastc = (~lastc & 0x3F) + 0x3F; + do { + *bp++ = lastc; + *bp++ = lastc; + } while (--count > 0); + } + lastc = (~*c & 0x3F) + 0x3F; + *bp++ = lastc; + *bp++ = lastc; + lastc = *c++; + } + *bp++ = '-'; /* New line */ + lastc = -1; + } + + sprintf((char *)bp, LN_ST); bp += sizeof LN_ST - 1; + *bp++ = '\f'; + write(1, (char *)buf, bp-buf); +} + +#define LINELEN 72 /* number of CHARS (bytes*2) per line of bitmap output */ + +ps_output_bits(iw, ih, flags, orientation, win, data) +int iw; +int ih; +int flags; +XWDFileHeader *win; +enum orientation orientation; +char *data; +{ + unsigned long swaptest = 1; + int iwb = win->bytes_per_line; + register int i; + int bytes; + unsigned char *buffer = (unsigned char *)data; + register int ocount=0; + extern char hex1[],hex2[]; + static char hex[] = "0123456789abcdef"; + + if (orientation == LANDSCAPE) { + /* read in and rotate the entire image */ + /* The Postscript language has a rotate operator, but using it + * seem to make printing (at least on the Apple Laserwriter + * take about 10 times as long (40 minutes for a 1024x864 full-screen + * dump)! Therefore, we rotate the image here. + */ + int ocol = ih; + int owidth = (ih+31)/32; /* width of rotated image, in bytes */ + int oheight = (iw+31)/32; /* height of rotated image, in scanlines */ + register char *p, *q; + char *obuf; + unsigned char *ibuf; + owidth *= 4; + oheight *= 32; + + /* Allocate buffer for the entire rotated image (output). + * Owidth and Oheight are rounded up to a multiple of 32 bits, + * to avoid special cases at the boundaries + */ + obuf = malloc((unsigned)(owidth*oheight)); + if (obuf==0) { + fprintf(stderr,"xpr: cannot allocate %d bytes\n",owidth*oheight); + exit(1); + } + bzero(obuf,owidth*oheight); + + ibuf = (unsigned char *)malloc((unsigned)(iwb + 3)); + for (i=0;i<ih;i++) { + bcopy((char *)buffer, (char *)ibuf, iwb); + buffer += iwb; + if (!(*(char *) &swaptest)) + _swaplong((char *)ibuf,(long)iwb); + ps_bitrot(ibuf,iw,--ocol,owidth,obuf); + } + if (!(*(char *) &swaptest)) + _swaplong(obuf,(long)(iw*owidth)); + q = &obuf[iw*owidth]; + bytes = (ih+7)/8; + for (p=obuf;p<q;p+=owidth) + ocount = ps_putbuf((unsigned char *)p,bytes,ocount,flags&F_COMPACT); + } + else { + for (i=0;i<ih;i++) { + ocount = ps_putbuf(buffer,(iw+7)/8,ocount,flags&F_COMPACT); + buffer += iwb; + } + } + if (flags & F_COMPACT) { + if (ocount) { + /* pad to an integral number of lines */ + while (ocount++ < LINELEN) + /* for debugging, pad with a "random" value */ + putchar(hex[ocount&15]); + putchar('\n'); + } + } +} + +unsigned char _reverse_byte[0x100] = { + 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, + 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, + 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, + 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, + 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, + 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, + 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, + 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, + 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, + 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, + 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, + 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, + 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, + 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, + 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, + 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, + 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, + 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, + 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, + 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, + 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, + 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, + 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, + 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, + 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, + 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, + 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, + 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, + 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, + 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, + 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, + 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff +}; + +_invbits (b, n) + register unsigned char *b; + register long n; +{ + do { + *b = ~*b; + b++; + } while (--n > 0); + +} + +/* copied from lib/X/XPutImage.c */ + +_swapbits (b, n) + register unsigned char *b; + register long n; +{ + do { + *b = _reverse_byte[*b]; + b++; + } while (--n > 0); + +} + +_swapshort (bp, n) + register char *bp; + register long n; +{ + register char c; + register char *ep = bp + n; + do { + c = *bp; + *bp = *(bp + 1); + bp++; + *bp = c; + bp++; + } + while (bp < ep); +} + +_swaplong (bp, n) + register char *bp; + register long n; +{ + register char c; + register char *ep = bp + n; + register char *sp; + do { + sp = bp + 3; + c = *sp; + *sp = *bp; + *bp++ = c; + sp = bp + 1; + c = *sp; + *sp = *bp; + *bp++ = c; + bp += 2; + } + while (bp < ep); +} + +/* Dump some bytes in hex, with bits in each byte reversed + * Ocount is number of chacters that have been written to the current + * output line. It's new value is returned as the result of the function. + * Ocount is ignored (and the return value is meaningless) if compact==0. + */ +int +ps_putbuf(s, n, ocount, compact) +register unsigned char *s; /* buffer to dump */ +register int n; /* number of BITS to dump */ +register int ocount; /* position on output line for next char */ +int compact; /* if non-zero, do compaction (see below) */ +{ + register int ffcount = 0; + extern char hex1[],hex2[]; + static char hex[] = "0123456789abcdef"; +#define PUT(c) { putchar(c); if (++ocount>=LINELEN) \ + { putchar('\n'); ocount=0; }} + + if (compact) { + /* The following loop puts out the bits of the image in hex, + * compressing runs of white space (represented by one bits) + * according the the following simple algorithm: A run of n + * 'ff' bytes (i.e., bytes with value 255--all ones), where + * 1<=n<=255, is represented by a single 'ff' byte followed by a + * byte containing n. + * On a typical dump of a full screen pretty much covered by + * black-on-white text windows, this compression decreased the + * size of the file from 223 Kbytes to 63 Kbytes. + * Of course, another factor of two could be saved by sending + * the bytes 'as is' rather than in hex, using some sort of + * escape convention to avoid problems with control characters. + * Another popular encoding is to pack three bytes into 4 'sixels' + * as in the LN03, etc, but I'm too lazy to write the necessary + * PostScript code to unpack fancier representations. + */ + while (n--) { + if (*s == 0xff) { + if (++ffcount == 255) { + PUT('f'); PUT('f'); + PUT('f'); PUT('f'); + ffcount = 0; + } + } + else { + if (ffcount) { + PUT('f'); PUT('f'); + PUT(hex[ffcount >> 4]); + PUT(hex[ffcount & 0xf]); + ffcount = 0; + } + PUT(hex1[*s]); + PUT(hex2[*s]); + } + s++; + } + if (ffcount) { + PUT('f'); PUT('f'); + PUT(hex[ffcount >> 4]); + PUT(hex[ffcount & 0xf]); + ffcount = 0; + } + } + else { /* no compaction: just dump the image in hex (bits reversed) */ + while (n--) { + putchar(hex1[*s]); + putchar(hex2[*s++]); + } + putchar('\n'); + } + return ocount; +} + +ps_bitrot(s,n,col,owidth,obuf) +unsigned char *s; +register int n; +int col; +register int owidth; +char *obuf; +/* s points to a chunk of memory and n is its width in bits. + * The algorithm is, roughly, + * for (i=0;i<n;i++) { + * OR the ith bit of s into the ith row of the + * (col)th column of obuf + * } + * Assume VAX bit and byte ordering for s: + * The ith bit of s is s[j]&(1<<k) where i=8*j+k. + * It can also be retrieved as t[j]&(1<<k), where t=(int*)s and i=32*j+k. + * Also assume VAX bit and byte ordering for each row of obuf. + * Ps_putbuf() takes care of converting to Motorola 68000 byte and bit + * ordering. The following code is very carefully tuned to yield a very + * tight loop on the VAX, since it easily dominates the entire running + * time of this program. In particular, iwordp is declared last, since + * there aren't enough registers, and iwordp is referenced only once + * every 32 times through the loop. + */ +{ + register int mask = 1<<(col%32); + register int iword; /* current input word (*iwordp) */ + register int b = 0; /* number of bits in iword left to examine */ + register char *opos = obuf + (col/32)*4; + /* pointer to word of obuf to receive next output bit */ + register int *iwordp = (int *) s; /* pointer to next word of s */ + + while (--n>=0) { + if (--b < 0) { + iword = *iwordp++; + b = 31; + } + if (iword & 1) { + *(int *)opos |= mask; + } + opos += owidth; + iword >>= 1; + } +} + +/* fullread() is the same as read(), except that it guarantees to + read all the bytes requested. */ + +fullread (file, data, nbytes) + int file; + char *data; + int nbytes; + { + int bytes_read; + while ((bytes_read = read(file, data, nbytes)) != nbytes) { + if (bytes_read < 0) { + perror ("error while reading standard input"); + return; + } + else if (bytes_read == 0) { + fprintf (stderr, "xpr: premature end of file\n"); + return; + } + nbytes -= bytes_read; + data += bytes_read; + } + } + +/* mapping tables to map a byte in to the hex representation of its + * bit-reversal + */ +char hex1[]="084c2a6e195d3b7f084c2a6e195d3b7f084c2a6e195d3b7f084c2a6e195d3b7f\ +084c2a6e195d3b7f084c2a6e195d3b7f084c2a6e195d3b7f084c2a6e195d3b7f\ +084c2a6e195d3b7f084c2a6e195d3b7f084c2a6e195d3b7f084c2a6e195d3b7f\ +084c2a6e195d3b7f084c2a6e195d3b7f084c2a6e195d3b7f084c2a6e195d3b7f"; + +char hex2[]="000000000000000088888888888888884444444444444444cccccccccccccccc\ +2222222222222222aaaaaaaaaaaaaaaa6666666666666666eeeeeeeeeeeeeeee\ +111111111111111199999999999999995555555555555555dddddddddddddddd\ +3333333333333333bbbbbbbbbbbbbbbb7777777777777777ffffffffffffffff"; + @@ -0,0 +1,33 @@ +#ifndef X_NOT_STDC_ENV +#include <stdlib.h> +#else +char *malloc(), *realloc(), *calloc(); +#endif +#if defined(macII) && !defined(__STDC__) /* stdlib.h fails to define these */ +char *malloc(), *realloc(), *calloc(); +#endif /* macII */ + +/* 3812 PagePrinter macros */ +#define PPI 240 +#define inch2pel(inches) ((int) ((inches) * PPI)) +#define DEFAULT_WIDTH 8.5 +#define X_MAX_PELS inch2pel(DEFAULT_WIDTH) +#define DEFAULT_LENGTH 11 +#define Y_MAX_PELS inch2pel(DEFAULT_LENGTH) + +#define INTENSITY(color) (30L*(int)(color)->red + \ + 59L*(int)(color)->green + \ + 11L*(int)(color)->blue) + +#define INTENSITYPER(per) (((1<<16)-1)*((long)per)) +#define HALFINTENSITY INTENSITYPER(50) + +enum orientation { + UNSPECIFIED = -1, + PORTRAIT = 0, + LANDSCAPE = 1, + UPSIDE_DOWN = 2, + LANDSCAPE_LEFT = 3 + }; + +enum device {LN01, LN03, LA100, PS, PP, LJET, PJET, PJETXL}; @@ -0,0 +1,338 @@ +.\" $XConsortium: xpr.man,v 1.22 94/04/17 20:44:06 gildea Exp $ +.TH XPR 1 "Release 6" "X Version 11" +.SH NAME +xpr \- print an X window dump +.SH SYNOPSIS +.B xpr +[ +.B \-device +.I devtype +] [ +.B \-scale +.I scale +] [ +.B \-height +.I inches +] [ +.B \-width +.I inches +] [ +.B \-left +.I inches +] [ +.B \-top +.I inches +] [ +.B \-header +.I string +] [ +.B \-trailer +.I string +] [ +.B \-landscape +] [ +.B \-portrait +] [ +.B \-plane +.I number +] [ +.B \-gray +] [ +.B \-rv +] [ +.B \-compact +] [ +.B \-output +.I filename +] [ +.B \-append +.I filename +] [ +.B \-noff +] [ +.B \-split +.I n +] [ +.B \-psfig +] [ +.B \-density +.I dpi +] [ +.B \-cutoff +.I level +] [ +.B \-noposition +] [ +.B \-gamma +.I correction +] [ +.B \-render +.I algorithm +] [ +.B \-slide +] [ +.I filename +] +.SH DESCRIPTION + +.I xpr +takes as input a window dump file produced by +.IR xwd(1) +and formats it for output on PostScript printers, the Digital LN03 or LA100, +the IBM PP3812 page printer, the HP LaserJet (or other PCL printers), +or the HP PaintJet. If no file +argument is given, the standard input is used. By default, \fIxpr\fP +prints the largest possible representation of the window on the +output page. Options allow the user to add headers and trailers, +specify margins, adjust the scale and orientation, and append +multiple window dumps to a single output file. Output is to +standard output unless +.B \-output +is specified. +.sp 1 +.ne 8 +.B Command Options +.sp 1 +.IP "\fB\-device\fP \fIdevtype\fP" +Specifies the device on which the file will be printed. Currently supported: +.RS 12 +.PD 0 +.TP +.B la100 +Digital LA100 +.TP +.B ljet +\s-1HP\s+1 LaserJet series and other monochrome PCL devices +such as ThinkJet, QuietJet, RuggedWriter, \s-1HP\s+12560 series, +and \s-1HP\s+12930 series printers +.TP +.B ln03 +Digital LN03 +.TP +.B pjet +HP PaintJet (color mode) +.TP +.B pjetxl +HP HP PaintJet XL Color Graphics Printer (color mode) +.TP +.B pp +IBM PP3812 +.TP +.B ps +PostScript printer +.PD +.RE +.IP +The default is PostScript. +\fB-device lw\fP (LaserWriter) is equivalent to -device ps and is +provided only for backwards compatibility. +.IP "\fB\-scale\fP \fIscale\fP" +Affects the size of the window on the page. The PostScript, LN03, and HP +printers are able to +translate each bit in a window pixel map into a grid of a specified size. +For example each bit might translate into a 3x3 grid. This would be +specified by \fB\-scale\fP \fI3\fP. By default a window is printed +with the largest scale that will fit onto the page for the specified +orientation. +.IP "\fB\-height\fP \fIinches\fP" +Specifies the maximum height of the page. +.IP "\fB\-width\fP \fIinches\fP" +Specifies the maximum width of the page. +.IP "\fB\-left\fP \fIinches\fP" +Specifies the left margin in inches. Fractions +are allowed. By default the window is centered in the page. +.IP "\fB\-top\fP \fIinches\fP" +Specifies the top margin for the picture in inches. Fractions are +allowed. +.IP "\fB\-header\fP \fIstring\fP" +Specifies a header string to be printed above the window. +.IP "\fB\-trailer\fP \fIstring\fP" +Specifies a trailer string to be printed below the window. +.IP "\fB\-landscape\fP" +Forces the window to printed in landscape mode. By default +a window is printed such that its longest side follows the long side of +the paper. +.IP "\fB\-plane\fP \fInumber\fP" +Specifies which bit plane to use in an image. The default is to use the +entire image and map values into black and white based on color intensities. +.IP "\fB\-gray\fP \fI 2 | 3 | 4\fP" +Uses a simple 2x2, 3x3, or 4x4 gray scale conversion on a color image, +rather than mapping to strictly black and white. This doubles, +triples, or quadruples the effective width and height of the image. +.IP "\fB\-portrait\fP" +Forces the window to be printed in portrait mode. By default +a window is printed such that its longest side follows the long side of +the paper. +.IP "\fB\-rv\fP" +Forces the window to be printed in reverse video. +.IP "\fB\-compact\fP" +Uses simple run-length encoding for compact representation of windows +with lots of white pixels. +.IP "\fB\-output\fP \fIfilename\fP" +Specifies an output file name. If this option is not specified, standard +output is used. +.IP "\fB\-append\fP \fIfilename\fP" +Specifies a filename previously produced by \fIxpr\fP to which the window +is to be appended. +.IP "\fB\-noff\fP" +When specified in conjunction with \fB\-append\fP, the window will appear +on the same page as the previous window. +.IP "\fB\-split\fP \fIn\fP" +This option allows the user to split a window onto several pages. +This might be necessary for very large windows that would otherwise +cause the printer to overload and print the page in an obscure manner. +.IP "\fB\-psfig\fP" +Suppress translation of the PostScript picture to the center of the page. +.IP "\fB\-density\fP \fIdpi\fP" +Indicates what dot-per-inch density should be used by the HP printer. +.IP "\fB\-cutoff\fP \fIlevel\fP" +Changes the intensity level where colors are mapped to either black or +white for monochrome output on a LaserJet printer. +The \fIlevel\fP is expressed as percentage of +full brightness. Fractions are allowed. +.IP "\fB\-noposition\fP" +This option causes header, trailer, and image positioning command +generation to be bypassed for LaserJet, PaintJet and +PaintJet XL printers. +.IP "\fB\-gamma\fP \fIcorrection\fP" +This changes the intensity of the colors printed by +PaintJet XL printer. The \fIcorrection\fP is +a floating point value in the range 0.00 to 3.00. +Consult the operator's manual to determine the correct value for +the specific printer. +.IP "\fB\-render\fP \fIalgorithm\fP" +This allows PaintJet XL printer to render the +image with the best quality versus performance tradeoff. +Consult the operator's manual to determine which \fIalgorithm\fPs +are available. +.IP "\fB\-slide\fP" +This option allows overhead transparencies to be printed +using the PaintJet and PaintJet XL printers. + +.SH SEE ALSO +xwd(1), xwud(1), X(1) +.SH LIMITATIONS + +The current version of \fIxpr\fP can generally print out on the LN03 +most X windows that are not larger than two-thirds of the screen. +For example, it will be able to print out a large Emacs window, but +it will usually fail when trying to print out the entire screen. The +LN03 has memory limitations that can cause it to incorrectly print +very large or complex windows. The two most common errors +encountered are ``band too complex'' and ``page memory exceeded.'' +In the first case, a window may have a particular six pixel row that +contains too many changes (from black to white to black). This will +cause the printer to drop part of the line and possibly parts of the +rest of the page. The printer will flash the number `1' on its front +panel when this problem occurs. A possible solution to this problem +is to increase the scale of the picture, or to split the picture onto +two or more pages. The second problem, ``page memory exceeded,'' +will occur if the picture contains too much black, or if the picture +contains complex half-tones such as the background color of a +display. When this problem occurs the printer will automatically +split the picture into two or more pages. It may flash the number +`5' on its from panel. There is no easy solution to this problem. +It will probably be necessary to either cut and paste, or to rework the +application to produce a less complex picture. + +There are several limitations on the LA100 support: +the picture will always be printed in +portrait mode, there is no scaling, +and the aspect ratio will be slightly off. + +Support for PostScript output currently cannot handle the \fB-append\fP, +\fB-noff\fP or \fB-split\fP options. + +The \fB-compact\fP option is +.I only +supported for PostScript output. +It compresses white space but not black space, so it is not useful for +reverse-video windows. + +For color images, should map directly to PostScript image support. + +.SH "HP PRINTERS" + +If no \fB\-density\fP is specified on the command line 300 dots per inch +will be assumed for \fIljet\fP and 90 dots per inch for \fIpjet\fP. +Allowable \fIdensity\fP values for a LaserJet printer are 300, 150, 100, +and 75 dots per inch. Consult the operator's manual to determine densities +supported by other printers. + +If no \fB\-scale\fP is specified the image will be expanded to fit the +printable page area. + +The default printable page area is 8x10.5 inches. Other paper sizes can +be accommodated using the \fB\-height\fP and \fB\-width\fP options. + +Note that a 1024x768 image fits the default printable area when processed +at 100 dpi with scale=1, the same image can also be printed using 300 dpi +with scale=3 but will require considerably more data be transferred to the +printer. + +\fIxpr\fP may be tailored for use with monochrome PCL printers other than +the LaserJet. To print on a ThinkJet (\s-1HP\s+12225A) \fIxpr\fP could be +invoked as: +.sp +.RS 4 +xpr -density 96 -width 6.667 \fIfilename\fP +.RE +.sp +or for black-and-white output to a PaintJet: +.sp +.RS 4 +xpr -density 180 \fIfilename\fP +.RE + +The monochrome intensity of a pixel is computed as 0.30*R + 0.59*G ++ 0.11*B. +If a pixel's computed intensity is less than the \fB\-cutoff\fP +level it will print as white. This maps light-on-dark display images +to black-on-white hardcopy. The default cutoff intensity is 50% of full +brightness. Example: specifying \fB\-cutoff 87.5\fP moves the +white/black intensity point to 87.5% of full brightness. + +A LaserJet printer must be configured with sufficient memory to handle the +image. For a full page at 300 dots per inch approximately 2MB of printer +memory is required. + +Color images are produced on the PaintJet +at 90 dots per inch. The +PaintJet is limited to sixteen colors from its 330 color palette on each +horizontal print line. \fIxpr\fP will issue a warning message if more than +sixteen colors are encountered on a line. \fIxpr\fP will program the +PaintJet for the first sixteen colors encountered on each line and use the +nearest matching programmed value for other colors present on the line. + +Specifying the \fB\-rv\fP, reverse video, option for the PaintJet will +cause black and white to be interchanged on the output image. No other +colors are changed. + +Multiplane images must be recorded by \fIxwd\fP in \fIZPixmap\fP format. +Single plane (monochrome) images may be in either \fIXYPixmap\fP or +\fIZPixmap\fP format. + +Some PCL printers do not recognize image positioning commands. Output for +these printers will not be centered on the page and header and trailer +strings may not appear where expected. + +The \fB\-gamma\fP and \fB-render\fP options are supported only on +the PaintJet XL printers. + +The \fB\-slide\fP option is not supported for LaserJet printers. + +The \fB\-split\fP option is not supported for HP printers. + +The \fB\-gray\fP option is not supported for HP or IBM printers. +.br +Copyright 1986, Marvin Solomon and the University of Wisconsin. +.br +Copyright 1988, Hewlett Packard Company. +.br +See \fIX(1)\fP for a full statement of rights and permissions. +.SH AUTHORS +Michael R. Gretzinger, MIT Project Athena, +Jose Capo, MIT Project Athena (PP3812 support), +Marvin Solomon, University of Wisconsin, +Bob Scheifler, MIT, Angela Bock and E. Mike Durbin, Rich Inc. (grayscale), +Larry Rupp, HP (HP printer support). |