Files
gimp/plug-ins/print/print-escp2.c
Sven Neumann 97297cb810 Added checks for print spoolers to configure.in as suggested by Michael
Sweet. The print plug-in still needs some changes to Makefile.am to make
make use of this.

Updated print and sgi plug-ins to version on the registry.


--Sven
1998-04-01 22:14:53 +00:00

623 lines
15 KiB
C

/*
* "$Id$"
*
* Print plug-in EPSON ESC/P2 driver for the GIMP.
*
* Copyright 1997-1998 Michael Sweet (mike@easysw.com)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Contents:
*
* escp2_print() - Print an image to an EPSON printer.
* escp2_write() - Send ESC/P2 graphics using TIFF packbits compression.
*
* Revision History:
*
* $Log$
* Revision 1.4 1998/04/01 22:14:44 neo
* Added checks for print spoolers to configure.in as suggested by Michael
* Sweet. The print plug-in still needs some changes to Makefile.am to make
* make use of this.
*
* Updated print and sgi plug-ins to version on the registry.
*
*
* --Sven
*
* Revision 1.8 1998/01/21 21:33:47 mike
* Updated copyright.
*
* Revision 1.7 1997/11/12 15:57:48 mike
* Minor changes for clean compiles under Digital UNIX.
*
* Revision 1.7 1997/11/12 15:57:48 mike
* Minor changes for clean compiles under Digital UNIX.
*
* Revision 1.6 1997/07/30 20:33:05 mike
* Final changes for 1.1 release.
*
* Revision 1.6 1997/07/30 20:33:05 mike
* Final changes for 1.1 release.
*
* Revision 1.5 1997/07/30 18:47:39 mike
* Added scaling, orientation, and offset options.
*
* Revision 1.4 1997/07/15 20:57:11 mike
* Updated ESC 800/1520/3000 output code to use vertical spacing of 5 instead of 40.
*
* Revision 1.3 1997/07/03 13:21:15 mike
* Updated documentation for 1.0 release.
*
* Revision 1.2 1997/07/03 13:03:57 mike
* Added horizontal offset to try to center image.
* Got rid of initial vertical positioning since the top margin is
* now set properly.
*
* Revision 1.2 1997/07/03 13:03:57 mike
* Added horizontal offset to try to center image.
* Got rid of initial vertical positioning since the top margin is
* now set properly.
*
* Revision 1.1 1997/07/02 13:51:53 mike
* Initial revision
*/
#include "print.h"
/*
* Local functions...
*/
static void escp2_write(FILE *, unsigned char *, int, int, int, int, int, int);
/*
* 'escp2_print()' - Print an image to an EPSON printer.
*/
void
escp2_print(FILE *prn, /* I - Print file or command */
GDrawable *drawable, /* I - Image to print */
int media_size, /* I - Output size */
int xdpi, /* I - Horizontal resolution */
int ydpi, /* I - Vertical resolution */
int output_type, /* I - Color or grayscale? */
int model, /* I - Model of printer */
guchar *lut, /* I - Brightness lookup table */
guchar *cmap, /* I - Colormap (for indexed images) */
int orientation, /* I - Orientation of image */
int scaling, /* I - Scaling of image */
int left, /* I - Left offset of image (10ths) */
int top) /* I - Top offset of image (10ths) */
{
int x, y; /* Looping vars */
int n; /* Output number */
GPixelRgn rgn; /* Image region */
unsigned char *in, /* Input pixels */
*out, /* Output pixels */
*black, /* Black bitmap data */
*cyan, /* Cyan bitmap data */
*magenta, /* Magenta bitmap data */
*yellow; /* Yellow bitmap data */
int page_width, /* Width of page */
page_height, /* Height of page */
out_width, /* Width of image on page */
out_height, /* Height of image on page */
out_bpp, /* Output bytes per pixel */
temp_width, /* Temporary width of image on page */
temp_height, /* Temporary height of image on page */
landscape, /* True if we rotate the output 90 degrees */
length, /* Length of raster data */
errdiv, /* Error dividend */
errmod, /* Error modulus */
errval, /* Current error value */
errline, /* Current raster line */
errlast; /* Last raster line loaded */
convert_t colorfunc; /* Color conversion function... */
/*
* Setup a read-only pixel region for the entire image...
*/
gimp_pixel_rgn_init(&rgn, drawable, 0, 0, drawable->width, drawable->height,
FALSE, FALSE);
/*
* Choose the correct color conversion function...
*/
if (drawable->bpp < 3 && cmap == NULL)
output_type = OUTPUT_GRAY; /* Force grayscale output */
if (output_type == OUTPUT_COLOR)
{
out_bpp = 3;
if (drawable->bpp >= 3)
colorfunc = rgb_to_rgb;
else
colorfunc = indexed_to_rgb;
}
else
{
out_bpp = 1;
if (drawable->bpp >= 3)
colorfunc = rgb_to_gray;
else if (cmap == NULL)
colorfunc = gray_to_gray;
else
colorfunc = indexed_to_gray;
};
/*
* Compute the output size...
*/
landscape = 0;
page_width = media_width(media_size, xdpi);
page_height = media_height(media_size, ydpi);
/*
* Portrait width/height...
*/
out_width = page_width * scaling / 100;
out_height = out_width * ydpi / xdpi * drawable->height / drawable->width;
if (out_height > page_height)
{
out_height = page_height;
out_width = out_height * xdpi / ydpi * drawable->width / drawable->height;
};
/*
* Landscape width/height...
*/
temp_width = page_width * scaling / 100;
temp_height = temp_width * ydpi / xdpi * drawable->width / drawable->height;
if (temp_height > page_height)
{
temp_height = page_height;
temp_width = temp_height * xdpi / ydpi * drawable->height / drawable->width;
};
/*
* See which orientation has the greatest area...
*/
if ((temp_width * temp_height) > (out_width * out_height) &&
orientation != ORIENT_PORTRAIT)
{
out_width = temp_width;
out_height = temp_height;
landscape = 1;
/*
* Swap left/top offsets...
*/
x = top;
top = left;
left = x;
};
/*
* Let the user know what we're doing...
*/
gimp_progress_init("Printing...");
/*
* Send ESC/P2 initialization commands...
*/
fputs("\033@", prn); /* ESC/P2 reset */
fwrite("\033(G\001\000\001", 6, 1, prn); /* Enter graphics mode */
switch (ydpi) /* Set line feed increment */
{
case 180 :
fwrite("\033(U\001\000\024", 6, 1, prn);
break;
case 360 :
fwrite("\033(U\001\000\012", 6, 1, prn);
break;
case 720 :
fwrite("\033(U\001\000\005", 6, 1, prn);
break;
};
fwrite("\033(C\002\000", 5, 1, prn); /* Page length */
n = page_height + ydpi;
putc(n & 255, prn);
putc(n >> 8, prn);
if (left < 0 || top < 0)
{
left = (page_width - out_width) / 2;
top = (page_height - out_height + ydpi) / 2;
}
else
{
left *= xdpi / 10;
top = top * ydpi / 10 + ydpi / 2;
};
fwrite("\033(c\004\000", 5, 1, prn); /* Top/bottom margins */
putc(top & 255, prn);
putc(top >> 8, prn);
n = page_height + ydpi / 2;
putc(n & 255, prn);
putc(n >> 8, prn);
switch (model) /* Printer specific initialization */
{
case 0 : /* ESC */
break;
case 1 : /* ESC Pro, Pro XL, 400, 500 */
fwrite("\033(e\002\000\000\001", 7, 1, prn); /* Small dots */
break;
case 2 : /* ESC 1500 */
fwrite("\033(e\002\000\000\001", 7, 1, prn); /* Small dots */
break;
case 3 : /* ESC 600 */
if (output_type == OUTPUT_GRAY)
fwrite("\033(K\002\000\000\001", 7, 1, prn); /* Fast black printing */
else
fwrite("\033(K\002\000\000\002", 7, 1, prn); /* Color printing */
fwrite("\033(e\002\000\000\003", 7, 1, prn); /* Small dots */
break;
case 4 : /* ESC 800, 1520, 3000 */
if (output_type == OUTPUT_GRAY)
fwrite("\033(K\002\000\000\001", 7, 1, prn); /* Fast black printing */
else
fwrite("\033(K\002\000\000\002", 7, 1, prn); /* Color printing */
fwrite("\033(e\002\000\000\002", 7, 1, prn); /* Small dots */
break;
};
/*
* Allocate memory for the raster data...
*/
length = (out_width + 7) / 8;
if (output_type == OUTPUT_GRAY)
{
black = g_malloc(length);
cyan = NULL;
magenta = NULL;
yellow = NULL;
}
else
{
cyan = g_malloc(length);
magenta = g_malloc(length);
yellow = g_malloc(length);
if (model != 2)
black = g_malloc(length);
else
black = NULL;
};
/*
* Output the page, rotating as necessary...
*/
if (landscape)
{
in = g_malloc(drawable->height * drawable->bpp);
out = g_malloc(drawable->height * out_bpp);
errdiv = drawable->width / out_height;
errmod = drawable->width % out_height;
errval = 0;
errlast = -1;
errline = drawable->width - 1;
for (x = 0; x < out_height; x ++)
{
#ifdef DEBUG
printf("escp2_print: x = %d, line = %d, val = %d, mod = %d, height = %d\n",
x, errline, errval, errmod, out_height);
#endif /* DEBUG */
if ((x & 255) == 0)
gimp_progress_update((double)x / (double)out_height);
if (errline != errlast)
{
errlast = errline;
gimp_pixel_rgn_get_col(&rgn, in, errline, 0, drawable->height);
};
(*colorfunc)(in, out, drawable->height, drawable->bpp, lut, cmap);
if (output_type == OUTPUT_GRAY)
{
dither_black(out, x, drawable->height, out_width, black);
escp2_write(prn, black, length, 0, ydpi, model, out_width, left);
}
else
{
dither_cmyk(out, x, drawable->height, out_width, cyan, magenta,
yellow, black);
escp2_write(prn, cyan, length, 2, ydpi, model, out_width, left);
escp2_write(prn, magenta, length, 1, ydpi, model, out_width, left);
escp2_write(prn, yellow, length, 4, ydpi, model, out_width, left);
if (black != NULL)
escp2_write(prn, black, length, 0, ydpi, model, out_width, left);
};
fwrite("\033(v\002\000\001\000", 7, 1, prn); /* Feed one line */
errval += errmod;
errline -= errdiv;
if (errval >= out_height)
{
errval -= out_height;
errline --;
};
};
}
else
{
in = g_malloc(drawable->width * drawable->bpp);
out = g_malloc(drawable->width * out_bpp);
errdiv = drawable->height / out_height;
errmod = drawable->height % out_height;
errval = 0;
errlast = -1;
errline = 0;
for (y = 0; y < out_height; y ++)
{
#ifdef DEBUG
printf("escp2_print: y = %d, line = %d, val = %d, mod = %d, height = %d\n",
y, errline, errval, errmod, out_height);
#endif /* DEBUG */
if ((y & 255) == 0)
gimp_progress_update((double)y / (double)out_height);
if (errline != errlast)
{
errlast = errline;
gimp_pixel_rgn_get_row(&rgn, in, 0, errline, drawable->width);
};
(*colorfunc)(in, out, drawable->width, drawable->bpp, lut, cmap);
if (output_type == OUTPUT_GRAY)
{
dither_black(out, y, drawable->width, out_width, black);
escp2_write(prn, black, length, 0, ydpi, model, out_width, left);
}
else
{
dither_cmyk(out, y, drawable->width, out_width, cyan, magenta,
yellow, black);
escp2_write(prn, cyan, length, 2, ydpi, model, out_width, left);
escp2_write(prn, magenta, length, 1, ydpi, model, out_width, left);
escp2_write(prn, yellow, length, 4, ydpi, model, out_width, left);
if (black != NULL)
escp2_write(prn, black, length, 0, ydpi, model, out_width, left);
};
fwrite("\033(v\002\000\001\000", 7, 1, prn); /* Feed one line */
errval += errmod;
errline += errdiv;
if (errval >= out_height)
{
errval -= out_height;
errline ++;
};
};
};
/*
* Cleanup...
*/
g_free(in);
g_free(out);
if (black != NULL)
g_free(black);
if (cyan != NULL)
{
g_free(cyan);
g_free(magenta);
g_free(yellow);
};
putc('\014', prn); /* Eject page */
fputs("\033@", prn); /* ESC/P2 reset */
}
/*
* 'escp2_write()' - Send ESC/P2 graphics using TIFF packbits compression.
*/
void
escp2_write(FILE *prn, /* I - Print file or command */
unsigned char *line, /* I - Output bitmap data */
int length, /* I - Length of bitmap data */
int plane, /* I - True if this is the last plane */
int ydpi, /* I - Vertical resolution */
int model, /* I - Printer model */
int width, /* I - Printed width */
int offset) /* I - Offset from left side */
{
unsigned char comp_buf[1536], /* Compression buffer */
*comp_ptr, /* Current slot in buffer */
*start, /* Start of compressed data */
repeat; /* Repeating char */
int count, /* Count of compressed bytes */
tcount; /* Temporary count < 128 */
static int last_plane = 0; /* Last color plane printed */
/*
* Don't send blank lines...
*/
if (line[0] == 0 && memcmp(line, line + 1, length - 1) == 0)
return;
/*
* Compress using TIFF "packbits" run-length encoding...
*/
comp_ptr = comp_buf;
while (length > 0)
{
/*
* Get a run of non-repeated chars...
*/
start = line;
line += 2;
length -= 2;
while (length > 0 && (line[-2] != line[-1] || line[-1] != line[0]))
{
line ++;
length --;
};
line -= 2;
length += 2;
/*
* Output the non-repeated sequences (max 128 at a time).
*/
count = line - start;
while (count > 0)
{
tcount = count > 128 ? 128 : count;
comp_ptr[0] = tcount - 1;
memcpy(comp_ptr + 1, start, tcount);
comp_ptr += tcount + 1;
start += tcount;
count -= tcount;
};
if (length <= 0)
break;
/*
* Find the repeated sequences...
*/
start = line;
repeat = line[0];
line ++;
length --;
while (length > 0 && *line == repeat)
{
line ++;
length --;
};
/*
* Output the repeated sequences (max 128 at a time).
*/
count = line - start;
while (count > 0)
{
tcount = count > 128 ? 128 : count;
comp_ptr[0] = 1 - tcount;
comp_ptr[1] = repeat;
comp_ptr += 2;
count -= tcount;
};
};
/*
* Set the print head position.
*/
putc('\r', prn);
fprintf(prn, "\033\\%c%c", offset & 255, offset >> 8);
/*
* Set the color if necessary...
*/
if (last_plane != plane)
{
last_plane = plane;
fprintf(prn, "\033r%c", plane);
};
/*
* Send a line of raster graphics...
*/
switch (ydpi) /* Raster graphics header */
{
case 180 :
fwrite("\033.\001\024\024\001", 6, 1, prn);
break;
case 360 :
fwrite("\033.\001\012\012\001", 6, 1, prn);
break;
case 720 :
if (model == 3)
fwrite("\033.\001\050\005\001", 6, 1, prn);
else
fwrite("\033.\001\005\005\001", 6, 1, prn);
break;
};
putc(width & 255, prn); /* Width of raster line in pixels */
putc(width >> 8, prn);
fwrite(comp_buf, comp_ptr - comp_buf, 1, prn);
}
/*
* End of "$Id$".
*/