mirror of https://github.com/GNOME/gimp.git
507 lines
13 KiB
C
507 lines
13 KiB
C
/*
|
|
* "$Id$"
|
|
*
|
|
* Print plug-in Adobe PostScript 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*
|
|
* Contents:
|
|
*
|
|
* ps_print() - Print an image to a PostScript printer.
|
|
* ps_hex() - Print binary data as a series of hexadecimal numbers.
|
|
* ps_ascii85() - Print binary data as a series of base-85 numbers.
|
|
*
|
|
* Revision History:
|
|
*
|
|
* $Log$
|
|
* Revision 1.6 1998/04/13 05:43:14 yosh
|
|
* Have fun recompiling gimp everyone. It's the great FSF address change!
|
|
*
|
|
* -Yosh
|
|
*
|
|
* Revision 1.5 1998/04/07 03:41:14 yosh
|
|
* configure.in: fix for $srcdir != $builddir for data. Tightened check for
|
|
* random() and add -lucb on systems that need it. Fix for xdelta.h check. Find
|
|
* xemacs as well as emacs. Properly define settings for print plugin.
|
|
*
|
|
* app/Makefile.am: ditch -DNDEBUG, since nothing uses it
|
|
*
|
|
* flame: properly handle random() and friends
|
|
*
|
|
* pnm: workaround for systems with old sprintfs
|
|
*
|
|
* print, sgi: fold back in portability fixes
|
|
*
|
|
* threshold_alpha: properly get params in non-interactive mode
|
|
*
|
|
* bmp: updated and merged in
|
|
*
|
|
* -Yosh
|
|
*
|
|
* Revision 1.4 1998/04/01 22:14:46 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.10 1998/01/22 15:38:46 mike
|
|
* Updated copyright notice.
|
|
* Whoops - wasn't encoding correctly for portrait output to level 2 printers!
|
|
*
|
|
* Revision 1.9 1998/01/21 21:33:47 mike
|
|
* Added support for Level 2 filters; images are now sent in hex or
|
|
* base-85 ASCII as necessary (faster printing).
|
|
*
|
|
* Revision 1.8 1997/11/12 15:57:48 mike
|
|
* Minor changes for clean compiles under Digital UNIX.
|
|
*
|
|
* Revision 1.8 1997/11/12 15:57:48 mike
|
|
* Minor changes for clean compiles under Digital UNIX.
|
|
*
|
|
* Revision 1.7 1997/07/30 20:33:05 mike
|
|
* Final changes for 1.1 release.
|
|
*
|
|
* Revision 1.7 1997/07/30 20:33:05 mike
|
|
* Final changes for 1.1 release.
|
|
*
|
|
* Revision 1.6 1997/07/30 18:47:39 mike
|
|
* Added scaling, orientation, and offset options.
|
|
*
|
|
* Revision 1.5 1997/07/26 18:38:55 mike
|
|
* Bug - was using asctime instead of ctime... D'oh!
|
|
*
|
|
* Revision 1.4 1997/07/26 18:19:54 mike
|
|
* Fixed positioning/scaling bug.
|
|
*
|
|
* Revision 1.3 1997/07/03 13:26:46 mike
|
|
* Updated documentation for 1.0 release.
|
|
*
|
|
* Revision 1.2 1997/07/02 18:49:36 mike
|
|
* Forgot to free memory buffers...
|
|
*
|
|
* Revision 1.2 1997/07/02 18:49:36 mike
|
|
* Forgot to free memory buffers...
|
|
*
|
|
* Revision 1.1 1997/07/02 13:51:53 mike
|
|
* Initial revision
|
|
*/
|
|
|
|
#include "print.h"
|
|
#include <time.h>
|
|
|
|
|
|
/*
|
|
* Local functions...
|
|
*/
|
|
|
|
static void ps_hex(FILE *, guchar *, int);
|
|
static void ps_ascii85(FILE *, guchar *, int, int);
|
|
|
|
|
|
/*
|
|
* 'ps_print()' - Print an image to a PostScript printer.
|
|
*/
|
|
|
|
void
|
|
ps_print(FILE *prn, /* I - File to print to */
|
|
GDrawable *drawable, /* I - Image to print */
|
|
int media_size, /* I - Size of output */
|
|
int xdpi, /* I - Horizontal resolution (always 72) */
|
|
int ydpi, /* I - Vertical resolution (always 72) */
|
|
int output_type, /* I - Output type (color/grayscale) */
|
|
int model, /* I - Model (ignored) */
|
|
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 */
|
|
GPixelRgn rgn; /* Image region */
|
|
guchar *in, /* Input pixels from image */
|
|
*out; /* Output pixels for printer */
|
|
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 */
|
|
out_length, /* Output length (Level 2 output) */
|
|
out_offset, /* Output offset (Level 2 output) */
|
|
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 */
|
|
time_t curtime; /* Current time of day */
|
|
convert_t colorfunc; /* Color conversion function... */
|
|
static char *filters[2] = /* PostScript image filters... */
|
|
{
|
|
"{currentfile picture readhexstring pop}", /* Level 1 */
|
|
"currentfile /ASCII85Decode filter" /* Level 2 */
|
|
};
|
|
|
|
|
|
/*
|
|
* 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...");
|
|
|
|
/*
|
|
* Output a standard PostScript header with DSC comments...
|
|
*/
|
|
|
|
curtime = time(NULL);
|
|
|
|
fputs("%!PS-Adobe-3.0\n", prn);
|
|
fputs("%%Creator: " PLUG_IN_NAME " plug-in V" PLUG_IN_VERSION " for GIMP.\n", prn);
|
|
fprintf(prn, "%%%%CreationDate: %s", ctime(&curtime));
|
|
fputs("%%Copyright: 1997-1998 by Michael Sweet (mike@easysw.com)\n", prn);
|
|
fprintf(prn, "%%%%BoundingBox: %d %d %d %d\n",
|
|
(page_width - out_width) / 2 + 18, (page_height - out_height) / 2 + 36,
|
|
(page_width + out_width) / 2 + 18, (page_height + out_height) / 2 + 36);
|
|
fputs("%%DocumentData: Clean7Bit\n", prn);
|
|
fprintf(prn, "%%%%LanguageLevel: %d\n", model + 1);
|
|
fputs("%%Pages: 1\n", prn);
|
|
fputs("%%Orientation: Portrait\n", prn);
|
|
fputs("%%EndComments\n", prn);
|
|
|
|
/*
|
|
* Output the page, rotating as necessary...
|
|
*/
|
|
|
|
fputs("%%Page: 1\n", prn);
|
|
fputs("gsave\n", prn);
|
|
|
|
if (top < 0 || left < 0)
|
|
{
|
|
left = (page_width - out_width) / 2 + 18;
|
|
top = (page_height - out_height) / 2 + 36;
|
|
}
|
|
else
|
|
{
|
|
left = 72 * left / 10 + 18;
|
|
top = page_height - out_height - 72 * top / 10 + 36;
|
|
};
|
|
|
|
fprintf(prn, "%d %d translate\n", left, top);
|
|
fprintf(prn, "%d %d scale\n", out_width, out_height);
|
|
|
|
if (landscape)
|
|
{
|
|
in = g_malloc(drawable->height * drawable->bpp);
|
|
out = g_malloc(drawable->height * out_bpp + 3);
|
|
|
|
if (model == 0)
|
|
fprintf(prn, "/picture %d string def\n", drawable->height * out_bpp);
|
|
|
|
if (output_type == OUTPUT_GRAY)
|
|
fprintf(prn, "%d %d 8 [%d 0 0 %d 0 %d] %s image\n",
|
|
drawable->height, drawable->width,
|
|
drawable->height, drawable->width, 0,
|
|
filters[model]);
|
|
else
|
|
fprintf(prn, "%d %d 8 [%d 0 0 %d 0 %d] %s false 3 colorimage\n",
|
|
drawable->height, drawable->width,
|
|
drawable->height, drawable->width, 0,
|
|
filters[model]);
|
|
|
|
for (x = 0, out_offset = 0; x < drawable->width; x ++)
|
|
{
|
|
if ((x & 15) == 0)
|
|
gimp_progress_update((double)x / (double)drawable->width);
|
|
|
|
gimp_pixel_rgn_get_col(&rgn, in, x, 0, drawable->height);
|
|
(*colorfunc)(in, out + out_offset, drawable->height, drawable->bpp, lut, cmap);
|
|
|
|
if (model)
|
|
{
|
|
out_length = out_offset + drawable->height * out_bpp;
|
|
|
|
if (x < (drawable->width - 1))
|
|
{
|
|
ps_ascii85(prn, out, out_length & ~3, 0);
|
|
out_offset = out_length & 3;
|
|
}
|
|
else
|
|
{
|
|
ps_ascii85(prn, out, out_length, 1);
|
|
out_offset = 0;
|
|
};
|
|
|
|
if (out_offset > 0)
|
|
memcpy(out, out + out_length - out_offset, out_offset);
|
|
}
|
|
else
|
|
ps_hex(prn, out, drawable->height * out_bpp);
|
|
};
|
|
}
|
|
else
|
|
{
|
|
in = g_malloc(drawable->width * drawable->bpp);
|
|
out = g_malloc(drawable->width * out_bpp + 3);
|
|
|
|
if (model == 0)
|
|
fprintf(prn, "/picture %d string def\n", drawable->width * out_bpp);
|
|
|
|
if (output_type == OUTPUT_GRAY)
|
|
fprintf(prn, "%d %d 8 [%d 0 0 %d 0 %d] %s image\n",
|
|
drawable->width, drawable->height,
|
|
drawable->width, -drawable->height, drawable->height,
|
|
filters[model]);
|
|
else
|
|
fprintf(prn, "%d %d 8 [%d 0 0 %d 0 %d] %s false 3 colorimage\n",
|
|
drawable->width, drawable->height,
|
|
drawable->width, -drawable->height, drawable->height,
|
|
filters[model]);
|
|
|
|
for (y = 0, out_offset = 0; y < drawable->height; y ++)
|
|
{
|
|
if ((y & 15) == 0)
|
|
gimp_progress_update((double)y / (double)drawable->height);
|
|
|
|
gimp_pixel_rgn_get_row(&rgn, in, 0, y, drawable->width);
|
|
(*colorfunc)(in, out + out_offset, drawable->width, drawable->bpp, lut, cmap);
|
|
|
|
if (model)
|
|
{
|
|
out_length = out_offset + drawable->width * out_bpp;
|
|
|
|
if (y < (drawable->height - 1))
|
|
{
|
|
ps_ascii85(prn, out, out_length & ~3, 0);
|
|
out_offset = out_length & 3;
|
|
}
|
|
else
|
|
{
|
|
ps_ascii85(prn, out, out_length, 1);
|
|
out_offset = 0;
|
|
};
|
|
|
|
if (out_offset > 0)
|
|
memcpy(out, out + out_length - out_offset, out_offset);
|
|
}
|
|
else
|
|
ps_hex(prn, out, drawable->width * out_bpp);
|
|
};
|
|
};
|
|
|
|
g_free(in);
|
|
g_free(out);
|
|
|
|
fputs("grestore\n", prn);
|
|
fputs("showpage\n", prn);
|
|
fputs("%%EndPage\n", prn);
|
|
fputs("%%EOF\n", prn);
|
|
}
|
|
|
|
|
|
/*
|
|
* 'ps_hex()' - Print binary data as a series of hexadecimal numbers.
|
|
*/
|
|
|
|
static void
|
|
ps_hex(FILE *prn, /* I - File to print to */
|
|
guchar *data, /* I - Data to print */
|
|
int length) /* I - Number of bytes to print */
|
|
{
|
|
static char *hex = "0123456789ABCDEF";
|
|
|
|
|
|
while (length > 0)
|
|
{
|
|
/*
|
|
* Put the hex chars out to the file; note that we don't use fprintf()
|
|
* for speed reasons...
|
|
*/
|
|
|
|
putc(hex[*data >> 4], prn);
|
|
putc(hex[*data & 15], prn);
|
|
|
|
data ++;
|
|
length --;
|
|
};
|
|
|
|
putc('\n', prn);
|
|
}
|
|
|
|
|
|
/*
|
|
* 'ps_ascii85()' - Print binary data as a series of base-85 numbers.
|
|
*/
|
|
|
|
static void
|
|
ps_ascii85(FILE *prn, /* I - File to print to */
|
|
guchar *data, /* I - Data to print */
|
|
int length, /* I - Number of bytes to print */
|
|
int last_line) /* I - Last line of raster data? */
|
|
{
|
|
unsigned b; /* Binary data word */
|
|
unsigned char c[5]; /* ASCII85 encoded chars */
|
|
int col; /* Current column */
|
|
|
|
|
|
col = 0;
|
|
while (length > 3)
|
|
{
|
|
b = (((((data[0] << 8) | data[1]) << 8) | data[2]) << 8) | data[3];
|
|
|
|
if (b == 0)
|
|
putc('z', prn);
|
|
else
|
|
{
|
|
c[4] = (b % 85) + '!';
|
|
b /= 85;
|
|
c[3] = (b % 85) + '!';
|
|
b /= 85;
|
|
c[2] = (b % 85) + '!';
|
|
b /= 85;
|
|
c[1] = (b % 85) + '!';
|
|
b /= 85;
|
|
c[0] = b + '!';
|
|
|
|
fwrite(c, 5, 1, prn);
|
|
};
|
|
|
|
data += 4;
|
|
length -= 4;
|
|
|
|
col = (col + 1) & 15;
|
|
if (col == 0 && length > 0)
|
|
putc('\n', prn);
|
|
};
|
|
|
|
if (last_line)
|
|
{
|
|
if (length > 0)
|
|
{
|
|
for (b = 0, col = length; col > 0; b = (b << 8) | data[0], data ++, col --);
|
|
|
|
c[4] = (b % 85) + '!';
|
|
b /= 85;
|
|
c[3] = (b % 85) + '!';
|
|
b /= 85;
|
|
c[2] = (b % 85) + '!';
|
|
b /= 85;
|
|
c[1] = (b % 85) + '!';
|
|
b /= 85;
|
|
c[0] = b + '!';
|
|
|
|
fwrite(c, length + 1, 1, prn);
|
|
};
|
|
|
|
fputs("~>\n", prn);
|
|
}
|
|
else
|
|
putc('\n', prn);
|
|
}
|
|
|
|
|
|
/*
|
|
* End of "$Id$".
|
|
*/
|