summaryrefslogtreecommitdiff
path: root/src/main/print-util.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/print-util.c')
-rw-r--r--src/main/print-util.c1649
1 files changed, 1649 insertions, 0 deletions
diff --git a/src/main/print-util.c b/src/main/print-util.c
new file mode 100644
index 0000000..a5d005a
--- /dev/null
+++ b/src/main/print-util.c
@@ -0,0 +1,1649 @@
+/*
+ * "$Id: print-util.c,v 1.53 2001/11/10 00:12:20 rlk Exp $"
+ *
+ * Print plug-in driver utility functions for the GIMP.
+ *
+ * Copyright 1997-2000 Michael Sweet (mike@easysw.com) and
+ * Robert Krawitz (rlk@alum.mit.edu)
+ *
+ * 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.
+ */
+
+/*
+ * This file must include only standard C header files. The core code must
+ * compile on generic platforms that don't support glib, gimp, gtk, etc.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <gimp-print/gimp-print.h>
+#include "gimp-print-internal.h"
+#include <gimp-print/gimp-print-intl-internal.h>
+#include <math.h>
+#include <limits.h>
+#if defined(HAVE_VARARGS_H) && !defined(HAVE_STDARG_H)
+#include <varargs.h>
+#else
+#include <stdarg.h>
+#endif
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define FMIN(a, b) ((a) < (b) ? (a) : (b))
+
+typedef struct stp_internal_option
+{
+ char *name;
+ size_t length;
+ char *data;
+ struct stp_internal_option *next;
+ struct stp_internal_option *prev;
+} stp_internal_option_t;
+
+typedef struct /* Plug-in variables */
+{
+ const char *output_to, /* Name of file or command to print to */
+ *driver, /* Name of printer "driver" */
+ *ppd_file, /* PPD file */
+ *resolution, /* Resolution */
+ *media_size, /* Media size */
+ *media_type, /* Media type */
+ *media_source, /* Media source */
+ *ink_type, /* Ink or cartridge */
+ *dither_algorithm; /* Dithering algorithm */
+ int output_type; /* Color or grayscale output */
+ float brightness; /* Output brightness */
+ float scaling; /* Scaling, percent of printable area */
+ int orientation, /* Orientation - 0 = port., 1 = land.,
+ -1 = auto */
+ left, /* Offset from lower-lefthand corner, points */
+ top; /* ... */
+ float gamma; /* Gamma */
+ float contrast, /* Output Contrast */
+ cyan, /* Output red level */
+ magenta, /* Output green level */
+ yellow; /* Output blue level */
+ float saturation; /* Output saturation */
+ float density; /* Maximum output density */
+ int image_type; /* Image type (line art etc.) */
+ int unit; /* Units for preview area 0=Inch 1=Metric */
+ float app_gamma; /* Application gamma */
+ int page_width; /* Width of page in points */
+ int page_height; /* Height of page in points */
+ int input_color_model; /* Color model for this device */
+ int output_color_model; /* Color model for this device */
+ void *lut; /* Look-up table */
+ void *driver_data; /* Private data of the driver */
+ unsigned char *cmap; /* Color map */
+ void (*outfunc)(void *data, const char *buffer, size_t bytes);
+ void *outdata;
+ void (*errfunc)(void *data, const char *buffer, size_t bytes);
+ void *errdata;
+ stp_internal_option_t *options;
+ int verified; /* Ensure that params are OK! */
+} stp_internal_vars_t;
+
+typedef struct stp_internal_printer
+{
+ const char *long_name, /* Long name for UI */
+ *driver; /* Short name for printrc file */
+ int model; /* Model number */
+ const stp_printfuncs_t *printfuncs;
+ stp_internal_vars_t printvars;
+} stp_internal_printer_t;
+
+typedef struct
+{
+ const char *name;
+ const char *text;
+ unsigned width;
+ unsigned height;
+ unsigned top;
+ unsigned left;
+ unsigned bottom;
+ unsigned right;
+ stp_papersize_unit_t paper_unit;
+} stp_internal_papersize_t;
+
+static const stp_internal_vars_t default_vars =
+{
+ "", /* Name of file or command to print to */
+ N_ ("ps2"), /* Name of printer "driver" */
+ "", /* Name of PPD file */
+ "", /* Output resolution */
+ "", /* Size of output media */
+ "", /* Type of output media */
+ "", /* Source of output media */
+ "", /* Ink type */
+ "", /* Dither algorithm */
+ OUTPUT_COLOR, /* Color or grayscale output */
+ 1.0, /* Output brightness */
+ 100.0, /* Scaling (100% means entire printable area, */
+ /* -XXX means scale by PPI) */
+ -1, /* Orientation (-1 = automatic) */
+ -1, /* X offset (-1 = center) */
+ -1, /* Y offset (-1 = center) */
+ 1.0, /* Screen gamma */
+ 1.0, /* Contrast */
+ 1.0, /* Cyan */
+ 1.0, /* Magenta */
+ 1.0, /* Yellow */
+ 1.0, /* Output saturation */
+ 1.0, /* Density */
+ IMAGE_CONTINUOUS, /* Image type */
+ 0, /* Unit 0=Inch */
+ 1.0, /* Application gamma placeholder */
+ 0, /* Page width */
+ 0, /* Page height */
+ COLOR_MODEL_RGB, /* Input color model */
+ COLOR_MODEL_RGB /* Output color model */
+};
+
+static const stp_internal_vars_t min_vars =
+{
+ "", /* Name of file or command to print to */
+ N_ ("ps2"), /* Name of printer "driver" */
+ "", /* Name of PPD file */
+ "", /* Output resolution */
+ "", /* Size of output media */
+ "", /* Type of output media */
+ "", /* Source of output media */
+ "", /* Ink type */
+ "", /* Dither algorithm */
+ 0, /* Color or grayscale output */
+ 0, /* Output brightness */
+ 5.0, /* Scaling (100% means entire printable area, */
+ /* -XXX means scale by PPI) */
+ -1, /* Orientation (-1 = automatic) */
+ -1, /* X offset (-1 = center) */
+ -1, /* Y offset (-1 = center) */
+ 0.1, /* Screen gamma */
+ 0, /* Contrast */
+ 0, /* Cyan */
+ 0, /* Magenta */
+ 0, /* Yellow */
+ 0, /* Output saturation */
+ .1, /* Density */
+ 0, /* Image type */
+ 0, /* Unit 0=Inch */
+ 1.0, /* Application gamma placeholder */
+ 0, /* Page width */
+ 0, /* Page height */
+ 0, /* Input color model */
+ 0 /* Output color model */
+};
+
+static const stp_internal_vars_t max_vars =
+{
+ "", /* Name of file or command to print to */
+ N_ ("ps2"), /* Name of printer "driver" */
+ "", /* Name of PPD file */
+ "", /* Output resolution */
+ "", /* Size of output media */
+ "", /* Type of output media */
+ "", /* Source of output media */
+ "", /* Ink type */
+ "", /* Dither algorithm */
+ OUTPUT_RAW_CMYK, /* Color or grayscale output */
+ 2.0, /* Output brightness */
+ 100.0, /* Scaling (100% means entire printable area, */
+ /* -XXX means scale by PPI) */
+ -1, /* Orientation (-1 = automatic) */
+ -1, /* X offset (-1 = center) */
+ -1, /* Y offset (-1 = center) */
+ 4.0, /* Screen gamma */
+ 4.0, /* Contrast */
+ 4.0, /* Cyan */
+ 4.0, /* Magenta */
+ 4.0, /* Yellow */
+ 9.0, /* Output saturation */
+ 2.0, /* Density */
+ NIMAGE_TYPES - 1, /* Image type */
+ 1, /* Unit 0=Inch */
+ 1.0, /* Application gamma placeholder */
+ 0, /* Page width */
+ 0, /* Page height */
+ NCOLOR_MODELS - 1, /* Input color model */
+ NCOLOR_MODELS - 1 /* Output color model */
+};
+
+stp_vars_t
+stp_allocate_vars(void)
+{
+ void *retval = stp_malloc(sizeof(stp_internal_vars_t));
+ memset(retval, 0, sizeof(stp_internal_vars_t));
+ stp_copy_vars(retval, (stp_vars_t)&default_vars);
+ return (retval);
+}
+
+#define SAFE_FREE(x) \
+do \
+{ \
+ if ((x)) \
+ stp_free((char *)(x)); \
+ ((x)) = NULL; \
+} while (0)
+
+static char *
+c_strdup(const char *s)
+{
+ char *ret;
+ if (!s)
+ {
+ ret = stp_malloc(1);
+ ret[0] = 0;
+ return ret;
+ }
+ else
+ {
+ ret = stp_malloc(strlen(s) + 1);
+ strcpy(ret, s);
+ return ret;
+ }
+}
+
+static char *
+c_strndup(const char *s, int n)
+{
+ char *ret;
+ if (!s || n < 0)
+ {
+ ret = stp_malloc(1);
+ ret[0] = 0;
+ return ret;
+ }
+ else
+ {
+ ret = stp_malloc(n + 1);
+ strncpy(ret, s, n);
+ ret[n] = 0;
+ return ret;
+ }
+}
+
+void
+stp_free_vars(stp_vars_t vv)
+{
+ stp_internal_vars_t *v = (stp_internal_vars_t *) vv;
+ SAFE_FREE(v->output_to);
+ SAFE_FREE(v->driver);
+ SAFE_FREE(v->ppd_file);
+ SAFE_FREE(v->resolution);
+ SAFE_FREE(v->media_size);
+ SAFE_FREE(v->media_type);
+ SAFE_FREE(v->media_source);
+ SAFE_FREE(v->ink_type);
+ SAFE_FREE(v->dither_algorithm);
+}
+
+#define DEF_STRING_FUNCS(s) \
+void \
+stp_set_##s(stp_vars_t vv, const char *val) \
+{ \
+ stp_internal_vars_t *v = (stp_internal_vars_t *) vv; \
+ if (v->s == val) \
+ return; \
+ SAFE_FREE(v->s); \
+ v->s = c_strdup(val); \
+ v->verified = 0; \
+} \
+ \
+void \
+stp_set_##s##_n(stp_vars_t vv, const char *val, int n) \
+{ \
+ stp_internal_vars_t *v = (stp_internal_vars_t *) vv; \
+ if (v->s == val) \
+ return; \
+ SAFE_FREE(v->s); \
+ v->s = c_strndup(val, n); \
+ v->verified = 0; \
+} \
+ \
+const char * \
+stp_get_##s(const stp_vars_t vv) \
+{ \
+ stp_internal_vars_t *v = (stp_internal_vars_t *) vv; \
+ return v->s; \
+}
+
+#define DEF_FUNCS(s, t) \
+void \
+stp_set_##s(stp_vars_t vv, t val) \
+{ \
+ stp_internal_vars_t *v = (stp_internal_vars_t *) vv; \
+ v->verified = 0; \
+ v->s = val; \
+} \
+ \
+t \
+stp_get_##s(const stp_vars_t vv) \
+{ \
+ stp_internal_vars_t *v = (stp_internal_vars_t *) vv; \
+ return v->s; \
+}
+
+DEF_STRING_FUNCS(output_to)
+DEF_STRING_FUNCS(driver)
+DEF_STRING_FUNCS(ppd_file)
+DEF_STRING_FUNCS(resolution)
+DEF_STRING_FUNCS(media_size)
+DEF_STRING_FUNCS(media_type)
+DEF_STRING_FUNCS(media_source)
+DEF_STRING_FUNCS(ink_type)
+DEF_STRING_FUNCS(dither_algorithm)
+DEF_FUNCS(output_type, int)
+DEF_FUNCS(orientation, int)
+DEF_FUNCS(left, int)
+DEF_FUNCS(top, int)
+DEF_FUNCS(image_type, int)
+DEF_FUNCS(unit, int)
+DEF_FUNCS(page_width, int)
+DEF_FUNCS(page_height, int)
+DEF_FUNCS(input_color_model, int)
+DEF_FUNCS(output_color_model, int)
+DEF_FUNCS(brightness, float)
+DEF_FUNCS(scaling, float)
+DEF_FUNCS(gamma, float)
+DEF_FUNCS(contrast, float)
+DEF_FUNCS(cyan, float)
+DEF_FUNCS(magenta, float)
+DEF_FUNCS(yellow, float)
+DEF_FUNCS(saturation, float)
+DEF_FUNCS(density, float)
+DEF_FUNCS(app_gamma, float)
+DEF_FUNCS(lut, void *)
+DEF_FUNCS(outdata, void *)
+DEF_FUNCS(errdata, void *)
+DEF_FUNCS(driver_data, void *)
+DEF_FUNCS(cmap, unsigned char *)
+DEF_FUNCS(outfunc, stp_outfunc_t)
+DEF_FUNCS(errfunc, stp_outfunc_t)
+
+void
+stp_set_verified(stp_vars_t vv, int val)
+{
+ stp_internal_vars_t *v = (stp_internal_vars_t *) vv;
+ v->verified = val;
+}
+
+int
+stp_get_verified(const stp_vars_t vv)
+{
+ stp_internal_vars_t *v = (stp_internal_vars_t *) vv;
+ return v->verified;
+}
+
+void
+stp_copy_options(stp_vars_t vd, const stp_vars_t vs)
+{
+ const stp_internal_vars_t *src = (const stp_internal_vars_t *)vs;
+ stp_internal_vars_t *dest = (stp_internal_vars_t *)vd;
+ stp_internal_option_t *opt = (stp_internal_option_t *) src->options;
+ stp_internal_option_t *popt = NULL;
+ if (opt)
+ {
+ stp_internal_option_t *nopt = stp_malloc(sizeof(stp_internal_option_t));
+ stp_set_verified(vd, 0);
+ dest->options = nopt;
+ memcpy(nopt, opt, sizeof(stp_internal_option_t));
+ nopt->name = stp_malloc(strlen(opt->name) + 1);
+ strcpy(nopt->name, opt->name);
+ nopt->data = stp_malloc(opt->length);
+ memcpy(nopt->data, opt->data, opt->length);
+ opt = opt->next;
+ popt = nopt;
+ while (opt)
+ {
+ nopt = stp_malloc(sizeof(stp_internal_option_t));
+ memcpy(nopt, opt, sizeof(stp_internal_option_t));
+ nopt->prev = popt;
+ popt->next = nopt;
+ nopt->name = stp_malloc(strlen(opt->name) + 1);
+ strcpy(nopt->name, opt->name);
+ nopt->data = stp_malloc(opt->length);
+ memcpy(nopt->data, opt->data, opt->length);
+ opt = opt->next;
+ popt = nopt;
+ }
+ }
+}
+
+void
+stp_copy_vars(stp_vars_t vd, const stp_vars_t vs)
+{
+ if (vs == vd)
+ return;
+ stp_set_output_to(vd, stp_get_output_to(vs));
+ stp_set_driver(vd, stp_get_driver(vs));
+ stp_set_driver_data(vd, stp_get_driver_data(vs));
+ stp_set_ppd_file(vd, stp_get_ppd_file(vs));
+ stp_set_resolution(vd, stp_get_resolution(vs));
+ stp_set_media_size(vd, stp_get_media_size(vs));
+ stp_set_media_type(vd, stp_get_media_type(vs));
+ stp_set_media_source(vd, stp_get_media_source(vs));
+ stp_set_ink_type(vd, stp_get_ink_type(vs));
+ stp_set_dither_algorithm(vd, stp_get_dither_algorithm(vs));
+ stp_set_output_type(vd, stp_get_output_type(vs));
+ stp_set_orientation(vd, stp_get_orientation(vs));
+ stp_set_left(vd, stp_get_left(vs));
+ stp_set_top(vd, stp_get_top(vs));
+ stp_set_image_type(vd, stp_get_image_type(vs));
+ stp_set_unit(vd, stp_get_unit(vs));
+ stp_set_page_width(vd, stp_get_page_width(vs));
+ stp_set_page_height(vd, stp_get_page_height(vs));
+ stp_set_brightness(vd, stp_get_brightness(vs));
+ stp_set_scaling(vd, stp_get_scaling(vs));
+ stp_set_gamma(vd, stp_get_gamma(vs));
+ stp_set_contrast(vd, stp_get_contrast(vs));
+ stp_set_cyan(vd, stp_get_cyan(vs));
+ stp_set_magenta(vd, stp_get_magenta(vs));
+ stp_set_yellow(vd, stp_get_yellow(vs));
+ stp_set_saturation(vd, stp_get_saturation(vs));
+ stp_set_density(vd, stp_get_density(vs));
+ stp_set_app_gamma(vd, stp_get_app_gamma(vs));
+ stp_set_input_color_model(vd, stp_get_input_color_model(vd));
+ stp_set_output_color_model(vd, stp_get_output_color_model(vd));
+ stp_set_lut(vd, stp_get_lut(vs));
+ stp_set_outdata(vd, stp_get_outdata(vs));
+ stp_set_errdata(vd, stp_get_errdata(vs));
+ stp_set_cmap(vd, stp_get_cmap(vs));
+ stp_set_outfunc(vd, stp_get_outfunc(vs));
+ stp_set_errfunc(vd, stp_get_errfunc(vs));
+ stp_copy_options(vd, vs);
+ stp_set_verified(vd, stp_get_verified(vs));
+}
+
+stp_vars_t
+stp_allocate_copy(const stp_vars_t vs)
+{
+ stp_vars_t vd = stp_allocate_vars();
+ stp_copy_vars(vd, vs);
+ return (vd);
+}
+
+#define ICLAMP(value) \
+do \
+{ \
+ if (stp_get_##value(user) < stp_get_##value(min)) \
+ stp_set_##value(user, stp_get_##value(min)); \
+ else if (stp_get_##value(user) > stp_get_##value(max)) \
+ stp_set_##value(user, stp_get_##value(max)); \
+} while (0)
+
+void
+stp_merge_printvars(stp_vars_t user, const stp_vars_t print)
+{
+ const stp_vars_t max = stp_maximum_settings();
+ const stp_vars_t min = stp_minimum_settings();
+ stp_set_cyan(user, stp_get_cyan(user) * stp_get_cyan(print));
+ ICLAMP(cyan);
+ stp_set_magenta(user, stp_get_magenta(user) * stp_get_magenta(print));
+ ICLAMP(magenta);
+ stp_set_yellow(user, stp_get_yellow(user) * stp_get_yellow(print));
+ ICLAMP(yellow);
+ stp_set_contrast(user, stp_get_contrast(user) * stp_get_contrast(print));
+ ICLAMP(contrast);
+ stp_set_brightness(user, stp_get_brightness(user)*stp_get_brightness(print));
+ ICLAMP(brightness);
+ stp_set_gamma(user, stp_get_gamma(user) / stp_get_gamma(print));
+ ICLAMP(gamma);
+ stp_set_saturation(user, stp_get_saturation(user)*stp_get_saturation(print));
+ ICLAMP(saturation);
+ stp_set_density(user, stp_get_density(user) * stp_get_density(print));
+ ICLAMP(density);
+ if (stp_get_output_type(print) == OUTPUT_GRAY &&
+ stp_get_output_type(user) == OUTPUT_COLOR)
+ stp_set_output_type(user, OUTPUT_GRAY);
+}
+
+/*
+ * 'stp_default_media_size()' - Return the size of a default page size.
+ */
+
+/*
+ * Sizes are converted to 1/72in, then rounded down so that we don't
+ * print off the edge of the paper.
+ */
+static stp_internal_papersize_t paper_sizes[] =
+{
+ /* Common imperial page sizes */
+ { "Letter", N_ ("Letter"),
+ 612, 792, 0, 0, 0, 0, PAPERSIZE_ENGLISH }, /* 8.5in x 11in */
+ { "Legal", N_ ("Legal"),
+ 612, 1008, 0, 0, 0, 0, PAPERSIZE_ENGLISH }, /* 8.5in x 14in */
+ { "Tabloid", N_ ("Tabloid"),
+ 792, 1224, 0, 0, 0, 0, PAPERSIZE_ENGLISH }, /* 11in x 17in */
+ { "Executive", N_ ("Executive"),
+ 522, 756, 0, 0, 0, 0, PAPERSIZE_ENGLISH }, /* 7.25 * 10.5in */
+ { "Postcard", N_ ("Postcard"),
+ 283, 416, 0, 0, 0, 0, PAPERSIZE_ENGLISH }, /* 100mm x 147mm */
+ { "w216h360", N_ ("3x5"),
+ 216, 360, 0, 0, 0, 0, PAPERSIZE_ENGLISH },
+ { "w288h432", N_ ("4x6"),
+ 288, 432, 0, 0, 0, 0, PAPERSIZE_ENGLISH },
+ { "w324h495", N_ ("Epson 4x6 Photo Paper"),
+ 324, 495, 0, 0, 0, 0, PAPERSIZE_ENGLISH },
+ { "w360h504", N_ ("5x7"),
+ 360, 504, 0, 0, 0, 0, PAPERSIZE_ENGLISH },
+ { "w360h576", N_ ("5x8"),
+ 360, 576, 0, 0, 0, 0, PAPERSIZE_ENGLISH },
+ { "w432h576", N_ ("6x8"),
+ 432, 576, 0, 0, 0, 0, PAPERSIZE_ENGLISH },
+ { "8x10", N_ ("8x10"),
+ 576, 720, 0, 0, 0, 0, PAPERSIZE_ENGLISH },
+ { "Statement", N_ ("Manual"),
+ 396, 612, 0, 0, 0, 0, PAPERSIZE_ENGLISH }, /* 5.5in x 8.5in */
+ { "TabloidExtra", N_ ("12x18"),
+ 864, 1296, 0, 0, 0, 0, PAPERSIZE_ENGLISH },
+ { "SuperB", N_ ("Super B 13x19"),
+ 936, 1368, 0, 0, 0, 0, PAPERSIZE_ENGLISH },
+
+ /* Other common photographic paper sizes */
+ { "w576h864", N_ ("8x12"),
+ 576, 864, 0, 0, 0, 0, PAPERSIZE_ENGLISH }, /* Sometimes used for 35 mm */
+ { "w792h1008", N_ ("11x14"),
+ 792, 1008, 0, 0, 0, 0, PAPERSIZE_ENGLISH },
+ { "w1152h1440", N_ ("16x20"),
+ 1152, 1440, 0, 0, 0, 0, PAPERSIZE_ENGLISH },
+ { "w1152h1728", N_ ("16x24"),
+ 1152, 1728, 0, 0, 0, 0, PAPERSIZE_ENGLISH }, /* 20x24 for 35 mm */
+ { "w1440h1728", N_ ("20x24"),
+ 1440, 1728, 0, 0, 0, 0, PAPERSIZE_ENGLISH },
+ { "w1440h2160", N_ ("20x30"),
+ 1440, 2160, 0, 0, 0, 0, PAPERSIZE_ENGLISH }, /* 24x30 for 35 mm */
+ { "w1728h2160", N_ ("24x30"),
+ 1728, 2160, 0, 0, 0, 0, PAPERSIZE_ENGLISH },
+ { "w1728h2592", N_ ("24x36"),
+ 1728, 2592, 0, 0, 0, 0, PAPERSIZE_ENGLISH }, /* Sometimes used for 35 mm */
+ { "w2160h2880", N_ ("30x40"),
+ 2160, 2880, 0, 0, 0, 0, PAPERSIZE_ENGLISH },
+
+ /* International Paper Sizes (mostly taken from BS4000:1968) */
+
+ /*
+ * "A" series: Paper and boards, trimmed sizes
+ *
+ * "A" sizes are in the ratio 1 : sqrt(2). A0 has a total area
+ * of 1 square metre. Everything is rounded to the nearest
+ * millimetre. Thus, A0 is 841mm x 1189mm. Every other A
+ * size is obtained by doubling or halving another A size.
+ */
+ { "w4768h6749", N_ ("4A"),
+ 4768, 6749, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 1682mm x 2378mm */
+ { "w3370h4768", N_ ("2A"),
+ 3370, 4768, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 1189mm x 1682mm */
+ { "A0", N_ ("A0"),
+ 2384, 3370, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 841mm x 1189mm */
+ { "A1", N_ ("A1"),
+ 1684, 2384, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 594mm x 841mm */
+ { "A2", N_ ("A2"),
+ 1191, 1684, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 420mm x 594mm */
+ { "A3", N_ ("A3"),
+ 842, 1191, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 297mm x 420mm */
+ { "A4", N_ ("A4"),
+ 595, 842, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 210mm x 297mm */
+ { "A5", N_ ("A5"),
+ 420, 595, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 148mm x 210mm */
+ { "A6", N_ ("A6"),
+ 297, 420, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 105mm x 148mm */
+ { "A7", N_ ("A7"),
+ 210, 297, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 74mm x 105mm */
+ { "A8", N_ ("A8"),
+ 148, 210, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 52mm x 74mm */
+ { "A9", N_ ("A9"),
+ 105, 148, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 37mm x 52mm */
+ { "A10", N_ ("A10"),
+ 73, 105, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 26mm x 37mm */
+
+ /*
+ * Stock sizes for normal trims.
+ * Allowance for trim is 3 millimetres.
+ */
+ { "w2437h3458", N_ ("RA0"),
+ 2437, 3458, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 860mm x 1220mm */
+ { "w1729h2437", N_ ("RA1"),
+ 1729, 2437, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 610mm x 860mm */
+ { "w1218h1729", N_ ("RA2"),
+ 1218, 1729, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 430mm x 610mm */
+ { "w864h1218", N_ ("RA3"),
+ 864, 1218, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 305mm x 430mm */
+ { "w609h864", N_ ("RA4"),
+ 609, 864, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 215mm x 305mm */
+
+ /*
+ * Stock sizes for bled work or extra trims.
+ */
+ { "w2551h3628", N_ ("SRA0"),
+ 2551, 3628, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 900mm x 1280mm */
+ { "w1814h2551", N_ ("SRA1"),
+ 1814, 2551, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 640mm x 900mm */
+ { "w1275h1814", N_ ("SRA2"),
+ 1275, 1814, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 450mm x 640mm */
+ { "w907h1275", N_ ("SRA3"),
+ 907, 1275, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 320mm x 450mm */
+ { "w637h907", N_ ("SRA4"),
+ 637, 907, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 225mm x 320mm */
+
+ /*
+ * "B" series: Posters, wall charts and similar items.
+ */
+ { "w5669h8016", N_ ("4B ISO"),
+ 5669, 8016, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 2000mm x 2828mm */
+ { "w4008h5669", N_ ("2B ISO"),
+ 4008, 5669, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 1414mm x 2000mm */
+ { "ISOB0", N_ ("B0 ISO"),
+ 2834, 4008, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 1000mm x 1414mm */
+ { "ISOB1", N_ ("B1 ISO"),
+ 2004, 2834, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 707mm x 1000mm */
+ { "ISOB2", N_ ("B2 ISO"),
+ 1417, 2004, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 500mm x 707mm */
+ { "ISOB3", N_ ("B3 ISO"),
+ 1000, 1417, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 353mm x 500mm */
+ { "ISOB4", N_ ("B4 ISO"),
+ 708, 1000, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 250mm x 353mm */
+ { "ISOB5", N_ ("B5 ISO"),
+ 498, 708, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 176mm x 250mm */
+ { "ISOB6", N_ ("B6 ISO"),
+ 354, 498, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 125mm x 176mm */
+ { "ISOB7", N_ ("B7 ISO"),
+ 249, 354, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 88mm x 125mm */
+ { "ISOB8", N_ ("B8 ISO"),
+ 175, 249, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 62mm x 88mm */
+ { "ISOB9", N_ ("B9 ISO"),
+ 124, 175, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 44mm x 62mm */
+ { "ISOB10", N_ ("B10 ISO"),
+ 87, 124, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 31mm x 44mm */
+
+ { "B0", N_ ("B0 JIS"),
+ 2919, 4127, 0, 0, 0, 0, PAPERSIZE_METRIC },
+ { "B1", N_ ("B1 JIS"),
+ 2063, 2919, 0, 0, 0, 0, PAPERSIZE_METRIC },
+ { "B2", N_ ("B2 JIS"),
+ 1459, 2063, 0, 0, 0, 0, PAPERSIZE_METRIC },
+ { "B3", N_ ("B3 JIS"),
+ 1029, 1459, 0, 0, 0, 0, PAPERSIZE_METRIC },
+ { "B4", N_ ("B4 JIS"),
+ 727, 1029, 0, 0, 0, 0, PAPERSIZE_METRIC },
+ { "B5", N_ ("B5 JIS"),
+ 518, 727, 0, 0, 0, 0, PAPERSIZE_METRIC },
+ { "B6", N_ ("B6 JIS"),
+ 362, 518, 0, 0, 0, 0, PAPERSIZE_METRIC },
+ { "B7", N_ ("B7 JIS"),
+ 257, 362, 0, 0, 0, 0, PAPERSIZE_METRIC },
+ { "B8", N_ ("B8 JIS"),
+ 180, 257, 0, 0, 0, 0, PAPERSIZE_METRIC },
+ { "B9", N_ ("B9 JIS"),
+ 127, 180, 0, 0, 0, 0, PAPERSIZE_METRIC },
+ { "B10", N_ ("B10 JIS"),
+ 90, 127, 0, 0, 0, 0, PAPERSIZE_METRIC },
+
+ /*
+ * "C" series: Envelopes or folders suitable for A size stationery.
+ */
+ { "C0", N_ ("C0"),
+ 2599, 3676, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 917mm x 1297mm */
+ { "C1", N_ ("C1"),
+ 1836, 2599, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 648mm x 917mm */
+ { "C2", N_ ("C2"),
+ 1298, 1836, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 458mm x 648mm */
+ { "C3", N_ ("C3"),
+ 918, 1298, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 324mm x 458mm */
+ { "C4", N_ ("C4"),
+ 649, 918, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 229mm x 324mm */
+ { "C5", N_ ("C5"),
+ 459, 649, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 162mm x 229mm */
+ { "w354h918", N_ ("B6-C4"),
+ 354, 918, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 125mm x 324mm */
+ { "C6", N_ ("C6"),
+ 323, 459, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 114mm x 162mm */
+ { "DL", N_ ("DL"),
+ 311, 623, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 110mm x 220mm */
+ { "w229h459", N_ ("C7-6"),
+ 229, 459, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 81mm x 162mm */
+ { "C7", N_ ("C7"),
+ 229, 323, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 81mm x 114mm */
+ { "C8", N_ ("C8"),
+ 161, 229, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 57mm x 81mm */
+ { "C9", N_ ("C9"),
+ 113, 161, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 40mm x 57mm */
+ { "C10", N_ ("C10"),
+ 79, 113, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 28mm x 40mm */
+
+ /*
+ * US CAD standard paper sizes
+ */
+ { "ARCHA", N_ ("ArchA"),
+ 648, 864, 0, 0, 0, 0, PAPERSIZE_ENGLISH },
+ { "ARCHB", N_ ("ArchB"),
+ 864, 1296, 0, 0, 0, 0, PAPERSIZE_ENGLISH },
+ { "ARCHC", N_ ("ArchC"),
+ 1296, 1728, 0, 0, 0, 0, PAPERSIZE_ENGLISH },
+ { "ARCHD", N_ ("ArchD"),
+ 1728, 2592, 0, 0, 0, 0, PAPERSIZE_ENGLISH },
+ { "ARCHE", N_ ("ArchE"),
+ 2592, 3456, 0, 0, 0, 0, PAPERSIZE_ENGLISH },
+
+ /*
+ * Foolscap
+ */
+ { "w612h936", N_ ("American foolscap"),
+ 612, 936, 0, 0, 0, 0, PAPERSIZE_ENGLISH }, /* American foolscap */
+ { "w648h936", N_ ("European foolscap"),
+ 648, 936, 0, 0, 0, 0, PAPERSIZE_ENGLISH }, /* European foolscap */
+
+ /*
+ * Sizes for book production
+ * The BPIF and the Publishers Association jointly recommend ten
+ * standard metric sizes for case-bound titles as follows:
+ */
+ { "w535h697", N_ ("Crown Quarto"),
+ 535, 697, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 189mm x 246mm */
+ { "w569h731", N_ ("Large Crown Quarto"),
+ 569, 731, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 201mm x 258mm */
+ { "w620h782", N_ ("Demy Quarto"),
+ 620, 782, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 219mm x 276mm */
+ { "w671h884", N_ ("Royal Quarto"),
+ 671, 884, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 237mm x 312mm */
+ /*{ "ISO A4", 595,
+ 841, PAPERSIZE_METRIC, 0, 0, 0, 0 }, 210mm x 297mm */
+ { "w348h527", N_ ("Crown Octavo"),
+ 348, 527, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 123mm x 186mm */
+ { "w365h561", N_ ("Large Crown Octavo"),
+ 365, 561, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 129mm x 198mm */
+ { "w391h612", N_ ("Demy Octavo"),
+ 391, 612, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 138mm x 216mm */
+ { "w442h663", N_ ("Royal Octavo"),
+ 442, 663, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 156mm x 234mm */
+ /*{ N_ ("ISO A5"), 419,
+ 595, 0, 0, 0, 0, PAPERSIZE_METRIC }, 148mm x 210mm */
+
+ /* Paperback sizes in common usage */
+ { "w314h504", N_ ("Small paperback"),
+ 314, 504, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 111mm x 178mm */
+ { "w314h513", N_ ("Penguin small paperback"),
+ 314, 513, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 111mm x 181mm */
+ { "w365h561", N_ ("Penguin large paperback"),
+ 365, 561, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 129mm x 198mm */
+
+ /* Miscellaneous sizes */
+ { "w283h420", N_ ("Hagaki Card"),
+ 283, 420, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 100 x 148 mm */
+ { "w420h567", N_ ("Oufuku Card"),
+ 420, 567, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* 148 x 200 mm */
+ { "w340h666", N_ ("Japanese long envelope #3"),
+ 340, 666, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* Japanese long envelope #3 */
+ { "w255h581", N_ ("Japanese long envelope #4"),
+ 255, 581, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* Japanese long envelope #4 */
+ { "w680h941", N_ ("Japanese Kaku envelope #4"),
+ 680, 941, 0, 0, 0, 0, PAPERSIZE_METRIC }, /* Japanese Kaku envelope #4 */
+ { "COM10", N_ ("Commercial 10"),
+ 297, 684, 0, 0, 0, 0, PAPERSIZE_ENGLISH }, /* US Commercial 10 env */
+ { "w315h414", N_ ("A2 Invitation"),
+ 315, 414, 0, 0, 0, 0, PAPERSIZE_ENGLISH }, /* US A2 invitation */
+ { "Custom", N_ ("Custom"),
+ 0, 0, 0, 0, 0, 0, PAPERSIZE_ENGLISH },
+
+ { "w252", N_ ("89 mm Roll Paper"),
+ 252, 0, 0, 0, 0, 0, PAPERSIZE_METRIC },
+ { "w288", N_ ("4 Inch Roll Paper"),
+ 288, 0, 0, 0, 0, 0, PAPERSIZE_ENGLISH },
+ { "w360", N_ ("5 Inch Roll Paper"),
+ 360, 0, 0, 0, 0, 0, PAPERSIZE_ENGLISH },
+ { "w595", N_ ("210 mm Roll Paper"),
+ 595, 0, 0, 0, 0, 0, PAPERSIZE_METRIC },
+ { "w936", N_ ("13 Inch Roll Paper"),
+ 936, 0, 0, 0, 0, 0, PAPERSIZE_ENGLISH },
+ { "w1584", N_ ("22 Inch Roll Paper"),
+ 1584, 0, 0, 0, 0, 0, PAPERSIZE_ENGLISH },
+ { "w1728", N_ ("24 Inch Roll Paper"),
+ 1728, 0, 0, 0, 0, 0, PAPERSIZE_ENGLISH },
+ { "w2592", N_ ("36 Inch Roll Paper"),
+ 2592, 0, 0, 0, 0, 0, PAPERSIZE_ENGLISH },
+ { "w3168", N_ ("44 Inch Roll Paper"),
+ 3168, 0, 0, 0, 0, 0, PAPERSIZE_ENGLISH },
+
+ { "", "", 0, 0, 0, 0, 0, PAPERSIZE_METRIC }
+};
+
+int
+stp_known_papersizes(void)
+{
+ return sizeof(paper_sizes) / sizeof(stp_internal_papersize_t) - 1;
+}
+
+const char *
+stp_papersize_get_name(const stp_papersize_t pt)
+{
+ const stp_internal_papersize_t *p = (const stp_internal_papersize_t *) pt;
+ return p->name;
+}
+
+const char *
+stp_papersize_get_text(const stp_papersize_t pt)
+{
+ const stp_internal_papersize_t *p = (const stp_internal_papersize_t *) pt;
+ return _(p->text);
+}
+
+unsigned
+stp_papersize_get_width(const stp_papersize_t pt)
+{
+ const stp_internal_papersize_t *p = (const stp_internal_papersize_t *) pt;
+ return p->width;
+}
+
+unsigned
+stp_papersize_get_height(const stp_papersize_t pt)
+{
+ const stp_internal_papersize_t *p = (const stp_internal_papersize_t *) pt;
+ return p->height;
+}
+
+unsigned
+stp_papersize_get_top(const stp_papersize_t pt)
+{
+ const stp_internal_papersize_t *p = (const stp_internal_papersize_t *) pt;
+ return p->top;
+}
+
+unsigned
+stp_papersize_get_left(const stp_papersize_t pt)
+{
+ const stp_internal_papersize_t *p = (const stp_internal_papersize_t *) pt;
+ return p->left;
+}
+
+unsigned
+stp_papersize_get_bottom(const stp_papersize_t pt)
+{
+ const stp_internal_papersize_t *p = (const stp_internal_papersize_t *) pt;
+ return p->bottom;
+}
+
+unsigned
+stp_papersize_get_right(const stp_papersize_t pt)
+{
+ const stp_internal_papersize_t *p = (const stp_internal_papersize_t *) pt;
+ return p->right;
+}
+
+stp_papersize_unit_t
+stp_papersize_get_unit(const stp_papersize_t pt)
+{
+ const stp_internal_papersize_t *p = (const stp_internal_papersize_t *) pt;
+ return p->paper_unit;
+}
+
+#if 1
+/*
+ * This is, of course, blatantly thread-unsafe. However, it certainly
+ * speeds up genppd by a lot!
+ */
+const stp_papersize_t
+stp_get_papersize_by_name(const char *name)
+{
+ static int last_used_papersize = 0;
+ int base = last_used_papersize;
+ int sizes = stp_known_papersizes();
+ int i;
+ for (i = 0; i < sizes; i++)
+ {
+ int size_to_try = (i + base) % sizes;
+ const stp_internal_papersize_t *val = &(paper_sizes[size_to_try]);
+ if (!strcmp(val->name, name))
+ {
+ last_used_papersize = size_to_try;
+ return (const stp_papersize_t) val;
+ }
+ }
+ return NULL;
+}
+#else
+const stp_papersize_t
+stp_get_papersize_by_name(const char *name)
+{
+ const stp_internal_papersize_t *val = &(paper_sizes[0]);
+ while (strlen(val->name) > 0)
+ {
+ if (!strcmp(val->name, name))
+ return (stp_papersize_t) val;
+ val++;
+ }
+ return NULL;
+}
+#endif
+
+const stp_papersize_t
+stp_get_papersize_by_index(int index)
+{
+ if (index < 0 || index >= stp_known_papersizes())
+ return NULL;
+ else
+ return (stp_papersize_t) &(paper_sizes[index]);
+}
+
+static int
+paper_size_mismatch(int l, int w, const stp_internal_papersize_t *val)
+{
+ int hdiff = abs(l - (int) val->height);
+ int vdiff = abs(w - (int) val->width);
+ return hdiff + vdiff;
+}
+
+const stp_papersize_t
+stp_get_papersize_by_size(int l, int w)
+{
+ int score = INT_MAX;
+ const stp_internal_papersize_t *ref = NULL;
+ const stp_internal_papersize_t *val = &(paper_sizes[0]);
+ int sizes = stp_known_papersizes();
+ int i;
+ for (i = 0; i < sizes; i++)
+ {
+ if (val->width == w && val->height == l)
+ return (stp_papersize_t) val;
+ else
+ {
+ int myscore = paper_size_mismatch(l, w, val);
+ if (myscore < score && myscore < 20)
+ {
+ ref = val;
+ score = myscore;
+ }
+ }
+ val++;
+ }
+ return (stp_papersize_t) ref;
+}
+
+void
+stp_default_media_size(const stp_printer_t printer,
+ /* I - Printer model (not used) */
+ const stp_vars_t v, /* I */
+ int *width, /* O - Width in points */
+ int *height) /* O - Height in points */
+{
+ if (stp_get_page_width(v) > 0 && stp_get_page_height(v) > 0)
+ {
+ *width = stp_get_page_width(v);
+ *height = stp_get_page_height(v);
+ }
+ else
+ {
+ const stp_papersize_t papersize =
+ stp_get_papersize_by_name(stp_get_media_size(v));
+ if (!papersize)
+ {
+ *width = 1;
+ *height = 1;
+ }
+ else
+ {
+ *width = stp_papersize_get_width(papersize);
+ *height = stp_papersize_get_height(papersize);
+ }
+ if (*width == 0)
+ *width = 612;
+ if (*height == 0)
+ *height = 792;
+ }
+}
+
+/*
+ * The list of printers has been moved to printers.c
+ */
+#include "print-printers.c"
+
+int
+stp_known_printers(void)
+{
+ return printer_count;
+}
+
+const stp_printer_t
+stp_get_printer_by_index(int idx)
+{
+ if (idx < 0 || idx >= printer_count)
+ return NULL;
+ return (stp_printer_t) &(printers[idx]);
+}
+
+const stp_printer_t
+stp_get_printer_by_long_name(const char *long_name)
+{
+ const stp_internal_printer_t *val = &(printers[0]);
+ int i;
+ for (i = 0; i < stp_known_printers(); i++)
+ {
+ if (!strcmp(val->long_name, long_name))
+ return (stp_printer_t) val;
+ val++;
+ }
+ return NULL;
+}
+
+const stp_printer_t
+stp_get_printer_by_driver(const char *driver)
+{
+ const stp_internal_printer_t *val = &(printers[0]);
+ int i;
+ for (i = 0; i < stp_known_printers(); i++)
+ {
+ if (!strcmp(val->driver, driver))
+ return (stp_printer_t) val;
+ val++;
+ }
+ return NULL;
+}
+
+int
+stp_get_printer_index_by_driver(const char *driver)
+{
+ int idx = 0;
+ const stp_internal_printer_t *val = &(printers[0]);
+ for (idx = 0; idx < stp_known_printers(); idx++)
+ {
+ if (!strcmp(val->driver, driver))
+ return idx;
+ val++;
+ }
+ return -1;
+}
+
+const char *
+stp_printer_get_long_name(const stp_printer_t p)
+{
+ const stp_internal_printer_t *val = (const stp_internal_printer_t *) p;
+ return val->long_name;
+}
+
+const char *
+stp_printer_get_driver(const stp_printer_t p)
+{
+ const stp_internal_printer_t *val = (const stp_internal_printer_t *) p;
+ return val->driver;
+}
+
+int
+stp_printer_get_model(const stp_printer_t p)
+{
+ const stp_internal_printer_t *val = (const stp_internal_printer_t *) p;
+ return val->model;
+}
+
+const stp_printfuncs_t *
+stp_printer_get_printfuncs(const stp_printer_t p)
+{
+ const stp_internal_printer_t *val = (const stp_internal_printer_t *) p;
+ return val->printfuncs;
+}
+
+const stp_vars_t
+stp_printer_get_printvars(const stp_printer_t p)
+{
+ const stp_internal_printer_t *val = (const stp_internal_printer_t *) p;
+ return (stp_vars_t) &(val->printvars);
+}
+
+const char *
+stp_default_dither_algorithm(void)
+{
+ return stp_dither_algorithm_name(0);
+}
+
+void
+stp_compute_page_parameters(int page_right, /* I */
+ int page_left, /* I */
+ int page_top, /* I */
+ int page_bottom, /* I */
+ double scaling, /* I */
+ int image_width, /* I */
+ int image_height, /* I */
+ stp_image_t *image, /* IO */
+ int *orientation, /* IO */
+ int *page_width, /* O */
+ int *page_height, /* O */
+ int *out_width, /* O */
+ int *out_height, /* O */
+ int *left, /* O */
+ int *top) /* O */
+{
+ *page_width = page_right - page_left;
+ *page_height = page_top - page_bottom;
+
+ /* In AUTO orientation, just orient the paper the same way as the image. */
+
+ if (*orientation == ORIENT_AUTO)
+ {
+ if ((*page_width >= *page_height && image_width >= image_height)
+ || (*page_height >= *page_width && image_height >= image_width))
+ *orientation = ORIENT_PORTRAIT;
+ else
+ *orientation = ORIENT_LANDSCAPE;
+ }
+
+ if (*orientation == ORIENT_LANDSCAPE)
+ image->rotate_ccw(image);
+ else if (*orientation == ORIENT_UPSIDEDOWN)
+ image->rotate_180(image);
+ else if (*orientation == ORIENT_SEASCAPE)
+ image->rotate_cw(image);
+
+ image_width = image->width(image);
+ image_height = image->height(image);
+
+ /*
+ * Calculate width/height...
+ */
+
+ if (scaling == 0.0)
+ {
+ *out_width = *page_width;
+ *out_height = *page_height;
+ }
+ else if (scaling < 0.0)
+ {
+ /*
+ * Scale to pixels per inch...
+ */
+
+ *out_width = image_width * -72.0 / scaling;
+ *out_height = image_height * -72.0 / scaling;
+ }
+ else
+ {
+ /*
+ * Scale by percent...
+ */
+
+ /*
+ * Decide which orientation gives the proper fit
+ * If we ask for 50%, we do not want to exceed that
+ * in either dimension!
+ */
+
+ int twidth0 = *page_width * scaling / 100.0;
+ int theight0 = twidth0 * image_height / image_width;
+ int theight1 = *page_height * scaling / 100.0;
+ int twidth1 = theight1 * image_width / image_height;
+
+ *out_width = FMIN(twidth0, twidth1);
+ *out_height = FMIN(theight0, theight1);
+ }
+
+ if (*out_width == 0)
+ *out_width = 1;
+ if (*out_height == 0)
+ *out_height = 1;
+
+ /*
+ * Adjust offsets depending on the page orientation...
+ */
+
+ if (*orientation == ORIENT_LANDSCAPE || *orientation == ORIENT_SEASCAPE)
+ {
+ int x;
+
+ x = *left;
+ *left = *top;
+ *top = x;
+ }
+
+ if ((*orientation == ORIENT_UPSIDEDOWN || *orientation == ORIENT_SEASCAPE)
+ && *left >= 0)
+ {
+ *left = *page_width - *left - *out_width;
+ if (*left < 0)
+ *left = 0;
+ }
+
+ if ((*orientation == ORIENT_UPSIDEDOWN || *orientation == ORIENT_LANDSCAPE)
+ && *top >= 0)
+ {
+ *top = *page_height - *top - *out_height;
+ if (*top < 0)
+ *top = 0;
+ }
+
+ if (*left < 0)
+ *left = (*page_width - *out_width) / 2;
+
+ if (*top < 0)
+ *top = (*page_height - *out_height) / 2;
+}
+
+void
+stp_set_printer_defaults(stp_vars_t v, const stp_printer_t p,
+ const char *ppd_file)
+{
+ const stp_printfuncs_t *printfuncs = stp_printer_get_printfuncs(p);
+ stp_set_resolution(v, ((printfuncs->default_parameters)
+ (p, ppd_file, "Resolution")));
+ stp_set_ink_type(v, ((printfuncs->default_parameters)
+ (p, ppd_file, "InkType")));
+ stp_set_media_type(v, ((printfuncs->default_parameters)
+ (p, ppd_file, "MediaType")));
+ stp_set_media_source(v, ((printfuncs->default_parameters)
+ (p, ppd_file, "InputSlot")));
+ stp_set_media_size(v, ((printfuncs->default_parameters)
+ (p, ppd_file, "PageSize")));
+ stp_set_dither_algorithm(v, stp_default_dither_algorithm());
+ stp_set_driver(v, stp_printer_get_driver(p));
+}
+
+static int
+verify_param(const char *checkval, stp_param_t *vptr,
+ int count, const char *what, const stp_vars_t v)
+{
+ int answer = 0;
+ int i;
+ if (count > 0)
+ {
+ for (i = 0; i < count; i++)
+ if (!strcmp(checkval, vptr[i].name))
+ {
+ answer = 1;
+ break;
+ }
+ if (!answer)
+ stp_eprintf(v, "%s is not a valid %s\n", checkval, what);
+ for (i = 0; i < count; i++)
+ {
+ stp_free((void *)vptr[i].name);
+ stp_free((void *)vptr[i].text);
+ }
+ }
+ else
+ stp_eprintf(v, "%s is not a valid %s\n", checkval, what);
+ if (vptr)
+ free(vptr);
+ return answer;
+}
+
+int
+stp_verify_printer_params(const stp_printer_t p, const stp_vars_t v)
+{
+ stp_param_t *vptr;
+ int count;
+ int i;
+ int answer = 1;
+ const stp_printfuncs_t *printfuncs = stp_printer_get_printfuncs(p);
+ const stp_vars_t printvars = stp_printer_get_printvars(p);
+ const char *ppd_file = stp_get_ppd_file(v);
+
+ /*
+ * Note that in raw CMYK mode the user is responsible for not sending
+ * color output to black & white printers!
+ */
+ if (stp_get_output_type(printvars) == OUTPUT_GRAY &&
+ (stp_get_output_type(v) == OUTPUT_COLOR ||
+ stp_get_output_type(v) == OUTPUT_RAW_CMYK))
+ {
+ answer = 0;
+ stp_eprintf(v, "Printer does not support color output\n");
+ }
+ if (strlen(stp_get_media_size(v)) > 0)
+ {
+ const char *checkval = stp_get_media_size(v);
+ vptr = (*printfuncs->parameters)(p, ppd_file, "PageSize", &count);
+ answer &= verify_param(checkval, vptr, count, "page size", v);
+ }
+ else
+ {
+ int height, width;
+ int min_height, min_width;
+ (*printfuncs->limit)(p, v, &width, &height, &min_width, &min_height);
+ if (stp_get_page_height(v) <= min_height ||
+ stp_get_page_height(v) > height ||
+ stp_get_page_width(v) <= min_width || stp_get_page_width(v) > width)
+ {
+ answer = 0;
+ stp_eprintf(v, "Image size is not valid\n");
+ }
+ }
+
+ if (strlen(stp_get_media_type(v)) > 0)
+ {
+ const char *checkval = stp_get_media_type(v);
+ vptr = (*printfuncs->parameters)(p, ppd_file, "MediaType", &count);
+ answer &= verify_param(checkval, vptr, count, "media type", v);
+ }
+
+ if (strlen(stp_get_media_source(v)) > 0)
+ {
+ const char *checkval = stp_get_media_source(v);
+ vptr = (*printfuncs->parameters)(p, ppd_file, "InputSlot", &count);
+ answer &= verify_param(checkval, vptr, count, "media source", v);
+ }
+
+ if (strlen(stp_get_resolution(v)) > 0)
+ {
+ const char *checkval = stp_get_resolution(v);
+ vptr = (*printfuncs->parameters)(p, ppd_file, "Resolution", &count);
+ answer &= verify_param(checkval, vptr, count, "resolution", v);
+ }
+
+ if (strlen(stp_get_ink_type(v)) > 0)
+ {
+ const char *checkval = stp_get_ink_type(v);
+ vptr = (*printfuncs->parameters)(p, ppd_file, "InkType", &count);
+ answer &= verify_param(checkval, vptr, count, "ink type", v);
+ }
+
+ for (i = 0; i < stp_dither_algorithm_count(); i++)
+ if (!strcmp(stp_get_dither_algorithm(v), stp_dither_algorithm_name(i)))
+ {
+ stp_set_verified(v, answer);
+ return answer;
+ }
+
+ stp_eprintf(v, "%s is not a valid dither algorithm\n",
+ stp_get_dither_algorithm(v));
+ stp_set_verified(v, 0);
+ return 0;
+}
+
+const stp_vars_t
+stp_default_settings()
+{
+ return (stp_vars_t) &default_vars;
+}
+
+const stp_vars_t
+stp_maximum_settings()
+{
+ return (stp_vars_t) &max_vars;
+}
+
+const stp_vars_t
+stp_minimum_settings()
+{
+ return (stp_vars_t) &min_vars;
+}
+
+#if defined DISABLE_NLS || !defined HAVE_VASPRINTF
+#include <stdarg.h>
+
+static int vasprintf (char **result, const char *format, va_list args);
+static int int_vasprintf (char **result, const char *format, va_list *args);
+
+static int
+int_vasprintf (char **result, const char *format, va_list *args)
+{
+ const char *p = format;
+ /* Add one to make sure that it is never zero, which might cause malloc
+ to return NULL. */
+ int total_width = strlen (format) + 1;
+ va_list ap;
+
+ memcpy (&ap, args, sizeof (va_list));
+
+ while (*p != '\0')
+ {
+ if (*p++ == '%')
+ {
+ while (strchr ("-+ #0", *p))
+ ++p;
+ if (*p == '*')
+ {
+ ++p;
+ total_width += abs (va_arg (ap, int));
+ }
+ else
+ total_width += strtoul (p, (char **) &p, 10);
+ if (*p == '.')
+ {
+ ++p;
+ if (*p == '*')
+ {
+ ++p;
+ total_width += abs (va_arg (ap, int));
+ }
+ else
+ total_width += strtoul (p, (char **) &p, 10);
+ }
+ while (strchr ("hlL", *p))
+ ++p;
+ /* Should be big enough for any format specifier except %s. */
+ total_width += 30;
+ switch (*p)
+ {
+ case 'd':
+ case 'i':
+ case 'o':
+ case 'u':
+ case 'x':
+ case 'X':
+ case 'c':
+ (void) va_arg (ap, int);
+ break;
+ case 'f':
+ case 'e':
+ case 'E':
+ case 'g':
+ case 'G':
+ (void) va_arg (ap, double);
+ break;
+ case 's':
+ total_width += strlen (va_arg (ap, char *));
+ break;
+ case 'p':
+ case 'n':
+ (void) va_arg (ap, char *);
+ break;
+ }
+ }
+ }
+#ifdef TEST
+ global_total_width = total_width;
+#endif
+ *result = malloc (total_width);
+ if (*result != NULL)
+ return vsprintf (*result, format, *args);
+ else
+ return 0;
+}
+
+static int
+vasprintf (char **result, const char *format, va_list args)
+{
+ return int_vasprintf (result, format, &args);
+}
+#else
+extern int vasprintf (char **result, const char *format, va_list args);
+#endif
+
+void
+stp_zprintf(const stp_vars_t v, const char *format, ...)
+{
+ va_list args;
+ int bytes;
+ char *result;
+ va_start(args, format);
+ bytes = vasprintf(&result, format, args);
+ va_end(args);
+ (stp_get_outfunc(v))((void *)(stp_get_outdata(v)), result, bytes);
+ free(result);
+}
+
+void
+stp_zfwrite(const char *buf, size_t bytes, size_t nitems, const stp_vars_t v)
+{
+ (stp_get_outfunc(v))((void *)(stp_get_outdata(v)), buf, bytes * nitems);
+}
+
+void
+stp_putc(int ch, const stp_vars_t v)
+{
+ char a = (char) ch;
+ (stp_get_outfunc(v))((void *)(stp_get_outdata(v)), &a, 1);
+}
+
+void
+stp_puts(const char *s, const stp_vars_t v)
+{
+ (stp_get_outfunc(v))((void *)(stp_get_outdata(v)), s, strlen(s));
+}
+
+void
+stp_eprintf(const stp_vars_t v, const char *format, ...)
+{
+ va_list args;
+ int bytes;
+ char *result;
+ if (stp_get_errfunc(v))
+ {
+ va_start(args, format);
+ bytes = vasprintf(&result, format, args);
+ va_end(args);
+ (stp_get_errfunc(v))((void *)(stp_get_errdata(v)), result, bytes);
+ free(result);
+ }
+}
+
+void
+stp_erputc(int ch)
+{
+ putc(ch, stderr);
+}
+
+void
+stp_erprintf(const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ vfprintf(stderr, format, args);
+ va_end(args);
+}
+
+static unsigned long stp_debug_level = 0;
+
+static void
+init_stp_debug(void)
+{
+ static int debug_initialized = 0;
+ if (!debug_initialized)
+ {
+ const char *dval = getenv("STP_DEBUG");
+ debug_initialized = 1;
+ if (dval)
+ {
+ stp_debug_level = strtoul(dval, 0, 0);
+ stp_erprintf("Gimp-Print %s %s\n", VERSION, RELEASE_DATE);
+ }
+ }
+}
+
+void
+stp_dprintf(unsigned long level, const stp_vars_t v, const char *format, ...)
+{
+ va_list args;
+ int bytes;
+ char *result;
+ init_stp_debug();
+ if ((level & stp_debug_level) && stp_get_errfunc(v))
+ {
+ va_start(args, format);
+ bytes = vasprintf(&result, format, args);
+ va_end(args);
+ (stp_get_errfunc(v))((void *)(stp_get_errdata(v)), result, bytes);
+ free(result);
+ }
+}
+
+void
+stp_deprintf(unsigned long level, const char *format, ...)
+{
+ va_list args;
+ int bytes;
+ char *result;
+ init_stp_debug();
+ if (level & stp_debug_level)
+ {
+ va_start(args, format);
+ bytes = vasprintf(&result, format, args);
+ va_end(args);
+ stp_erprintf("%s", result);
+ free(result);
+ }
+}
+
+void *
+stp_malloc (size_t size)
+{
+ register void *memptr = NULL;
+
+ if ((memptr = malloc (size)) == NULL)
+ {
+ fputs("Virtual memory exhausted.\n", stderr);
+ exit (EXIT_FAILURE);
+ }
+ return (memptr);
+}
+
+void
+stp_free(void *ptr)
+{
+ free(ptr);
+}
+
+int
+stp_init(void)
+{
+ static int stp_is_initialised = 0;
+ if (!stp_is_initialised)
+ {
+ /* Things that are only initialised once */
+ /* Set up gettext */
+#ifdef ENABLE_NLS
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, PACKAGE_LOCALE_DIR);
+#endif
+ init_stp_debug();
+ }
+ stp_is_initialised = 1;
+ return (0);
+}
+
+#ifdef QUANTIFY
+unsigned quantify_counts[NUM_QUANTIFY_BUCKETS] = {0};
+struct timeval quantify_buckets[NUM_QUANTIFY_BUCKETS] = {{0,0}};
+int quantify_high_index = 0;
+int quantify_first_time = 1;
+struct timeval quantify_cur_time;
+struct timeval quantify_prev_time;
+
+void print_timers(const stp_vars_t v)
+{
+ int i;
+
+ stp_eprintf(v, "%s", "Quantify timers:\n");
+ for (i = 0; i <= quantify_high_index; i++)
+ {
+ if (quantify_counts[i] > 0)
+ {
+ stp_eprintf(v,
+ "Bucket %d:\t%ld.%ld s\thit %u times\n", i,
+ quantify_buckets[i].tv_sec, quantify_buckets[i].tv_usec,
+ quantify_counts[i]);
+ quantify_buckets[i].tv_sec = 0;
+ quantify_buckets[i].tv_usec = 0;
+ quantify_counts[i] = 0;
+ }
+ }
+}
+#endif