#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
#define NL_SETN 2
#include <nl_types.h>
extern nl_catd nlmsg_fd;
#endif
#ifndef TRUE
# define FALSE 0
# define TRUE 1
#endif
#define STDWIDTH 8.0
#define STDHEIGHT 10.5
#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;
static Area page;
static Location headerloc;
static Location trailerloc;
static Location imageloc;
static int headerlimit;
static int trailerlimit;
static XWDFileHeader xwd_header;
static XColor *xwd_colors;
static char *xwd_image;
static unsigned long Z_pixel_mask;
static int true_scale;
typedef struct {
unsigned long Rmask, Gmask, Bmask;
int Rshift, Gshift, Bshift;
} RGBshiftmask;
static void set_image_limits ( int scale, int density, enum orientation orient, Area print_area);
static void set_header_trailer_limits (char *header, char *trailer, long printwidth);
static void set_print_locations ( int scale, int density, int top, int left, const char *header, const char *trailer, enum orientation orient, int position_on_page);
static int scale_raster (
int density,
enum orientation orient,
Area print_area);
static void scale_and_orient_image (
int *scale, int *density,
int width, int height, int left, int top,
const char *header, const char *trailer,
enum orientation *orient,
int position_on_page,
enum device device);
static void setup_RGBshiftmask (RGBshiftmask *sm, unsigned long rmask, unsigned long gmask, unsigned long bmask);
static void swap_black_and_white (void);
static void reset_color_mapping (void);
static void prepare_color_mapping (
int invert, int paintjet,
unsigned int cutoff,
FILE *out);
static
void select_grey (int level, int *r, int *g, int *b);
static int load_printer_color (
long index,
int nearmatch,
enum device device);
static int lookup_color_index (long i);
static void select_printer_color (
long index,
int *red, int *green, int *blue,
long *compositeRGB,
enum device device);
static int color_already_in_printer (long compositeRGB, long *pindex);
static int program_new_printer_color (
int red, int green, int blue,
long compositeRGB,
long *pindex);
static long composite_diff (long x, long y);
static long find_nearest_programmed_color (long compositeRGB);
static void add_index_to_chain (
long cindex,
long pindex);
static int load_printer_color_DT (
long index,
int nearmatch,
enum device device);
static int load_line_colors (
long *line,
int length, int nearmatch,
enum device device);
static void download_colors (
long *line,
int length,
enum device device);
static void validate_visual(void);
static void read_xwd_data (FILE *in);
static void write_image_prefix (
FILE *out,
int scale, int density,
const char *header,
enum device device,
int position_on_page, int initial_formfeed,
enum orientation orient,
float gamma,
int render,
int slide);
static void write_image_suffix (
FILE *out,
const char *trailer,
int position_on_page,
int slide, int render,
enum device device);
static unsigned long Z_image_pixel (int x, int y);
static unsigned long XY_image_pixel (int x, int y);
static void direct_by_pixel(
FILE *out,
long *line,
int length,
enum device device);
static void index_by_pixel(
FILE *out,
long *line,
int length);
static void write_raster_line (
FILE *out,
int scale,
enum device device,
long *line,
int length);
static void write_portrait_Z_image (
FILE *out,
int scale,
enum device device);
static void write_landscape_Z_image (
FILE *out,
int scale,
enum device device);
static void write_portrait_XY_image (
FILE *out,
int scale,
enum device device);
static void write_landscape_XY_image (
FILE *out,
int scale,
enum device device);
static void write_Z_image (
FILE *out,
int scale,
enum orientation orient,
enum device device);
static void write_XY_image (
FILE *out,
int scale,
enum orientation orient,
enum device device);
static void write_image (
FILE *out,
int scale,
enum orientation orient,
enum device device);
static void fatal_err (const char *s, ...);
#define dot_centipoints(s,d) ((7200.0 * (s)) / (d))
static
void set_image_limits (
int scale, int density,
enum orientation orient,
Area print_area)
{
Area print_dots;
double dotsize;
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);
}
static
void set_header_trailer_limits (char *header, char *trailer, long printwidth)
{
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';
}
}
static
void set_print_locations (
int scale, int density,
int top, int left,
const char *header, const char *trailer,
enum orientation orient,
int position_on_page)
{
Area image;
double dotsize;
dotsize = dot_centipoints(scale, density);
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) {
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;
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;
}
}
}
static
int scale_raster (
int density,
enum orientation orient,
Area print_area)
{
Area image;
int h_scale, v_scale;
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;
}
h_scale = print_area.width / image.width;
v_scale = print_area.height / image.height;
return (((h_scale > 0) && (v_scale > 0))
? ((h_scale<v_scale) ? h_scale : v_scale)
: 1);
}
static
void scale_and_orient_image (
int *scale, int *density,
int width, int height, int left, int top,
const char *header, const char *trailer,
enum orientation *orient,
int position_on_page,
enum device device)
{
Area usable;
page.width = (width >= 0) ? width * 24 : STDWIDTH * 7200;
page.height = (height >= 0) ? height * 24 : STDHEIGHT * 7200;
if (device == PJETXL)
page.height = page.height - 7200;
usable.width = page.width - ((left > 0) ? (left * 24) : 0);
usable.height = page.height - ((top > 0) ? (top * 24) : 0)
- ((header) ? CHARHEIGHT : 0)
- ((trailer) ? CHARHEIGHT : 0);
if ((usable.width <= 0) || (usable.height <= 0)) {
fatal_err((catgets(nlmsg_fd,NL_SETN,4,
"No space available on page for image.")));
}
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;
}
if (*density <= 0) {
switch(device) {
case LJET: *density = 300;
break;
case PJET: *density = 90;
break;
case PJETXL: *density = 180;
break;
}
}
if (*scale <= 0)
*scale = scale_raster(*density, *orient, usable);
set_image_limits(*scale, *density, *orient, usable);
set_header_trailer_limits(header, trailer, usable.width);
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)
long *colormap;
long pjcolor[MAX_PJ_COLOR];
static int color_warning_given = FALSE;
char Direct_or_TrueColor;
typedef struct colorindex {
long index;
long pjcolor_index;
struct colorindex *next;
} COLORINDEX;
struct {
int PaintJet;
int Invert;
unsigned int CutOff;
FILE *OutFile;
COLORINDEX *indexchain, *freechain;
RGBshiftmask sm;
} color;
static
void setup_RGBshiftmask (
RGBshiftmask *sm,
unsigned long rmask, unsigned long gmask, unsigned long 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;
}
static
void swap_black_and_white (void)
{
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;
}
static
void reset_color_mapping (void)
{
int n;
long *cmap;
COLORINDEX *splice;
for (n=0; n<MAX_PJ_COLOR; n++)
pjcolor[n] = EMPTY;
if (!color.PaintJet) {
pjcolor[0] = WHITE;
pjcolor[1] = BLACK;
}
if (Direct_or_TrueColor) {
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)
static
void prepare_color_mapping (
int invert, int 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.")));
if (paintjet && invert)
swap_black_and_white();
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();
}
#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))
static
void select_grey (int level, int *r, int *g, int *b)
{
if (level > 66) {
*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 {
*r = 4; *g = 4; *b = 6;
}
}
static
int load_printer_color (
long index,
int nearmatch,
enum device device)
{
int n, red, blue, green, xred, xgreen, xblue;
long compositeRGB;
if (colormap[index] != EMPTY)
return(1);
else {
xred = xwd_colors[index].red;
xgreen = xwd_colors[index].green;
xblue = xwd_colors[index].blue;
if (device == PJET) {
red = fixred(xred);
green = fixgreen(xgreen);
blue = fixblue(xblue);
if (is_grey(xred, xgreen, xblue))
select_grey(red, &red, &green, &blue);
}
compositeRGB = (red << 16) | (green << 8) | blue;
for (n=0; n<MAX_PJ_COLOR; n++) {
if (pjcolor[n] == compositeRGB) {
colormap[index] = n;
return(1);
} else if (pjcolor[n] == EMPTY) {
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);
pjcolor[n] = compositeRGB;
colormap[index] = n;
return(1);
}
}
if (nearmatch)
colormap[index] = find_nearest_programmed_color(compositeRGB);
}
return(0);
}
static
int lookup_color_index (long i)
{
COLORINDEX *start, *current;
start = current = color.indexchain;
if (current == NULL)
return(-1);
do {
if (current->index == i) {
color.indexchain = current;
return(current->pjcolor_index);
}
current = current->next;
} while (current != start);
return(-1);
}
static
void select_printer_color (
long index,
int *red, int *green, int *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;
}
if (device == PJET) {
*red = fixred(xred);
*green = fixgreen(xgreen);
*blue = fixblue(xblue);
if (is_grey(xred, xgreen, xblue))
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
*compositeRGB = (Intensity(xred, xgreen, xblue) < color.CutOff)
? (color.Invert ? BLACK : WHITE)
: (color.Invert ? WHITE : BLACK);
}
static
int color_already_in_printer (long compositeRGB, long *pindex)
{
int n;
for (n=0; n<MAX_PJ_COLOR; n++)
if (pjcolor[n] == EMPTY)
return(0);
else if (pjcolor[n] == compositeRGB) {
*pindex = n;
return(1);
}
return(0);
}
static
int program_new_printer_color (
int red, int green, int blue,
long compositeRGB,
long *pindex)
{
int n;
for (n=0; n<MAX_PJ_COLOR; n++)
if (pjcolor[n] == EMPTY) {
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);
pjcolor[n] = compositeRGB;
*pindex = n;
return(1);
}
return(0);
}
static
long composite_diff (long x, long 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);
}
static
long find_nearest_programmed_color (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);
}
static
void add_index_to_chain (
long cindex,
long pindex)
{
COLORINDEX *new;
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;
}
new->index = cindex;
new->pjcolor_index = pindex;
if (color.indexchain == NULL)
new->next = new;
else {
new->next = color.indexchain->next;
color.indexchain->next = new;
}
color.indexchain = new;
}
static
int load_printer_color_DT (
long index,
int nearmatch,
enum device device)
{
int pjred, pjgreen, pjblue;
long compositeRGB;
long pindex;
if (lookup_color_index(index) >= 0)
return(1);
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);
} else if (program_new_printer_color(pjred, pjgreen, pjblue,
compositeRGB, &pindex)) {
add_index_to_chain(index, pindex);
return(1);
} else if (nearmatch) {
add_index_to_chain(index, find_nearest_programmed_color(compositeRGB));
return(0);
}
}
return(0);
}
static
int load_line_colors (
long *line,
int length, int nearmatch,
enum device device)
{
int result = 1;
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);
}
static
void download_colors (
long *line,
int length,
enum device device)
{
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;
}
}
}
static
void validate_visual(void)
{
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_err(errmsg, depth, "GrayScale"); break;
case StaticGray:
if (depth > 8) fatal_err(errmsg, depth, "StaticGray"); break;
case PseudoColor:
if (depth > 8) fatal_err(errmsg, depth, "PseudoColor"); break;
case StaticColor:
if (depth > 8) fatal_err(errmsg, depth, "StaticColor"); break;
case DirectColor:
case TrueColor:
if (depth != 12 && depth != 24)
fatal_err(errmsg, depth, (xwd_header.visual_class == DirectColor)
? "DirectColor" : "TrueColor");
break;
default:
fatal_err((catgets(nlmsg_fd,NL_SETN,26,
"visual class #%d not supported.\n")), xwd_header.visual_class);
}
}
static
void read_xwd_data (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];
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();
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;
}
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.")));
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));
}
}
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.")));
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.")));
}
static
void write_image_prefix (
FILE *out,
int scale, int density,
const char *header,
enum device device,
int position_on_page, int initial_formfeed,
enum orientation orient,
float gamma,
int render,
int slide)
{
if (initial_formfeed)
fprintf(out,"\014");
if (header) {
if (position_on_page)
fprintf(out,"\033&a%dH\033&a%dV",
(int) headerloc.x / 10, (int) headerloc.y / 10);
fprintf(out,"%s\n", header);
}
if (position_on_page)
fprintf(out,"\033&a%dH\033&a%dV",
(int) imageloc.x / 10, (int) imageloc.y / 10);
if (slide && device != LJET)
fprintf(out, "\033&k3W");
fprintf(out,"\033*t%dR", density);
if (device == PJET) {
fprintf(out,"\033*r4U");
fprintf(out,"\033*r%dS",
((int) (orient == PORTRAIT) ? limit.width : limit.height)
* scale);
}
if (device == PJETXL) {
double dotsize;
int n;
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)
fwrite("\033*v6W\000\003\010\010\010\010", 1, 11, out);
else {
fwrite("\033*v6W\000\001\010\010\010\010", 1, 11, out);
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);
}
}
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));
}
if (device != PJETXL)
fprintf(out,"\033*r1A");
else
fprintf(out,"\033*r3A");
}
static
void write_image_suffix (
FILE *out,
const char *trailer,
int position_on_page,
int slide, int render,
enum device device)
{
if (device == PJETXL)
fprintf(out,"\033*rC");
else
fprintf(out,"\033*rB");
if (slide && device != LJET)
fprintf(out, "\033&k1W");
if (device == PJETXL) {
if (render)
fprintf(out, "\033*t3J");
fprintf(out, "\033&a0N");
}
if (trailer) {
if (position_on_page)
fprintf(out,"\033&a%dH\033&a%dV",
(int) trailerloc.x / 10, (int) trailerloc.y / 10);
fprintf(out,"%s\n", trailer);
}
}
static
unsigned long Z_image_pixel (int x, int 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:
if (xwd_header.bits_per_pixel == 1) {
if (xwd_header.byte_order == MSBFirst)
pixel = *image >> (7 - (x % 8));
else
pixel = *image >> (x % 8);
} else {
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);
}
static
unsigned long XY_image_pixel (int x, int 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);
}
static
void direct_by_pixel(
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);
}
}
static
void index_by_pixel(
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);
}
static
void write_raster_line (
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);
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);
}
static
void write_portrait_Z_image (
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);
}
}
static
void write_landscape_Z_image (
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);
}
}
static
void write_portrait_XY_image (
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);
}
}
static
void write_landscape_XY_image (
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);
}
}
static
void write_Z_image (
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);
}
static
void write_XY_image (
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);
}
static
void write_image (
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(
FILE *in, FILE *out,
int scale, int density,
int width, int height, int left, int top,
const char *header, const char *trailer,
enum orientation orient,
int invert, int initial_formfeed, int position_on_page, int slide,
enum device device,
unsigned int cutoff,
float gamma,
int render)
{
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);
}
static
void fatal_err (const char *s, ...)
{
fprintf(stderr, "%s: %s\n", progname, s);
exit(EXIT_FAILURE);
}