filter/braille/filters/TODO.txt
EXTRA_DIST += \
- cupsfilters/testdriver.c \
+ ppd/testdriver.c \
data/makePDFfromPS.sh \
data/classified.ps \
data/confidential.ps \
pkgppdinclude_DATA = \
ppd/ppd.h \
ppd/ppdc.h \
- cupsfilters/log.h
+ ppd/ppd-filter.h
pkgppddefsdir = $(datadir)/ppdc
pkgppddefs_DATA = \
ppd/ppd-conflicts.c \
ppd/ppd-custom.c \
ppd/ppd-emit.c \
+ ppd/ppd-filter.c \
+ ppd/ppd-generator.c \
+ ppd/ppd-load-profile.c \
ppd/ppd-localize.c \
ppd/ppd-mark.c \
ppd/ppd-page.c \
ppd/encode.c \
ppd/file.c \
ppd/file-private.h \
+ ppd/imagetops-pstops.c \
ppd/ipp-private.h \
ppd/language.c \
ppd/language-private.h \
+ ppd/pdftops.c \
ppd/raster-interpret.c \
ppd/raster-error.c \
ppd/raster-private.h \
+ ppd/rastertops.c \
ppd/string.c \
ppd/snprintf.c \
ppd/string-private.h \
$(pkgppdinclude_DATA) \
$(pkgppddefs_DATA)
libppd_la_LIBADD = \
+ libcupsfilters.la \
$(CUPS_LIBS)
libppd_la_CFLAGS = \
+ -I$(srcdir)/cupsfilters/ \
$(CUPS_CFLAGS)
libppd_la_LDFLAGS = \
-no-undefined \
-version-info 1
+libppd_la_DEPENDENCIES = \
+ libcupsfilters.la
testppd_SOURCES = ppd/testppd.c
testppd_LDADD = libppd.la \
pkgfiltersincludedir = $(includedir)/cupsfilters
pkgfiltersinclude_DATA = \
cupsfilters/bitmap.h \
+ cupsfilters/catalog.h \
cupsfilters/colord.h \
cupsfilters/colormanager.h \
cupsfilters/driver.h \
cupsfilters/log.h \
cupsfilters/pdf.h \
cupsfilters/pdfutils.h \
- cupsfilters/ppdgenerator.h \
cupsfilters/raster.h
lib_LTLIBRARIES += libcupsfilters.la
#TESTS += test1284
libcupsfilters_la_SOURCES = \
- cupsfilters/attr.c \
cupsfilters/bannertopdf.c \
cupsfilters/bitmap.c \
+ cupsfilters/catalog.c \
cupsfilters/check.c \
cupsfilters/cmyk.c \
cupsfilters/colord.c \
cupsfilters/pdf.cxx \
cupsfilters/pdftopdf/pdftopdf.cxx \
cupsfilters/pdftopdf/pdftopdf-private.h \
- cupsfilters/pdftopdf/pdftopdf-jcl.cxx \
- cupsfilters/pdftopdf/pdftopdf-jcl-private.h \
cupsfilters/pdftopdf/pdftopdf-processor.cxx \
cupsfilters/pdftopdf/pdftopdf-processor-private.h \
cupsfilters/pdftopdf/qpdf-pdftopdf-processor.cxx \
cupsfilters/pdftopdf/qpdf-pdftopdf-private.h \
cupsfilters/pdftopdf/qpdf-cm.cxx \
cupsfilters/pdftopdf/qpdf-cm-private.h \
- cupsfilters/pdftops.c \
cupsfilters/pdftoraster.cxx \
cupsfilters/pdfutils.c \
- cupsfilters/ppdgenerator.c \
- cupsfilters/imagetops-pstops.c \
cupsfilters/pwgtoraster.c \
cupsfilters/raster.c \
- cupsfilters/rastertops.c \
cupsfilters/rastertopdf.cxx \
cupsfilters/rastertopwg.c \
cupsfilters/rgb.c \
cupsfilters/getline.c \
cupsfilters/strcasestr.c
libcupsfilters_la_LIBADD = \
- libppd.la \
libfontembed.la \
$(FONTCONFIG_LIBS) \
$(GETLINE) \
$(POPPLER_LIBS) \
-lm
libcupsfilters_la_CFLAGS = \
- -I$(srcdir)/ppd/ \
-I$(srcdir)/fontembed/ \
$(FONTCONFIG_CFLAGS) \
$(CUPS_CFLAGS) \
libcupsfilters_la_LIBADD += $(DBUS_LIBS)
endif
libcupsfilters_la_DEPENDENCIES = \
- libppd.la \
libfontembed.la \
$(GETLINE) \
$(STRCASESTR)
filter/bannertopdf.c
bannertopdf_CFLAGS = \
$(CUPS_CFLAGS) \
- -I$(srcdir)/cupsfilters/
+ -I$(srcdir)/cupsfilters/ \
+ -I$(srcdir)/ppd/
bannertopdf_LDADD = \
$(CUPS_LIBS) \
- libcupsfilters.la
+ libcupsfilters.la \
+ libppd.la
commandtoescpx_SOURCES = \
cupsfilters/driver.h \
foomatic_rip_CFLAGS = \
-DCONFIG_PATH='"$(sysconfdir)/foomatic"' \
$(CUPS_CFLAGS) \
- -I$(srcdir)/cupsfilters/
+ -I$(srcdir)/cupsfilters/ \
+ -I$(srcdir)/ppd/
foomatic_rip_LDADD = \
$(CUPS_LIBS) \
-lm \
- libcupsfilters.la
+ libcupsfilters.la \
+ libppd.la
gstoraster_SOURCES = \
filter/gstoraster.c
gstoraster_CFLAGS = \
$(CUPS_CFLAGS) \
- -I$(srcdir)/cupsfilters/
+ -I$(srcdir)/cupsfilters/ \
+ -I$(srcdir)/ppd/
gstoraster_LDADD = \
$(CUPS_LIBS) \
- libcupsfilters.la
+ libcupsfilters.la \
+ libppd.la
gstopdf_SOURCES = \
filter/gstopdf.c
gstopdf_CFLAGS = \
$(CUPS_CFLAGS) \
- -I$(srcdir)/cupsfilters/
+ -I$(srcdir)/cupsfilters/ \
+ -I$(srcdir)/ppd/
gstopdf_LDADD = \
$(CUPS_LIBS) \
- libcupsfilters.la
+ libcupsfilters.la \
+ libppd.la
gstopxl_SOURCES = \
filter/gstopxl.c
gstopxl_CFLAGS = \
$(CUPS_CFLAGS) \
- -I$(srcdir)/cupsfilters/
+ -I$(srcdir)/cupsfilters/ \
+ -I$(srcdir)/ppd/
gstopxl_LDADD = \
$(CUPS_LIBS) \
- libcupsfilters.la
+ libcupsfilters.la \
+ libppd.la
imagetopdf_SOURCES = \
filter/imagetopdf.c
imagetopdf_CFLAGS = \
$(CUPS_CFLAGS) \
- -I$(srcdir)/cupsfilters/
+ -I$(srcdir)/cupsfilters/ \
+ -I$(srcdir)/ppd/
imagetopdf_LDADD = \
$(CUPS_LIBS) \
- libcupsfilters.la
+ libcupsfilters.la \
+ libppd.la
imagetops_SOURCES = \
filter/imagetops.c
imagetops_CFLAGS = \
$(CUPS_CFLAGS) \
- -I$(srcdir)/cupsfilters/
+ -I$(srcdir)/cupsfilters/ \
+ -I$(srcdir)/ppd/
imagetops_LDADD = \
$(CUPS_LIBS) \
- libcupsfilters.la
+ libcupsfilters.la \
+ libppd.la
imagetoraster_SOURCES = \
filter/imagetoraster.c
imagetoraster_CFLAGS = \
$(CUPS_CFLAGS) \
- -I$(srcdir)/cupsfilters/
+ -I$(srcdir)/cupsfilters/ \
+ -I$(srcdir)/ppd/
imagetoraster_LDADD = \
$(CUPS_LIBS) \
- libcupsfilters.la
+ libcupsfilters.la \
+ libppd.la
pclmtoraster_SOURCES = \
filter/pclmtoraster.c
pclmtoraster_CXXFLAGS = \
-I$(srcdir)/cupsfilters/ \
+ -I$(srcdir)/ppd/ \
$(CUPS_CFLAGS)
pclmtoraster_LDADD = \
libcupsfilters.la \
+ libppd.la \
$(CUPS_LIBS)
rastertopclm_SOURCES = \
filter/rastertopclm.c
rastertopclm_CFLAGS = \
$(CUPS_CFLAGS) \
- -I$(srcdir)/cupsfilters/
+ -I$(srcdir)/cupsfilters/ \
+ -I$(srcdir)/ppd/
rastertopclm_LDADD = \
$(CUPS_LIBS) \
- libcupsfilters.la
+ libcupsfilters.la \
+ libppd.la
rastertopdf_SOURCES = \
filter/rastertopdf.c
rastertopdf_CFLAGS = \
$(CUPS_CFLAGS) \
- -I$(srcdir)/cupsfilters/
+ -I$(srcdir)/cupsfilters/ \
+ -I$(srcdir)/ppd/
rastertopdf_LDADD = \
$(CUPS_LIBS) \
- libcupsfilters.la
+ libcupsfilters.la \
+ libppd.la
mupdftopwg_SOURCES = \
filter/mupdftopwg.c
filter/pwgtoraster.c
pwgtoraster_CFLAGS = \
$(CUPS_CFLAGS) \
- -I$(srcdir)/cupsfilters/
+ -I$(srcdir)/cupsfilters/ \
+ -I$(srcdir)/ppd/
pwgtoraster_LDADD = \
$(CUPS_LIBS) \
- libcupsfilters.la
+ libcupsfilters.la \
+ libppd.la
rastertops_SOURCES = \
filter/rastertops.c
rastertops_CFLAGS = \
$(CUPS_CFLAGS) \
- -I$(srcdir)/cupsfilters/
+ -I$(srcdir)/cupsfilters/ \
+ -I$(srcdir)/ppd/
rastertops_LDADD = \
$(CUPS_LIBS) \
- libcupsfilters.la
+ libcupsfilters.la \
+ libppd.la
rastertopwg_SOURCES = \
filter/rastertopwg.c
rastertopwg_CFLAGS = \
$(CUPS_CFLAGS) \
- -I$(srcdir)/cupsfilters/
+ -I$(srcdir)/cupsfilters/ \
+ -I$(srcdir)/ppd/
rastertopwg_LDADD = \
$(CUPS_LIBS) \
- libcupsfilters.la
+ libcupsfilters.la \
+ libppd.la
texttotext_SOURCES = \
filter/texttotext.c
texttotext_CFLAGS = \
-I$(srcdir)/cupsfilters/ \
+ -I$(srcdir)/ppd/ \
$(CUPS_CFLAGS)
texttotext_LDADD = \
libcupsfilters.la \
+ libppd.la \
$(CUPS_LIBS)
texttopdf_SOURCES = \
filter/texttopdf.c
texttopdf_CFLAGS = \
-I$(srcdir)/cupsfilters/ \
+ -I$(srcdir)/ppd/ \
$(CUPS_CFLAGS)
texttopdf_LDADD = \
libcupsfilters.la \
+ libppd.la \
$(CUPS_LIBS)
pdftops_SOURCES = \
filter/pdftops.c
pdftops_CFLAGS = \
-I$(srcdir)/cupsfilters/ \
+ -I$(srcdir)/ppd/ \
$(CUPS_CFLAGS)
pdftops_LDADD = \
libcupsfilters.la \
+ libppd.la \
$(CUPS_LIBS)
pstops_SOURCES = \
filter/pstops.c
pstops_CFLAGS = \
-I$(srcdir)/cupsfilters/ \
+ -I$(srcdir)/ppd/ \
$(CUPS_CFLAGS)
pstops_LDADD = \
libcupsfilters.la \
+ libppd.la \
$(CUPS_LIBS)
pdftoraster_SOURCES = \
filter/pdftoraster.c
pdftoraster_CFLAGS = \
-I$(srcdir)/cupsfilters/ \
+ -I$(srcdir)/ppd/ \
$(CUPS_CFLAGS)
pdftoraster_LDADD = \
libcupsfilters.la \
+ libppd.la \
$(CUPS_LIBS)
rastertoescpx_SOURCES = \
$(CUPS_CFLAGS)
universal_LDADD = \
libcupsfilters.la \
+ libppd.la \
$(CUPS_LIBS)
# =====
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
-#include <cupsfilters/filter.h>
+#include <ppd/ppd-filter.h>
#include <cupsfilters/ipp.h>
/*
int fd, nullfd;
cf_filter_data_t filter_data;
cf_filter_universal_parameter_t universal_parameters;
- cf_filter_external_cups_t ipp_backend_params;
+ ppd_filter_external_cups_t ipp_backend_params;
cf_filter_filter_in_chain_t universal_in_chain,
ipp_in_chain;
cups_array_t *filter_chain;
filter_data.job_user = argv[2];
filter_data.job_title = title;
filter_data.copies = atoi(argv[4]);
+ filter_data.content_type = "application/vnd.cups-pdf";
+ filter_data.final_content_type = document_format;
filter_data.job_attrs = NULL; /* We use command line options */
- if ((filter_data.printer_attrs =
- cfGetPrinterAttributes4(printer_uri, NULL, 0, NULL, 0, 1, 0)) !=
- NULL)
+ filter_data.printer_attrs =
+ cfGetPrinterAttributes4(printer_uri, NULL, 0, NULL, 0, 1, 0);
/* Poll the printer attributes from
the printer */
- filter_data.ppdfile = NULL; /* We have successfully polled
- the IPP attributes from the
- printer. This is the most
- precise printer capability info.
- As the queue's PPD is only
- for the cluster we prefer the
- IPP attributes */
- else
- filter_data.ppdfile = getenv("PPD");/*The polling of the printer's
- IPP attribute failed, meaning
- that it is most probably not a
- driverless IPP printers (IPP 2.x)
- but a legacy IPP printer (IPP
- 1.x) which usually has
- unsufficient capability info.
- Therefore we fall back to the
- PPD file here which contains
- some info from the printer's
- DNS-SD record. */
filter_data.num_options = num_options;
filter_data.options = options; /* Command line options from 5th
arg */
+ filter_data.extension = NULL;
filter_data.back_pipe[0] = -1;
filter_data.back_pipe[1] = -1;
filter_data.side_pipe[0] = -1;
function */
filter_data.iscanceleddata = &job_canceled;
- cfFilterLoadPPD(&filter_data);
- if (filter_data.printer_attrs == NULL && filter_data.ppd == NULL)
+ /* If the polling of the printer's IPP attributes has failed, it
+ means most probably that it is not a driverless IPP printer
+ (IPP 2.x) but a legacy IPP printer (IPP 1.x) which usually
+ has unsufficient capability info. Therefore we fall back to
+ the PPD file here which contains some info from the printer's
+ DNS-SD record.
+
+ If we have successfully polled the IPP attributes from the
+ printer, these attributes are the most precise printer
+ capability info and as the queue's PPD is only for the
+ cluster we prefer the IPP attributes. */
+ if (filter_data.printer_attrs == NULL &&
+ ppdFilterLoadPPDFile(&filter_data, getenv("PPD")) < 0)
{
ippDelete(response);
fprintf(stderr, "ERROR: Unable to get sufficient capability info of the destination printer.\n");
cfFilterOpenBackAndSidePipes(&filter_data);
- /* Parameters (input/output MIME types) for cfFilterUniversal() call */
- universal_parameters.input_format = "application/vnd.cups-pdf";
- universal_parameters.output_format = document_format;
+ /* Parameters for cfFilterUniversal() call */
+ universal_parameters.actual_output_type = NULL;
memset(&(universal_parameters.texttopdf_params), 0,
sizeof(cf_filter_texttopdf_parameter_t));
ipp_backend_params.options = NULL;
ipp_backend_params.envp = NULL;
- /* Filter chain entry for the cfFilterUniversal() filter function call */
- universal_in_chain.function = cfFilterUniversal;
+ /* Filter chain entry for the ppdFilterUniversal() filter function call */
+ universal_in_chain.function = ppdFilterUniversal;
universal_in_chain.parameters = &universal_parameters;
universal_in_chain.name = "Filters";
/* Filter chain entry for the IPP CUPS backend call */
- ipp_in_chain.function = cfFilterExternalCUPS;
+ ipp_in_chain.function = ppdFilterExternalCUPS;
ipp_in_chain.parameters = &ipp_backend_params;
ipp_in_chain.name = "Backend";
/* Call the filter chain to run the needed filters and the backend */
retval = cfFilterChain(fd, nullfd, fd != 0 ? 1 : 0, &filter_data,
- filter_chain);
+ filter_chain);
cfFilterCloseBackAndSidePipes(&filter_data);
/* Clean up */
cupsArrayDelete(filter_chain);
ippDelete(response);
- cfFilterFreePPD(&filter_data);
+
+ ppdFilterFreePPDFile(&filter_data);
if (retval) {
fprintf(stderr, "ERROR: Job processing failed.\n");
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
+#include <stdio.h>
#include <sys/socket.h>
+++ /dev/null
-/*
- * PPD attribute lookup routine for CUPS.
- *
- * Copyright 2007-2011 by Apple Inc.
- * Copyright 1993-2005 by Easy Software Products.
- *
- * These coded instructions, statements, and computer programs are the
- * property of Apple Inc. and are protected by Federal copyright
- * law. Distribution and use rights are outlined in the file "COPYING"
- * which should have been included with this file.
- *
- * Contents:
- *
- * cfFindAttr() - Find a PPD attribute based on the colormodel,
- * media, and resolution.
- */
-
-/*
- * Include necessary headers.
- */
-
-#include <config.h>
-#include "driver.h"
-#include <string.h>
-#include <ctype.h>
-
-
-/*
- * 'cfFindAttr()' - Find a PPD attribute based on the colormodel,
- * media, and resolution.
- */
-
-ppd_attr_t * /* O - Matching attribute or NULL */
-cfFindAttr(ppd_file_t *ppd, /* I - PPD file */
- const char *name, /* I - Attribute name */
- const char *colormodel, /* I - Color model */
- const char *media, /* I - Media type */
- const char *resolution, /* I - Resolution */
- char *spec, /* O - Final selection string */
- int specsize, /* I - Size of string buffer */
- cf_logfunc_t log, /* I - Log function */
- void *ld) /* I - Log function data */
-{
- ppd_attr_t *attr; /* Attribute */
-
-
- /*
- * Range check input...
- */
-
- if (!ppd || !name || !colormodel || !media || !resolution || !spec ||
- specsize < PPD_MAX_NAME)
- return (NULL);
-
- /*
- * Look for the attribute with the following keywords:
- *
- * ColorModel.MediaType.Resolution
- * ColorModel.Resolution
- * ColorModel
- * MediaType.Resolution
- * MediaType
- * Resolution
- * ""
- */
-
- snprintf(spec, specsize, "%s.%s.%s", colormodel, media, resolution);
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "Looking for \"*%s %s\"...", name, spec);
- if ((attr = ppdFindAttr(ppd, name, spec)) != NULL && attr->value != NULL)
- return (attr);
-
- snprintf(spec, specsize, "%s.%s", colormodel, resolution);
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "Looking for \"*%s %s\"...", name, spec);
- if ((attr = ppdFindAttr(ppd, name, spec)) != NULL && attr->value != NULL)
- return (attr);
-
- snprintf(spec, specsize, "%s", colormodel);
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "Looking for \"*%s %s\"...", name, spec);
- if ((attr = ppdFindAttr(ppd, name, spec)) != NULL && attr->value != NULL)
- return (attr);
-
- snprintf(spec, specsize, "%s.%s", media, resolution);
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "Looking for \"*%s %s\"...", name, spec);
- if ((attr = ppdFindAttr(ppd, name, spec)) != NULL && attr->value != NULL)
- return (attr);
-
- snprintf(spec, specsize, "%s", media);
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "Looking for \"*%s %s\"...", name, spec);
- if ((attr = ppdFindAttr(ppd, name, spec)) != NULL && attr->value != NULL)
- return (attr);
-
- snprintf(spec, specsize, "%s", resolution);
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "Looking for \"*%s %s\"...", name, spec);
- if ((attr = ppdFindAttr(ppd, name, spec)) != NULL && attr->value != NULL)
- return (attr);
-
- spec[0] = '\0';
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "Looking for \"*%s\"...", name);
- if ((attr = ppdFindAttr(ppd, name, spec)) != NULL && attr->value != NULL)
- return (attr);
-
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "No instance of \"*%s\" found...", name);
-
- return (NULL);
-}
-
#include <stdarg.h>
#include <math.h>
#include <errno.h>
-#include <cupsfilters/ppdgenerator.h>
+#include "ipp.h"
+#include "ipp.h"
#include "raster.h"
#ifndef HAVE_OPEN_MEMSTREAM
#endif
#include <cups/cups.h>
-#include <ppd/ppd.h>
-#if (CUPS_VERSION_MAJOR > 1) || (CUPS_VERSION_MINOR > 6)
-#define HAVE_CUPS_1_7 1
-#endif
-#ifdef HAVE_CUPS_1_7
#include <cups/pwg.h>
-#endif /* HAVE_CUPS_1_7 */
#include "filter.h"
#include "pdf.h"
return banner;
}
-static float get_float_option(const char *name,
- int noptions,
- cups_option_t *options,
- float def)
-{
- const char *value = cupsGetOption(name, noptions, options);
- return value ? atof(value) : def;
-}
-
static int get_int_option(const char *name,
- int noptions,
+ int num_options,
cups_option_t *options,
int def)
{
- const char *value = cupsGetOption(name, noptions, options);
+ const char *value = cupsGetOption(name, num_options, options);
return value ? atoi(value) : def;
}
-static void get_pagesize(cf_filter_data_t *data,
- int noptions,
- cups_option_t *options,
- float *width,
- float *length,
- float media_limits[4])
+static int duplex_marked(cf_filter_data_t *data)
{
- ppd_file_t *ppd = data->ppd;
- ipp_t *printer_attrs = data->printer_attrs;
- static ppd_size_t defaultsize = {
- 0, /* marked */
- "", /* name */
- 612.0, /* width */
- 792.0, /* length */
- 18.0, /* left */
- 36.0, /* bottom */
- 594.0, /* right */
- 756.0, /* top */
- };
- ppd_size_t *pagesize = &defaultsize;
-#ifdef HAVE_CUPS_1_7
- pwg_media_t *size_found; /* page size found for given name */
- const char *val; /* Pointer into value */
- char *ptr1, *ptr2, /* Pointer into string */
- s[255]; /* Temporary string */
-#endif /* HAVE_CUPS_1_7 */
-
- if (!ppd || !(pagesize = ppdPageSize(ppd, NULL))) {
- pagesize = &defaultsize;
- if(printer_attrs!=NULL){
- int left,
- right,
- top,
- bottom,
- min_length = 2147483647,
- min_width = 2147483647,
- max_length = 0,
- max_width = 0;
- char defsize[41];
- ipp_attribute_t *defattr;
- cups_array_t *printer_sizes;
- printer_sizes = cfGenerateSizes(printer_attrs, &defattr, &min_length, &min_width,
- &max_length, &max_width,
- &bottom, &left, &right, &top, defsize);
- for(cups_size_t *size = (cups_size_t*)cupsArrayFirst(printer_sizes); size;
- size = (cups_size_t*)cupsArrayNext(printer_sizes)){
- if(!strcmp(size->media, defsize)){
- ppd_size_t temp;
- snprintf(temp.name, sizeof(temp.name),"%s", defsize);
- temp.top = size->top *72.0 / 2540.0;
- temp.bottom = size->bottom *72.0 / 2540.0;
- temp.left = size->left *72.0 / 2540.0;
- temp.right = size->right *72.0 / 2540.0;
- temp.width = size->width *72.0 / 2540.0;
- temp.length = size->length *72.0 / 2540.0;
- pagesize = &temp;
- break;
- }
- }
- }
- }
-
- *width = pagesize->width;
- *length = pagesize->length;
-
- media_limits[0] = get_float_option("page-left",
- noptions, options,
- pagesize->left);
- media_limits[1] = get_float_option("page-bottom",
- noptions, options,
- pagesize->bottom);
- media_limits[2] = get_float_option("page-right",
- noptions, options,
- fabs(pagesize->right));
- media_limits[3] = get_float_option("page-top",
- noptions, options,
- fabs(pagesize->top));
-
-#ifdef HAVE_CUPS_1_7
- if (!ppd)
- {
- if ((val = cupsGetOption("media-size", noptions, options)) != NULL ||
- (val = cupsGetOption("MediaSize", noptions, options)) != NULL ||
- (val = cupsGetOption("page-size", noptions, options)) != NULL ||
- (val = cupsGetOption("PageSize", noptions, options)) != NULL ||
- (val = cupsGetOption("media", noptions, options)) != NULL)
- {
- for (ptr1 = (char *)val; *ptr1;)
- {
- for (ptr2 = s; *ptr1 && *ptr1 != ',' && (ptr2 - s) < (sizeof(s) - 1);)
- *ptr2++ = *ptr1++;
- *ptr2++ = '\0';
- if (*ptr1 == ',')
- ptr1++;
- size_found = NULL;
- if ((size_found = pwgMediaForPWG(s)) == NULL)
- if ((size_found = pwgMediaForPPD(s)) == NULL)
- size_found = pwgMediaForLegacy(s);
- if (size_found != NULL)
- {
- *width = size_found->width * 72.0 / 2540.0;
- *length = size_found->length * 72.0 / 2540.0;
- media_limits[2] += (*width - 612.0);
- media_limits[3] += (*length - 792.0);
- }
- }
- }
- if ((val = cupsGetOption("media-left-margin", noptions, options)) != NULL)
- media_limits[0] = atol(val) * 72.0 / 2540.0;
- if ((val = cupsGetOption("media-bottom-margin", noptions, options)) != NULL)
- media_limits[1] = atol(val) * 72.0 / 2540.0;
- if ((val = cupsGetOption("media-right-margin", noptions, options)) != NULL)
- media_limits[2] = *width - atol(val) * 72.0 / 2540.0;
- if ((val = cupsGetOption("media-top-margin", noptions, options)) != NULL)
- media_limits[3] = *length - atol(val) * 72.0 / 2540.0;
- }
-#endif /* HAVE_CUPS_1_7 */
-}
-
-static int duplex_marked(ppd_file_t *ppd,
- int noptions,
- cups_option_t *options)
-{
- const char *val; /* Pointer into value */
- return (ppd &&
- (ppdIsMarked(ppd, "Duplex", "DuplexNoTumble") ||
- ppdIsMarked(ppd, "Duplex", "DuplexTumble") ||
- ppdIsMarked(ppd, "JCLDuplex", "DuplexNoTumble") ||
- ppdIsMarked(ppd, "JCLDuplex", "DuplexTumble") ||
- ppdIsMarked(ppd, "EFDuplex", "DuplexNoTumble") ||
- ppdIsMarked(ppd, "EFDuplex", "DuplexTumble") ||
- ppdIsMarked(ppd, "EFDuplexing", "DuplexNoTumble") ||
- ppdIsMarked(ppd, "EFDuplexing", "DuplexTumble") ||
- ppdIsMarked(ppd, "ARDuplex", "DuplexNoTumble") ||
- ppdIsMarked(ppd, "ARDuplex", "DuplexTumble") ||
- ppdIsMarked(ppd, "KD03Duplex", "DuplexNoTumble") ||
- ppdIsMarked(ppd, "KD03Duplex", "DuplexTumble"))) ||
- ((val = cupsGetOption("Duplex", noptions, options)) != NULL &&
- (!strcasecmp(val, "DuplexNoTumble") ||
- !strcasecmp(val, "DuplexTumble"))) ||
- ((val = cupsGetOption("sides", noptions, options)) != NULL &&
- (!strcasecmp(val, "two-sided-long-edge") ||
- !strcasecmp(val, "two-sided-short-edge")));
+ const char *val; /* Pointer into value */
+ if ((val = cupsGetOption("Duplex",
+ data->num_options, data->options)) != NULL)
+ return (strncasecmp(val, "Duplex", 6) == 0);
+ else if ((val = cupsGetOption("sides",
+ data->num_options, data->options)) != NULL)
+ return (strncasecmp(val, "two-sided-", 10) == 0);
+ else if ((val = cfIPPAttrEnumValForPrinter(data->printer_attrs,
+ data->job_attrs,
+ "sides")) != NULL)
+ return (strncasecmp(val, "two-sided-", 10) == 0);
+ else if (data->header)
+ return (data->header->Duplex);
+ return (0);
}
static void info_linef(FILE *s,
const char *jobid,
const char *user,
const char *jobtitle,
- int noptions,
+ int num_options,
cups_option_t *options)
{
- ppd_file_t *ppd = data->ppd;
- ppd_attr_t *attr;
cf_opt_t *opt = NULL;
ipp_t *printer_attrs = data->printer_attrs;
ipp_attribute_t *ipp_attr;
/* Printer info */
if ((value = cupsGetOption("printer-info",
- noptions, options)) == NULL || !value[0])
+ num_options, options)) == NULL || !value[0])
value = getenv("PRINTER_INFO");
opt = add_opt(opt, "printer-info", value);
/* Time at creation */
opt = add_opt(opt, "time-at-creation",
- human_time(cupsGetOption("time-at-creation", noptions, options)));
+ human_time(cupsGetOption("time-at-creation", num_options, options)));
/* Processing time */
opt = add_opt(opt, "time-at-processing",
- human_time(cupsGetOption("time-at-processing", noptions, options)));
+ human_time(cupsGetOption("time-at-processing", num_options, options)));
/* Billing information */
opt = add_opt(opt, "job-billing",
- cupsGetOption("job-billing", noptions, options));
+ cupsGetOption("job-billing", num_options, options));
/* Source hostname */
opt = add_opt(opt, "job-originating-host-name",
- cupsGetOption("job-originating-host-name", noptions, options));
+ cupsGetOption("job-originating-host-name", num_options, options));
/* Banner font */
opt = add_opt(opt, "banner-font",
- cupsGetOption("banner-font", noptions, options));
+ cupsGetOption("banner-font", num_options, options));
/* Banner font size */
opt = add_opt(opt, "banner-font-size",
- cupsGetOption("banner-font-size", noptions, options));
+ cupsGetOption("banner-font-size", num_options, options));
/* Job UUID */
opt = add_opt(opt, "job-uuid",
- cupsGetOption("job-uuid", noptions, options));
+ cupsGetOption("job-uuid", num_options, options));
/* Security context */
opt = add_opt(opt, "security-context",
- cupsGetOption("security-context", noptions, options));
+ cupsGetOption("security-context", num_options, options));
/* Security context range part */
opt = add_opt(opt, "security-context-range",
- cupsGetOption("security-context-range", noptions, options));
+ cupsGetOption("security-context-range", num_options, options));
/* Security context current range part */
- const char *full_range = cupsGetOption("security-context-range", noptions, options);
+ const char *full_range = cupsGetOption("security-context-range", num_options, options);
if (full_range)
{
size_t cur_size = strcspn(full_range, "-");
/* Security context type part */
opt = add_opt(opt, "security-context-type",
- cupsGetOption("security-context-type", noptions, options));
+ cupsGetOption("security-context-type", num_options, options));
/* Security context role part */
opt = add_opt(opt, "security-context-role",
- cupsGetOption("security-context-role", noptions, options));
+ cupsGetOption("security-context-role", num_options, options));
/* Security context user part */
opt = add_opt(opt, "security-context-user",
- cupsGetOption("security-context-user", noptions, options));
+ cupsGetOption("security-context-user", num_options, options));
- if (ppd)
- {
- /* Driver */
- opt = add_opt(opt, "driver", ppd->pcfilename);
-
- /* Driver version */
- opt = add_opt(opt, "driver-version",
- (attr = ppdFindAttr(ppd, "FileVersion", NULL)) ? attr->value : "");
+#if 0
+ /* Driver */
+ opt = add_opt(opt, "driver", "driverless");
- /* Make and model */
- opt = add_opt(opt, "make-and-model", ppd->nickname);
- }
- else
- {
- /* Driver */
- opt = add_opt(opt, "driver", "drvless.ppd");
-
- /* Driver version */
- opt = add_opt(opt, "driver-version", VERSION);
-
- /* Make and model */
- int is_fax = 0;
- char make[256];
- char *model;
- if ((ipp_attr = ippFindAttribute(printer_attrs, "ipp-features-supported",
- IPP_TAG_ZERO)) != NULL &&
- ippContainsString(ipp_attr, "faxout"))
- {
- ipp_attr = ippFindAttribute(printer_attrs, "printer-uri-supported",
- IPP_TAG_ZERO);
- if (ipp_attr)
- {
- ippAttributeString(ipp_attr, buf, sizeof(buf));
- if (strcasestr(buf, "faxout"))
- is_fax = 1;
- }
- }
+ /* Driver version */
+ opt = add_opt(opt, "driver-version", VERSION);
+#endif
- if ((ipp_attr = ippFindAttribute(printer_attrs, "printer-make-and-model",
- IPP_TAG_ZERO)) != NULL)
- snprintf(make, sizeof(make), "%s", ippGetString(ipp_attr, 0, NULL));
- else
- snprintf(make, sizeof(make), "%s", "Unknown Printer");
- if (!strncasecmp(make, "Hewlett Packard ", 16) ||
- !strncasecmp(make, "Hewlett-Packard ", 16)) {
- model = make + 16;
- snprintf(make, sizeof(make), "%s", "HP");
- }
- else if ((model = strchr(make, ' ')) != NULL)
- *model++ = '\0';
- else
- model = make;
- snprintf(buf, sizeof(buf), "%s %s, %sdriverless, cups-filters %s",
- make, model, (is_fax ? "Fax, " : ""), VERSION);
- char *nickname = buf;
- opt = add_opt(opt, "make-and-model", nickname);
+ /* Make and model */
+ int is_fax = 0;
+ char make[256];
+ char *model;
+ if ((ipp_attr = ippFindAttribute(printer_attrs, "ipp-features-supported",
+ IPP_TAG_ZERO)) != NULL &&
+ ippContainsString(ipp_attr, "faxout"))
+ {
+ ipp_attr = ippFindAttribute(printer_attrs, "printer-uri-supported",
+ IPP_TAG_ZERO);
+ if (ipp_attr)
+ {
+ ippAttributeString(ipp_attr, buf, sizeof(buf));
+ if (strcasestr(buf, "faxout"))
+ is_fax = 1;
+ }
}
+ if ((ipp_attr = ippFindAttribute(printer_attrs, "printer-info",
+ IPP_TAG_ZERO)) != NULL ||
+ (ipp_attr = ippFindAttribute(printer_attrs, "printer-make-and-model",
+ IPP_TAG_ZERO)) != NULL)
+ snprintf(make, sizeof(make), "%s", ippGetString(ipp_attr, 0, NULL));
+ else
+ snprintf(make, sizeof(make), "%s", "Unknown Printer");
+ if (!strncasecmp(make, "Hewlett Packard ", 16) ||
+ !strncasecmp(make, "Hewlett-Packard ", 16)) {
+ model = make + 16;
+ snprintf(make, sizeof(make), "%s", "HP");
+ }
+ else if ((model = strchr(make, ' ')) != NULL)
+ *model++ = '\0';
+ else
+ model = make;
+ snprintf(buf, sizeof(buf), "%s %s%s",
+ make, model, (is_fax ? ", Fax" : ""));
+ char *nickname = buf;
+ opt = add_opt(opt, "make-and-model", nickname);
return opt;
}
const char *jobid,
const char *user,
const char *jobtitle,
- int noptions,
+ int num_options,
cups_option_t *options,
cf_logfunc_t log,
void *ld,
size_t len;
FILE *s;
cf_pdf_t *doc;
- float page_width, page_length;
+ float page_width = 0.0, page_length = 0.0;
float media_limits[4];
float page_scale;
- ppd_attr_t *attr;
unsigned copies;
ipp_t *printer_attrs = data->printer_attrs;
ipp_attribute_t *ipp_attr;
- ppd_file_t *ppd = data->ppd;
char buf2[1024];
const char *value;
#ifndef HAVE_OPEN_MEMSTREAM
return (1);
}
- get_pagesize(data, noptions, options,
- &page_width, &page_length, media_limits);
+ memset(media_limits, 0, sizeof(media_limits));
+ if (data != NULL && (data->printer_attrs) != NULL)
+ {
+ cfGetPageDimensions(data->printer_attrs, data->job_attrs,
+ num_options, options,
+ data->header, 0,
+ &(page_width), &(page_length),
+ &(media_limits[0]), &(media_limits[1]),
+ &(media_limits[2]), &(media_limits[3]),
+ NULL, NULL);
+ media_limits[2] = page_width - media_limits[2];
+ media_limits[3] = page_length - media_limits[3];
+ }
if (cfPDFResizePage(doc, 1, page_width, page_length, &page_scale) != 0)
{
fprintf(s, "17 TL\n");
if ((banner->infos & INFO_PRINTER_NAME) &&
- data->printer && data->printer[0])
+ data->printer && data->printer[0] && data->printer[0] != '/')
info_line(s, "Printer", data->printer);
if ((banner->infos & INFO_PRINTER_INFO) &&
(((value = cupsGetOption("printer-info",
- noptions, options)) != NULL && value[0]) ||
+ num_options, options)) != NULL && value[0]) ||
((value = getenv("PRINTER_INFO")) != NULL && value[0])))
info_line(s, "Description", value);
if ((banner->infos & INFO_PRINTER_LOCATION) &&
(((value = cupsGetOption("printer-location",
- noptions, options)) != NULL && value[0]) ||
+ num_options, options)) != NULL && value[0]) ||
((value = getenv("PRINTER_LOCATION")) != NULL && value[0])))
info_line(s, "Location", value);
if ((banner->infos & INFO_JOB_ID) &&
- data->printer && data->printer[0] && jobid && jobid[0])
+ data->printer && data->printer[0] && data->printer[0] != '/' &&
+ jobid && jobid[0])
info_linef(s, "Job ID", "%s-%s", data->printer, jobid);
if ((banner->infos & INFO_JOB_NAME) && jobtitle && jobtitle[0])
if ((banner->infos & INFO_JOB_ORIGINATING_HOST_NAME) &&
(value = cupsGetOption("job-originating-host-name",
- noptions, options)) != NULL && value[0])
+ num_options, options)) != NULL && value[0])
info_line(s, "Printed from", value);
if ((banner->infos & INFO_JOB_ORIGINATING_USER_NAME) && user && user[0])
if ((banner->infos & INFO_TIME_AT_CREATION) &&
(value =
- cupsGetOption("time-at-creation", noptions, options)) != NULL &&
+ cupsGetOption("time-at-creation", num_options, options)) != NULL &&
value[0])
info_line_time(s, "Created at", value);
if ((banner->infos & INFO_TIME_AT_PROCESSING) &&
(value =
- cupsGetOption("time-at-processing", noptions, options)) != NULL &&
+ cupsGetOption("time-at-processing", num_options, options)) != NULL &&
value[0])
info_line_time(s, "Printed at", value);
if ((banner->infos & INFO_JOB_BILLING) &&
- (value = cupsGetOption("job-billing", noptions, options)) != NULL &&
+ (value = cupsGetOption("job-billing", num_options, options)) != NULL &&
value[0])
info_line(s, "Billing Information\n", value);
if ((banner->infos & INFO_JOB_UUID) &&
- (value = cupsGetOption("job-uuid", noptions, options)) != NULL &&
+ (value = cupsGetOption("job-uuid", num_options, options)) != NULL &&
value[0])
info_line(s, "Job UUID", value);
- if (ppd)
- {
- if ((banner->infos & INFO_PRINTER_DRIVER_NAME) ||
- (banner->infos & INFO_PRINTER_MAKE_AND_MODEL))
- info_line(s, "Driver/Model", ppd->nickname);
-
- if ((banner->infos & INFO_PRINTER_DRIVER_VERSION) &&
- (attr = ppdFindAttr(ppd, "FileVersion", NULL)) != NULL &&
- attr->value && attr->value[0])
- info_line(s, "Driver Version", attr->value);
- }
- else if ((banner->infos & INFO_PRINTER_DRIVER_NAME) ||
- (banner->infos & INFO_PRINTER_MAKE_AND_MODEL))
+ if ((banner->infos & INFO_PRINTER_DRIVER_NAME) ||
+ (banner->infos & INFO_PRINTER_MAKE_AND_MODEL))
{
int is_fax = 0;
}
if ((ipp_attr = ippFindAttribute(printer_attrs,
+ "printer-info",
+ IPP_TAG_ZERO)) != NULL ||
+ (ipp_attr = ippFindAttribute(printer_attrs,
"printer-make-and-model",
IPP_TAG_ZERO)) != NULL)
{
jobid,
user,
jobtitle,
- noptions,
+ num_options,
options);
/*
}
}
- copies = get_int_option("number-up", noptions, options, 1);
+ copies = get_int_option("number-up", num_options, options, 1);
- if (duplex_marked(ppd, noptions, options))
+ if (duplex_marked(data))
copies *= 2;
if (copies > 1)
--- /dev/null
+ /***
+ This file is part of cups-filters.
+
+ This file is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of the
+ License, or (at your option) any later version.
+
+ This file 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 Lesser General
+ Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with avahi; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ USA.
+***/
+
+/*
+ * Include necessary headers.
+ */
+
+#include <config.h>
+
+#include <ctype.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <stdio.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <cups/cups.h>
+#include <cups/backend.h>
+#include <cups/dir.h>
+#include <cups/pwg.h>
+#include <cupsfilters/catalog.h>
+
+
+int /* O - 1 on success, 0 on failure */
+cfGetURI(const char *url, /* I - URL to get */
+ char *name, /* I - Temporary filename */
+ size_t namesize) /* I - Size of temporary filename
+ buffer */
+{
+ http_t *http = NULL;
+ char scheme[32], /* URL scheme */
+ userpass[256], /* URL username:password */
+ host[256], /* URL host */
+ resource[256]; /* URL resource */
+ int port; /* URL port */
+ http_encryption_t encryption; /* Type of encryption to use */
+ http_status_t status; /* Status of GET request */
+ int fd; /* Temporary file */
+
+
+ if (httpSeparateURI(HTTP_URI_CODING_ALL, url, scheme, sizeof(scheme),
+ userpass, sizeof(userpass), host, sizeof(host), &port,
+ resource, sizeof(resource)) < HTTP_URI_STATUS_OK)
+ return (0);
+
+ if (port == 443 || !strcmp(scheme, "https"))
+ encryption = HTTP_ENCRYPTION_ALWAYS;
+ else
+ encryption = HTTP_ENCRYPTION_IF_REQUESTED;
+
+ http = httpConnect2(host, port, NULL, AF_UNSPEC, encryption, 1, 5000, NULL);
+
+ if (!http)
+ return (0);
+
+ if ((fd = cupsTempFd(name, (int)namesize)) < 0)
+ return (0);
+
+ status = cupsGetFd(http, resource, fd);
+
+ close(fd);
+ httpClose(http);
+
+ if (status != HTTP_STATUS_OK) {
+ unlink(name);
+ *name = '\0';
+ return (0);
+ }
+
+ return (1);
+}
+
+
+/*
+ * 'cfCatalogFind()' - Find a CUPS message catalog file containing
+ * human-readable standard option and choice names
+ * for IPP printers
+ */
+
+const char *
+cfCatalogSearchDir(const char *dirname)
+{
+ const char *catalog = NULL, *c1, *c2;
+ cups_dir_t *dir = NULL, *subdir;
+ cups_dentry_t *subdirentry, *catalogentry;
+ char subdirpath[1024], catalogpath[2048], lang[8];
+ int i;
+
+ if (dirname == NULL)
+ return NULL;
+
+ /* Check first whether we have an English file and prefer this */
+ snprintf(catalogpath, sizeof(catalogpath), "%s/en/cups_en.po", dirname);
+ if (access(catalogpath, R_OK) == 0) {
+ /* Found */
+ catalog = strdup(catalogpath);
+ return catalog;
+ }
+
+ if ((dir = cupsDirOpen(dirname)) == NULL)
+ return NULL;
+
+ while ((subdirentry = cupsDirRead(dir)) != NULL) {
+ /* Do we actually have a subdir? */
+ if (!S_ISDIR(subdirentry->fileinfo.st_mode))
+ continue;
+ /* Check format of subdir name */
+ c1 = subdirentry->filename;
+ if (c1[0] < 'a' || c1[0] > 'z' || c1[1] < 'a' || c1[1] > 'z')
+ continue;
+ if (c1[2] >= 'a' && c1[2] <= 'z')
+ i = 3;
+ else
+ i = 2;
+ if (c1[i] == '_') {
+ i ++;
+ if (c1[i] < 'A' || c1[i] > 'Z' || c1[i+1] < 'A' || c1[i+1] > 'Z')
+ continue;
+ i += 2;
+ if (c1[i] >= 'A' && c1[i] <= 'Z')
+ i ++;
+ }
+ if (c1[i] != '\0' && c1[i] != '@')
+ continue;
+ strncpy(lang, c1, i);
+ lang[i] = '\0';
+ snprintf(subdirpath, sizeof(subdirpath), "%s/%s", dirname, c1);
+ if ((subdir = cupsDirOpen(subdirpath)) != NULL) {
+ while ((catalogentry = cupsDirRead(subdir)) != NULL) {
+ /* Do we actually have a regular file? */
+ if (!S_ISREG(catalogentry->fileinfo.st_mode))
+ continue;
+ /* Check format of catalog name */
+ c2 = catalogentry->filename;
+ if (strlen(c2) < 10 || strncmp(c2, "cups_", 5) != 0 ||
+ strncmp(c2 + 5, lang, i) != 0 ||
+ strcmp(c2 + strlen(c2) - 3, ".po"))
+ continue;
+ /* Is catalog readable ? */
+ snprintf(catalogpath, sizeof(catalogpath), "%s/%s", subdirpath, c2);
+ if (access(catalogpath, R_OK) != 0)
+ continue;
+ /* Found */
+ catalog = strdup(catalogpath);
+ break;
+ }
+ cupsDirClose(subdir);
+ subdir = NULL;
+ if (catalog != NULL)
+ break;
+ }
+ }
+
+ cupsDirClose(dir);
+ return catalog;
+}
+
+
+const char *
+cfCatalogFind(const char *preferreddir)
+{
+ const char *catalog = NULL, *c;
+ char buf[1024];
+
+ /* Directory supplied by calling program, from config file,
+ environment variable, ... */
+ if ((catalog = cfCatalogSearchDir(preferreddir)) != NULL)
+ goto found;
+
+ /* Directory supplied by environment variable CUPS_LOCALEDIR */
+ if ((catalog = cfCatalogSearchDir(getenv("CUPS_LOCALEDIR"))) != NULL)
+ goto found;
+
+ /* Determine CUPS datadir (usually /usr/share/cups) */
+ if ((c = getenv("CUPS_DATADIR")) == NULL)
+ c = CUPS_DATADIR;
+
+ /* Search /usr/share/cups/locale/ (location which
+ Debian/Ubuntu package of CUPS is using) */
+ snprintf(buf, sizeof(buf), "%s/locale", c);
+ if ((catalog = cfCatalogSearchDir(buf)) != NULL)
+ goto found;
+
+ /* Search /usr/(local/)share/locale/ (standard location
+ which CUPS is using on Linux) */
+ snprintf(buf, sizeof(buf), "%s/../locale", c);
+ if ((catalog = cfCatalogSearchDir(buf)) != NULL)
+ goto found;
+
+ /* Search /usr/(local/)lib/locale/ (standard location
+ which CUPS is using on many non-Linux systems) */
+ snprintf(buf, sizeof(buf), "%s/../../lib/locale", c);
+ if ((catalog = cfCatalogSearchDir(buf)) != NULL)
+ goto found;
+
+ found:
+ return catalog;
+}
+
+
+static int
+compare_choices(void *a,
+ void *b,
+ void *user_data)
+{
+ return strcasecmp(((catalog_choice_strings_t *)a)->name,
+ ((catalog_choice_strings_t *)b)->name);
+}
+
+
+static int
+compare_options(void *a,
+ void *b,
+ void *user_data)
+{
+ return strcasecmp(((catalog_opt_strings_t *)a)->name,
+ ((catalog_opt_strings_t *)b)->name);
+}
+
+
+void
+cfCatalogFreeChoiceStrings(void* entry,
+ void* user_data)
+{
+ catalog_choice_strings_t *entry_rec = (catalog_choice_strings_t *)entry;
+
+ if (entry_rec) {
+ if (entry_rec->name) free(entry_rec->name);
+ if (entry_rec->human_readable) free(entry_rec->human_readable);
+ free(entry_rec);
+ }
+}
+
+
+void
+cfCatalogFreeOptionStrings(void* entry,
+ void* user_data)
+{
+ catalog_opt_strings_t *entry_rec = (catalog_opt_strings_t *)entry;
+
+ if (entry_rec) {
+ if (entry_rec->name) free(entry_rec->name);
+ if (entry_rec->human_readable) free(entry_rec->human_readable);
+ if (entry_rec->choices) cupsArrayDelete(entry_rec->choices);
+ free(entry_rec);
+ }
+}
+
+
+cups_array_t *
+cfCatalogOptionArrayNew()
+{
+ return cupsArrayNew3(compare_options, NULL, NULL, 0,
+ NULL, cfCatalogFreeOptionStrings);
+}
+
+
+catalog_opt_strings_t *
+cfCatalogFindOption(cups_array_t *options,
+ char *name)
+{
+ catalog_opt_strings_t opt;
+
+ if (!name || !options)
+ return NULL;
+
+ opt.name = name;
+ return cupsArrayFind(options, &opt);
+}
+
+
+catalog_choice_strings_t *
+cfCatalogFindChoice(cups_array_t *choices,
+ char *name)
+{
+ catalog_choice_strings_t choice;
+
+ if (!name || !choices)
+ return NULL;
+
+ choice.name = name;
+ return cupsArrayFind(choices, &choice);
+}
+
+
+catalog_opt_strings_t *
+cfCatalogAddOption(char *name,
+ char *human_readable,
+ cups_array_t *options)
+{
+ catalog_opt_strings_t *opt = NULL;
+
+ if (!name || !options)
+ return NULL;
+
+ if ((opt = cfCatalogFindOption(options, name)) == NULL) {
+ opt = calloc(1, sizeof(catalog_opt_strings_t));
+ if (!opt) return NULL;
+ opt->human_readable = NULL;
+ opt->choices = cupsArrayNew3(compare_choices, NULL, NULL, 0,
+ NULL, cfCatalogFreeChoiceStrings);
+ if (!opt->choices) {
+ free(opt);
+ return NULL;
+ }
+ opt->name = strdup(name);
+ if (!cupsArrayAdd(options, opt)) {
+ cfCatalogFreeOptionStrings(opt, NULL);
+ return NULL;
+ }
+ }
+
+ if (human_readable)
+ opt->human_readable = strdup(human_readable);
+
+ return opt;
+}
+
+
+catalog_choice_strings_t *
+cfCatalogAddChoice(char *name,
+ char *human_readable,
+ char *opt_name,
+ cups_array_t *options)
+{
+ catalog_choice_strings_t *choice = NULL;
+ catalog_opt_strings_t *opt;
+
+ if (!name || !human_readable || !opt_name || !options)
+ return NULL;
+
+ opt = cfCatalogAddOption(opt_name, NULL, options);
+ if (!opt) return NULL;
+
+ if ((choice = cfCatalogFindChoice(opt->choices, name)) == NULL) {
+ choice = calloc(1, sizeof(catalog_choice_strings_t));
+ if (!choice) return NULL;
+ choice->human_readable = NULL;
+ choice->name = strdup(name);
+ if (!cupsArrayAdd(opt->choices, choice)) {
+ cfCatalogFreeChoiceStrings(choice, NULL);
+ return NULL;
+ }
+ }
+
+ if (human_readable)
+ choice->human_readable = strdup(human_readable);
+
+ return choice;
+
+}
+
+
+char *
+cfCatalogLookUpOption(char *name,
+ cups_array_t *options,
+ cups_array_t *printer_options)
+{
+ catalog_opt_strings_t *opt = NULL;
+
+ if (!name || !options)
+ return NULL;
+
+ if (printer_options &&
+ (opt = cfCatalogFindOption(printer_options, name)) != NULL)
+ return opt->human_readable;
+ if ((opt = cfCatalogFindOption(options, name)) != NULL)
+ return opt->human_readable;
+ else
+ return NULL;
+}
+
+
+char *
+cfCatalogLookUpChoice(char *name,
+ char *opt_name,
+ cups_array_t *options,
+ cups_array_t *printer_options)
+{
+ catalog_opt_strings_t *opt = NULL;
+ catalog_choice_strings_t *choice = NULL;
+
+ if (!name || !opt_name || !options)
+ return NULL;
+
+ if (printer_options &&
+ (opt = cfCatalogFindOption(printer_options, opt_name)) != NULL &&
+ (choice = cfCatalogFindChoice(opt->choices, name)) != NULL)
+ return choice->human_readable;
+ else if ((opt = cfCatalogFindOption(options, opt_name)) != NULL &&
+ (choice = cfCatalogFindChoice(opt->choices, name)) != NULL)
+ return choice->human_readable;
+ else
+ return NULL;
+}
+
+
+void
+cfCatalogLoad(const char *location,
+ cups_array_t *options)
+{
+ char tmpfile[1024];
+ const char *filename = NULL;
+ struct stat statbuf;
+ cups_file_t *fp;
+ char line[65536];
+ char *ptr, *start, *start2, *end, *end2, *sep;
+ char *opt_name = NULL, *choice_name = NULL,
+ *human_readable = NULL;
+ int part = -1; /* -1: before first "msgid" or invalid
+ line
+ 0: "msgid"
+ 1: "msgstr"
+ 2: "..." = "..."
+ 10: EOF, save last entry */
+ int digit;
+ int found_in_catalog = 0;
+
+ if (location == NULL || (strncasecmp(location, "http:", 5) &&
+ strncasecmp(location, "https:", 6))) {
+ if (location == NULL ||
+ (stat(location, &statbuf) == 0 &&
+ S_ISDIR(statbuf.st_mode))) /* directory? */
+ {
+ filename = cfCatalogFind(location);
+ if (filename)
+ found_in_catalog = 1;
+ }
+ else
+ filename = location;
+ } else {
+ if (cfGetURI(location, tmpfile, sizeof(tmpfile)))
+ filename = tmpfile;
+ }
+ if (!filename)
+ return;
+
+ if ((fp = cupsFileOpen(filename, "r")) == NULL)
+ {
+ if (filename == tmpfile)
+ unlink(filename);
+ return;
+ }
+
+ while (cupsFileGets(fp, line, sizeof(line)) || (part = 10)) {
+ /* Find a pair of quotes delimiting a string in each line
+ and optional "msgid" or "msgstr" keywords, or a
+ "..." = "..." pair. Skip comments ('#') and empty lines. */
+ if (part < 10) {
+ ptr = line;
+ while (isspace(*ptr)) ptr ++;
+ if (*ptr == '#' || *ptr == '\0') continue;
+ if ((start = strchr(ptr, '\"')) == NULL) continue;
+ if ((end = strrchr(ptr, '\"')) == start) continue;
+ if (*(end - 1) == '\\') continue;
+ start2 = NULL;
+ end2 = NULL;
+ if (start > ptr) {
+ if (*(start - 1) == '\\') continue;
+ if (strncasecmp(ptr, "msgid", 5) == 0) part = 0;
+ if (strncasecmp(ptr, "msgstr", 6) == 0) part = 1;
+ } else {
+ start2 = ptr;
+ while ((start2 = strchr(start2 + 1, '\"')) < end &&
+ *(start2 - 1) == '\\');
+ if (start2 < end) {
+ /* Line with "..." = "..." of text/strings format */
+ end2 = end;
+ end = start2;
+ start2 ++;
+ while (isspace(*start2)) start2 ++;
+ if (*start2 != '=') continue;
+ start2 ++;
+ while (isspace(*start2)) start2 ++;
+ if (*start2 != '\"') continue;
+ start2 ++;
+ *end2 = '\0';
+ part = 2;
+ } else
+ /* Continuation line in message catalog file */
+ start2 = NULL;
+ }
+ start ++;
+ *end = '\0';
+ }
+ /* Read out the strings between the quotes and save entries */
+ if (part == 0 || part == 2 || part == 10) {
+ /* Save previous attribute */
+ if (human_readable) {
+ if (opt_name) {
+ if (choice_name) {
+ cfCatalogAddChoice(choice_name, human_readable,
+ opt_name, options);
+ free(choice_name);
+ } else
+ cfCatalogAddOption(opt_name, human_readable, options);
+ free(opt_name);
+ }
+ free(human_readable);
+ opt_name = NULL;
+ choice_name = NULL;
+ human_readable = NULL;
+ }
+ /* Stop the loop after saving the last entry */
+ if (part == 10)
+ break;
+ /* IPP attribute has to be defined with a single msgid line,
+ no continuation lines */
+ if (opt_name) {
+ free (opt_name);
+ opt_name = NULL;
+ if (choice_name) {
+ free (choice_name);
+ choice_name = NULL;
+ }
+ part = -1;
+ continue;
+ }
+ /* No continuation line in text/strings format */
+ if (part == 2 && (start2 == NULL || end2 == NULL)) {
+ part = -1;
+ continue;
+ }
+ /* Check line if it is a valid IPP attribute:
+ No spaces, only lowercase letters, digits, '-', '_',
+ "option" or "option.choice" */
+ for (ptr = start, sep = NULL; ptr < end; ptr ++)
+ if (*ptr == '.') { /* Separator between option and choice */
+ if (!sep) { /* Only the first '.' counts */
+ sep = ptr + 1;
+ *ptr = '\0';
+ }
+ } else if (!((*ptr >= 'a' && *ptr <= 'z') ||
+ (*ptr >= '0' && *ptr <= '9') ||
+ *ptr == '-' || *ptr == '_'))
+ break;
+ if (ptr < end) { /* Illegal character found */
+ part = -1;
+ continue;
+ }
+ if (strlen(start) > 0) /* Option name found */
+ opt_name = strdup(start);
+ else { /* Empty option name */
+ part = -1;
+ continue;
+ }
+ if (sep && strlen(sep) > 0) /* Choice name found */
+ choice_name = strdup(sep);
+ else /* Empty choice name */
+ choice_name = NULL;
+ if (part == 2) { /* Human-readable string in the same line */
+ start = start2;
+ end = end2;
+ }
+ }
+ if (part == 1 || part == 2) {
+ /* msgid was not for an IPP attribute, ignore this msgstr */
+ if (!opt_name) continue;
+ /* Empty string */
+ if (start == end) continue;
+ /* Unquote string */
+ ptr = start;
+ end = start;
+ while (*ptr) {
+ if (*ptr == '\\') {
+ ptr ++;
+ if (isdigit(*ptr)) {
+ digit = 0;
+ *end = 0;
+ while (isdigit(*ptr) && digit < 3) {
+ *end = *end * 8 + *ptr - '0';
+ digit ++;
+ ptr ++;
+ }
+ end ++;
+ } else {
+ if (*ptr == 'n')
+ *end ++ = '\n';
+ else if (*ptr == 'r')
+ *end ++ = '\r';
+ else if (*ptr == 't')
+ *end ++ = '\t';
+ else
+ *end ++ = *ptr;
+ ptr ++;
+ }
+ } else
+ *end ++ = *ptr ++;
+ }
+ *end = '\0';
+ /* Did the unquoting make the string empty? */
+ if (strlen(start) == 0) continue;
+ /* Add the string to our human-readable string */
+ if (human_readable) { /* Continuation line */
+ human_readable = realloc(human_readable,
+ sizeof(char) *
+ (strlen(human_readable) +
+ strlen(start) + 2));
+ ptr = human_readable + strlen(human_readable);
+ *ptr = ' ';
+ strncpy(ptr + 1, start,
+ sizeof(human_readable) - (ptr - human_readable) - 1);
+ } else /* First line */
+ human_readable = strdup(start);
+ }
+ }
+ cupsFileClose(fp);
+ if (choice_name != NULL)
+ free(choice_name);
+ if (opt_name != NULL)
+ free(opt_name);
+ if (filename == tmpfile)
+ unlink(filename);
+ if (found_in_catalog)
+ free((char *)filename);
+}
--- /dev/null
+ /***
+ This file is part of cups-filters.
+
+ This file is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of the
+ License, or (at your option) any later version.
+
+ This file 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 Lesser General
+ Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with avahi; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ USA.
+***/
+
+#ifndef _CUPS_FILTERS_CATALOG_H_
+# define _CUPS_FILTERS_CATALOG_H_
+
+# ifdef __cplusplus
+extern "C" {
+# endif /* __cplusplus */
+
+/*
+ * Include necessary headers...
+ */
+
+#include <config.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <math.h>
+
+#if defined(WIN32) || defined(__EMX__)
+# include <io.h>
+#else
+# include <unistd.h>
+# include <fcntl.h>
+#endif /* WIN32 || __EMX__ */
+
+#include <cups/cups.h>
+#include <cups/backend.h>
+#include <cups/raster.h>
+
+/* Data structure for IPP choice name and human-readable string */
+typedef struct catalog_choice_strings_s {
+ char *name, *human_readable;
+} catalog_choice_strings_t;
+
+/* Data structure for IPP option name, human-readable string, and choice list */
+typedef struct catalog_opt_strings_s {
+ char *name, *human_readable;
+ cups_array_t *choices;
+} catalog_opt_strings_t;
+
+
+/*
+ * Prototypes...
+ */
+
+int cfGetURI(const char *url, char *name, size_t namesize);
+const char *cfCatalogSearchDir(const char *dirname);
+const char *cfCatalogFind(const char *preferreddir);
+void cfCatalogFreeChoiceStrings(void* entry, void* user_data);
+void cfCatalogFreeOptionStrings(void* entry, void* user_data);
+cups_array_t *cfCatalogOptionArrayNew();
+catalog_opt_strings_t *cfCatalogFindOption(cups_array_t *options, char *name);
+catalog_choice_strings_t *cfCatalogFindChoice(cups_array_t *choices,
+ char *name);
+catalog_opt_strings_t *cfCatalogAddOption(char *name, char *human_readable,
+ cups_array_t *options);
+catalog_choice_strings_t *cfCatalogAddChoice(char *name, char *human_readable,
+ char *opt_name,
+ cups_array_t *options);
+char *cfCatalogLookUpOption(char *name, cups_array_t *options,
+ cups_array_t *printer_options);
+char *cfCatalogLookUpChoice(char *name, char *opt_name,
+ cups_array_t *options,
+ cups_array_t *printer_options);
+void cfCatalogLoad(const char *location, cups_array_t *options);
+
+
+# ifdef __cplusplus
+}
+# endif /* __cplusplus */
+
+#endif /* !_CUPS_FILTERS_CATALOG_H_ */
* cfCMYKDoCMYK() - Do a CMYK separation...
* cfCMYKDoGray() - Do a grayscale separation...
* cfCMYKDoRGB() - Do an sRGB separation...
- * cfCMYKLoad() - Load a CMYK color profile from PPD attributes.
* cfCMYKNew() - Create a new CMYK color separation.
* cfCMYKSetBlack() - Set the transition range for CMY to black.
* cfCMYKSetCurve() - Set a color transform curve using points.
}
-/*
- * 'cfCMYKLoad()' - Load a CMYK color profile from PPD attributes.
- */
-
-cf_cmyk_t * /* O - CMYK color separation */
-cfCMYKLoad(ppd_file_t *ppd, /* I - PPD file */
- const char *colormodel, /* I - ColorModel value */
- const char *media, /* I - MediaType value */
- const char *resolution, /* I - Resolution value */
- cf_logfunc_t log, /* I - Log function */
- void *ld) /* I - Log function data */
-{
- cf_cmyk_t *cmyk; /* CMYK color separation */
- char spec[PPD_MAX_NAME]; /* Profile name */
- ppd_attr_t *attr; /* Attribute from PPD file */
- int num_channels; /* Number of color components */
- float gamval, /* Gamma correction value */
- density, /* Density value */
- light, /* Light ink limit */
- dark, /* Light ink cut-off */
- lower, /* Start of black ink */
- upper; /* End of color ink */
- int num_xypoints; /* Number of X,Y points */
- float xypoints[100 * 2], /* X,Y points */
- *xyptr; /* Current X,Y point */
-
-
- /*
- * Range check input...
- */
-
- if (ppd == NULL || colormodel == NULL || resolution == NULL || media == NULL)
- return (NULL);
-
- /*
- * Find the following attributes:
- *
- * cupsAllGamma - Set default curve using gamma + density
- * cupsAllXY - Set default curve using XY points
- * cupsBlackGamma - Set black curve using gamma + density
- * cupsBlackGeneration - Set black generation
- * cupsBlackLightDark - Set black light/dark transition
- * cupsBlackXY - Set black curve using XY points
- * cupsCyanGamma - Set cyan curve using gamma + density
- * cupsCyanLightDark - Set cyan light/dark transition
- * cupsCyanXY - Set cyan curve using XY points
- * cupsInkChannels - Set number of color channels
- * cupsInkLimit - Set total ink limit
- * cupsLightBlackGamma - Set light black curve using gamma + density
- * cupsLightBlackXY - Set light black curve using XY points
- * cupsLightCyanGamma - Set light cyan curve using gamma + density
- * cupsLightCyanXY - Set light cyan curve using XY points
- * cupsLightMagentaGamma - Set light magenta curve using gamma + density
- * cupsLightMagentaXY - Set light magenta curve using XY points
- * cupsMagentaGamma - Set magenta curve using gamma + density
- * cupsMagentaLightDark - Set magenta light/dark transition
- * cupsMagentaXY - Set magenta curve using XY points
- * cupsYellowGamma - Set yellow curve using gamma + density
- * cupsYellowXY - Set yellow curve using XY points
- *
- * The only required attribute is cupsInkChannels.
- *
- * The *XY attributes have precedence over the *Gamma attributes, and
- * the *Light* attributes have precedence over the corresponding
- * *LightDark* attributes.
- */
-
- /*
- * Get the required cupsInkChannels attribute...
- */
-
- if ((attr = cfFindAttr(ppd, "cupsInkChannels", colormodel, media,
- resolution, spec, sizeof(spec), log, ld)) == NULL)
- return (NULL);
-
- num_channels = atoi(attr->value);
-
- if (num_channels < 1 || num_channels > 7 || num_channels == 5)
- return (NULL);
-
- if ((cmyk = cfCMYKNew(num_channels)) == NULL)
- return (NULL);
-
- /*
- * Get the optional cupsInkLimit attribute...
- */
-
- if ((attr = cfFindAttr(ppd, "cupsInkLimit", colormodel, media,
- resolution, spec, sizeof(spec), log, ld)) != NULL)
- cfCMYKSetInkLimit(cmyk, atof(attr->value));
-
- /*
- * Get the optional cupsBlackGeneration attribute...
- */
-
- if ((attr = cfFindAttr(ppd, "cupsBlackGeneration", colormodel, media,
- resolution, spec, sizeof(spec), log, ld)) != NULL)
- {
- if (sscanf(attr->value, "%f%f", &lower, &upper) == 2)
- cfCMYKSetBlack(cmyk, lower, upper, log, ld);
- }
-
- /*
- * Get the optional cupsBlackXY or cupsBlackGamma attributes...
- */
-
- if (num_channels != 3)
- {
- if ((attr = cfFindAttr(ppd, "cupsBlackXY", colormodel, media,
- resolution, spec, sizeof(spec), log, ld)) != NULL)
- {
- for (num_xypoints = 0, xyptr = xypoints;
- attr != NULL && attr->value != NULL && num_xypoints < 100;
- attr = ppdFindNextAttr(ppd, "cupsBlackXY", spec))
- if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
- {
- num_xypoints ++;
- xyptr += 2;
- }
-
- switch (num_channels)
- {
- case 1 :
- case 2 :
- cfCMYKSetCurve(cmyk, 0, num_xypoints, xypoints, log, ld);
- break;
- case 4 :
- cfCMYKSetCurve(cmyk, 3, num_xypoints, xypoints, log, ld);
- break;
- case 6 :
- case 7 :
- cfCMYKSetCurve(cmyk, 5, num_xypoints, xypoints, log, ld);
- break;
- }
- }
- else if ((attr = cfFindAttr(ppd, "cupsBlackGamma", colormodel,
- media, resolution, spec,
- sizeof(spec), log, ld)) != NULL)
- {
- if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
- switch (num_channels)
- {
- case 1 :
- case 2 :
- cfCMYKSetGamma(cmyk, 0, gamval, density, log, ld);
- break;
- case 4 :
- cfCMYKSetGamma(cmyk, 3, gamval, density, log, ld);
- break;
- case 6 :
- case 7 :
- cfCMYKSetGamma(cmyk, 5, gamval, density, log, ld);
- break;
- }
- }
- else if ((attr = cfFindAttr(ppd, "cupsAllXY", colormodel, media,
- resolution, spec, sizeof(spec), log, ld)) !=
- NULL)
- {
- for (num_xypoints = 0, xyptr = xypoints;
- attr != NULL && attr->value != NULL && num_xypoints < 100;
- attr = ppdFindNextAttr(ppd, "cupsAllXY", spec))
- if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
- {
- num_xypoints ++;
- xyptr += 2;
- }
-
- switch (num_channels)
- {
- case 1 :
- case 2 :
- cfCMYKSetCurve(cmyk, 0, num_xypoints, xypoints, log, ld);
- break;
- case 4 :
- cfCMYKSetCurve(cmyk, 3, num_xypoints, xypoints, log, ld);
- break;
- case 6 :
- case 7 :
- cfCMYKSetCurve(cmyk, 5, num_xypoints, xypoints, log, ld);
- break;
- }
- }
- else if ((attr = cfFindAttr(ppd, "cupsAllGamma", colormodel,
- media, resolution, spec,
- sizeof(spec), log, ld)) != NULL &&
- num_channels != 3)
- {
- if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
- switch (num_channels)
- {
- case 1 :
- case 2 :
- cfCMYKSetGamma(cmyk, 0, gamval, density, log, ld);
- break;
- case 4 :
- cfCMYKSetGamma(cmyk, 3, gamval, density, log, ld);
- break;
- case 6 :
- case 7 :
- cfCMYKSetGamma(cmyk, 5, gamval, density, log, ld);
- break;
- }
- }
- }
-
- if (num_channels > 2)
- {
- /*
- * Get the optional cupsCyanXY or cupsCyanGamma attributes...
- */
-
- if ((attr = cfFindAttr(ppd, "cupsCyanXY", colormodel, media,
- resolution, spec, sizeof(spec), log, ld)) != NULL)
- {
- for (num_xypoints = 0, xyptr = xypoints;
- attr != NULL && attr->value != NULL && num_xypoints < 100;
- attr = ppdFindNextAttr(ppd, "cupsCyanXY", spec))
- if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
- {
- num_xypoints ++;
- xyptr += 2;
- }
-
- cfCMYKSetCurve(cmyk, 0, num_xypoints, xypoints, log, ld);
- }
- else if ((attr = cfFindAttr(ppd, "cupsCyanGamma", colormodel, media,
- resolution, spec, sizeof(spec), log, ld)) !=
- NULL)
- {
- if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
- cfCMYKSetGamma(cmyk, 0, gamval, density, log, ld);
- }
- else if ((attr = cfFindAttr(ppd, "cupsAllXY", colormodel, media,
- resolution, spec, sizeof(spec), log, ld)) !=
- NULL)
- {
- for (num_xypoints = 0, xyptr = xypoints;
- attr != NULL && attr->value != NULL && num_xypoints < 100;
- attr = ppdFindNextAttr(ppd, "cupsAllXY", spec))
- if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
- {
- num_xypoints ++;
- xyptr += 2;
- }
-
- cfCMYKSetCurve(cmyk, 0, num_xypoints, xypoints, log, ld);
- }
- else if ((attr = cfFindAttr(ppd, "cupsAllGamma", colormodel, media,
- resolution, spec, sizeof(spec), log, ld)) !=
- NULL)
- {
- if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
- cfCMYKSetGamma(cmyk, 0, gamval, density, log, ld);
- }
-
- /*
- * Get the optional cupsMagentaXY or cupsMagentaGamma attributes...
- */
-
- if ((attr = cfFindAttr(ppd, "cupsMagentaXY", colormodel, media,
- resolution, spec, sizeof(spec), log, ld)) != NULL)
- {
- for (num_xypoints = 0, xyptr = xypoints;
- attr != NULL && attr->value != NULL && num_xypoints < 100;
- attr = ppdFindNextAttr(ppd, "cupsMagentaXY", spec))
- if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
- {
- num_xypoints ++;
- xyptr += 2;
- }
-
- switch (num_channels)
- {
- case 3 :
- case 4 :
- cfCMYKSetCurve(cmyk, 1, num_xypoints, xypoints, log, ld);
- break;
- case 6 :
- case 7 :
- cfCMYKSetCurve(cmyk, 2, num_xypoints, xypoints, log, ld);
- break;
- }
- }
- else if ((attr = cfFindAttr(ppd, "cupsMagentaGamma", colormodel, media,
- resolution, spec, sizeof(spec), log, ld)) !=
- NULL)
- {
- if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
- switch (num_channels)
- {
- case 3 :
- case 4 :
- cfCMYKSetGamma(cmyk, 1, gamval, density, log, ld);
- break;
- case 6 :
- case 7 :
- cfCMYKSetGamma(cmyk, 2, gamval, density, log, ld);
- break;
- }
- }
- else if ((attr = cfFindAttr(ppd, "cupsAllXY", colormodel, media,
- resolution, spec, sizeof(spec), log, ld)) !=
- NULL)
- {
- for (num_xypoints = 0, xyptr = xypoints;
- attr != NULL && attr->value != NULL && num_xypoints < 100;
- attr = ppdFindNextAttr(ppd, "cupsAllXY", spec))
- if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
- {
- num_xypoints ++;
- xyptr += 2;
- }
-
- switch (num_channels)
- {
- case 3 :
- case 4 :
- cfCMYKSetCurve(cmyk, 1, num_xypoints, xypoints, log, ld);
- break;
- case 6 :
- case 7 :
- cfCMYKSetCurve(cmyk, 2, num_xypoints, xypoints, log, ld);
- break;
- }
- }
- else if ((attr = cfFindAttr(ppd, "cupsAllGamma", colormodel, media,
- resolution, spec, sizeof(spec), log, ld)) !=
- NULL)
- {
- if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
- switch (num_channels)
- {
- case 3 :
- case 4 :
- cfCMYKSetGamma(cmyk, 1, gamval, density, log, ld);
- break;
- case 6 :
- case 7 :
- cfCMYKSetGamma(cmyk, 2, gamval, density, log, ld);
- break;
- }
- }
-
- /*
- * Get the optional cupsYellowXY or cupsYellowGamma attributes...
- */
-
- if ((attr = cfFindAttr(ppd, "cupsYellowXY", colormodel, media,
- resolution, spec, sizeof(spec), log, ld)) != NULL)
- {
- for (num_xypoints = 0, xyptr = xypoints;
- attr != NULL && attr->value != NULL && num_xypoints < 100;
- attr = ppdFindNextAttr(ppd, "cupsYellowXY", spec))
- if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
- {
- num_xypoints ++;
- xyptr += 2;
- }
-
- switch (num_channels)
- {
- case 3 :
- case 4 :
- cfCMYKSetCurve(cmyk, 2, num_xypoints, xypoints, log, ld);
- break;
- case 6 :
- case 7 :
- cfCMYKSetCurve(cmyk, 4, num_xypoints, xypoints, log, ld);
- break;
- }
- }
- else if ((attr = cfFindAttr(ppd, "cupsYellowGamma", colormodel, media,
- resolution, spec, sizeof(spec), log, ld)) !=
- NULL)
- {
- if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
- switch (num_channels)
- {
- case 3 :
- case 4 :
- cfCMYKSetGamma(cmyk, 2, gamval, density, log, ld);
- break;
- case 6 :
- case 7 :
- cfCMYKSetGamma(cmyk, 4, gamval, density, log, ld);
- break;
- }
- }
- else if ((attr = cfFindAttr(ppd, "cupsAllXY", colormodel, media,
- resolution, spec, sizeof(spec), log, ld)) !=
- NULL)
- {
- for (num_xypoints = 0, xyptr = xypoints;
- attr != NULL && attr->value != NULL && num_xypoints < 100;
- attr = ppdFindNextAttr(ppd, "cupsAllXY", spec))
- if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
- {
- num_xypoints ++;
- xyptr += 2;
- }
-
- switch (num_channels)
- {
- case 3 :
- case 4 :
- cfCMYKSetCurve(cmyk, 2, num_xypoints, xypoints, log, ld);
- break;
- case 6 :
- case 7 :
- cfCMYKSetCurve(cmyk, 4, num_xypoints, xypoints, log, ld);
- break;
- }
- }
- else if ((attr = cfFindAttr(ppd, "cupsAllGamma", colormodel, media,
- resolution, spec, sizeof(spec), log, ld)) !=
- NULL)
- {
- if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
- switch (num_channels)
- {
- case 3 :
- case 4 :
- cfCMYKSetGamma(cmyk, 2, gamval, density, log, ld);
- break;
- case 6 :
- case 7 :
- cfCMYKSetGamma(cmyk, 4, gamval, density, log, ld);
- break;
- }
- }
- }
-
- /*
- * Get the optional cupsLightBlackXY, cupsLightBlackGamma, or
- * cupsBlackLtDk attributes...
- */
-
- if (num_channels == 2 || num_channels == 7)
- {
- if ((attr = cfFindAttr(ppd, "cupsLightBlackXY", colormodel, media,
- resolution, spec, sizeof(spec), log, ld)) != NULL)
- {
- for (num_xypoints = 0, xyptr = xypoints;
- attr != NULL && attr->value != NULL && num_xypoints < 100;
- attr = ppdFindNextAttr(ppd, "cupsLightBlackXY", spec))
- if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
- {
- num_xypoints ++;
- xyptr += 2;
- }
-
- switch (num_channels)
- {
- case 2 :
- cfCMYKSetCurve(cmyk, 1, num_xypoints, xypoints, log, ld);
- break;
- case 7 :
- cfCMYKSetCurve(cmyk, 6, num_xypoints, xypoints, log, ld);
- break;
- }
- }
- else if ((attr = cfFindAttr(ppd, "cupsLightBlackGamma", colormodel,
- media, resolution, spec,
- sizeof(spec), log, ld)) != NULL)
- {
- if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
- switch (num_channels)
- {
- case 2 :
- cfCMYKSetGamma(cmyk, 1, gamval, density, log, ld);
- break;
- case 7 :
- cfCMYKSetGamma(cmyk, 6, gamval, density, log, ld);
- break;
- }
- }
- else if ((attr = cfFindAttr(ppd, "cupsBlackLtDk", colormodel, media,
- resolution, spec, sizeof(spec), log, ld)) !=
- NULL)
- {
- if (sscanf(attr->value, "%f%f", &light, &dark) == 2)
- switch (num_channels)
- {
- case 2 :
- cfCMYKSetLtDk(cmyk, 0, light, dark, log, ld);
- break;
- case 7 :
- cfCMYKSetLtDk(cmyk, 5, light, dark, log, ld);
- break;
- }
- else
- if (log) log(ld, CF_LOGLEVEL_ERROR,
- "Bad cupsBlackLtDk value \"%s\"!",
- attr->value);
- }
- else
- if (log) log(ld, CF_LOGLEVEL_WARN,
- "No light black attribute found for %s!",
- spec);
- }
-
- if (num_channels >= 6)
- {
- /*
- * Get the optional cupsLightCyanXY, cupsLightCyanGamma, or
- * cupsCyanLtDk attributes...
- */
-
- if ((attr = cfFindAttr(ppd, "cupsLightCyanXY", colormodel, media,
- resolution, spec, sizeof(spec), log, ld)) != NULL)
- {
- for (num_xypoints = 0, xyptr = xypoints;
- attr != NULL && attr->value != NULL && num_xypoints < 100;
- attr = ppdFindNextAttr(ppd, "cupsLightCyanXY", spec))
- if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
- {
- num_xypoints ++;
- xyptr += 2;
- }
-
- cfCMYKSetCurve(cmyk, 1, num_xypoints, xypoints, log, ld);
- }
- else if ((attr = cfFindAttr(ppd, "cupsLightCyanGamma", colormodel,
- media, resolution, spec,
- sizeof(spec), log, ld)) != NULL)
- {
- if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
- cfCMYKSetGamma(cmyk, 1, gamval, density, log, ld);
- }
- else if ((attr = cfFindAttr(ppd, "cupsCyanLtDk", colormodel, media,
- resolution, spec, sizeof(spec), log, ld)) !=
- NULL)
- {
- if (sscanf(attr->value, "%f%f", &light, &dark) == 2)
- cfCMYKSetLtDk(cmyk, 0, light, dark, log, ld);
- else
- if (log) log(ld, CF_LOGLEVEL_ERROR,
- "Bad cupsCyanLtDk value \"%s\"!",
- attr->value);
- }
- else
- if (log) log(ld, CF_LOGLEVEL_WARN,
- "No light cyan attribute found for %s!",
- spec);
-
- /*
- * Get the optional cupsLightMagentaXY, cupsLightMagentaGamma, or
- * cupsMagentaLtDk attributes...
- */
-
- if ((attr = cfFindAttr(ppd, "cupsLightMagentaXY", colormodel, media,
- resolution, spec, sizeof(spec), log, ld)) != NULL)
- {
- for (num_xypoints = 0, xyptr = xypoints;
- attr != NULL && attr->value != NULL && num_xypoints < 100;
- attr = ppdFindNextAttr(ppd, "cupsLightMagentaXY", spec))
- if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
- {
- num_xypoints ++;
- xyptr += 2;
- }
-
- cfCMYKSetCurve(cmyk, 3, num_xypoints, xypoints, log, ld);
- }
- else if ((attr = cfFindAttr(ppd, "cupsLightMagentaGamma", colormodel,
- media, resolution, spec,
- sizeof(spec), log, ld)) != NULL)
- {
- if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
- cfCMYKSetGamma(cmyk, 3, gamval, density, log, ld);
- }
- else if ((attr = cfFindAttr(ppd, "cupsMagentaLtDk", colormodel, media,
- resolution, spec, sizeof(spec), log, ld)) !=
- NULL)
- {
- if (sscanf(attr->value, "%f%f", &light, &dark) == 2)
- cfCMYKSetLtDk(cmyk, 2, light, dark, log, ld);
- else
- if (log) log(ld, CF_LOGLEVEL_ERROR,
- "Bad cupsMagentaLtDk value \"%s\"!",
- attr->value);
- }
- else
- if (log) log(ld, CF_LOGLEVEL_WARN,
- "No light magenta attribute found for %s!",
- spec);
- }
-
- /*
- * Return the new profile...
- */
-
- return (cmyk);
-}
-
-
/*
* 'cfCMYKNew()' - Create a new CMYK color separation.
*/
#include <stdio.h>
#include <sys/types.h>
#include <cupsfilters/filter.h>
+#include <cupsfilters/raster.h>
#ifdef HAVE_DBUS
#include <dbus/dbus.h>
#endif
#define QUAL_SIZE 3
char **
-cfColordGetQualifierForPPD (ppd_file_t *ppd)
+cfColordGetQualifier(cf_filter_data_t *data,
+ const char *color_space,
+ const char *media_type,
+ int x_res,
+ int y_res)
{
- char q_keyword[PPD_MAX_NAME];
+ int i, len;
+ const char *val;
+ const char *ptr1, *ptr2;
+ char buf[64];
char **tuple = NULL;
- const char *q1_choice;
- const char *q2_choice;
- const char *q3_choice;
- ppd_attr_t *attr;
- ppd_attr_t *q1_attr;
- ppd_attr_t *q2_attr;
- ppd_attr_t *q3_attr;
-
- /* get colorspace */
- if ((attr = ppdFindAttr (ppd, "cupsICCQualifier1", NULL)) != NULL &&
- attr->value && attr->value[0])
- {
- snprintf (q_keyword, sizeof (q_keyword), "Default%s", attr->value);
- q1_attr = ppdFindAttr (ppd, q_keyword, NULL);
- }
- else if ((q1_attr = ppdFindAttr (ppd, "DefaultColorModel", NULL)) == NULL)
- q1_attr = ppdFindAttr (ppd, "DefaultColorSpace", NULL);
+ int num_options = 0;
+ cups_option_t *options = NULL;
- if (q1_attr && q1_attr->value && q1_attr->value[0])
- q1_choice = q1_attr->value;
- else
- q1_choice = "";
- /* get media */
- if ((attr = ppdFindAttr(ppd, "cupsICCQualifier2", NULL)) != NULL &&
- attr->value && attr->value[0])
+ num_options = cfJoinJobOptionsAndAttrs(data, num_options, &options);
+
+ /* Get data from "cm-profile-qualifier" option */
+ if ((val =
+ cupsGetOption("cm-profile-qualifier",
+ data->num_options, data->options)) != NULL &&
+ val[0] != '\0')
{
- snprintf(q_keyword, sizeof(q_keyword), "Default%s", attr->value);
- q2_attr = ppdFindAttr(ppd, q_keyword, NULL);
+ tuple = calloc(QUAL_SIZE + 1, sizeof(char*));
+ ptr1 = ptr2 = val;
+ for (i = 0; i < QUAL_SIZE; i ++)
+ {
+ while (*ptr2 && *ptr2 != '.') ptr2 ++;
+ len = ptr2 - ptr1;
+ tuple[i] = malloc((len + 1) * sizeof(char));
+ memcpy(tuple[i], ptr1, len);
+ tuple[i][len] = '\0';
+ if (*ptr2)
+ ptr2 ++;
+ ptr1 = ptr2;
+ }
}
else
- q2_attr = ppdFindAttr(ppd, "DefaultMediaType", NULL);
-
- if (q2_attr && q2_attr->value && q2_attr->value[0])
- q2_choice = q2_attr->value;
- else
- q2_choice = "";
-
- /* get resolution */
- if ((attr = ppdFindAttr(ppd, "cupsICCQualifier3", NULL)) != NULL &&
- attr->value && attr->value[0])
{
- snprintf(q_keyword, sizeof(q_keyword), "Default%s", attr->value);
- q3_attr = ppdFindAttr(ppd, q_keyword, NULL);
+ /* String for resolution */
+ if (x_res <= 0)
+ buf[0] = '\0';
+ else if (y_res <= 0 || y_res == x_res)
+ snprintf(buf, sizeof(buf), "%ddpi", x_res);
+ else
+ snprintf(buf, sizeof(buf), "%dx%ddpi", x_res, y_res);
+
+ /* return a NULL terminated array so we don't have to break it up later */
+ tuple = calloc(QUAL_SIZE + 1, sizeof(char*));
+ tuple[QUAL_COLORSPACE] = strdup(color_space ? color_space : "");
+ tuple[QUAL_MEDIA] = strdup(media_type ? media_type : "");
+ tuple[QUAL_RESOLUTION] = strdup(buf);
}
- else
- q3_attr = ppdFindAttr(ppd, "DefaultResolution", NULL);
-
- if (q3_attr && q3_attr->value && q3_attr->value[0])
- q3_choice = q3_attr->value;
- else
- q3_choice = "";
+
+ cupsFreeOptions(num_options, options);
- /* return a NULL terminated array so we don't have to break it up later */
- tuple = calloc(QUAL_SIZE + 1, sizeof(char*));
- tuple[QUAL_COLORSPACE] = strdup(q1_choice);
- tuple[QUAL_MEDIA] = strdup(q2_choice);
- tuple[QUAL_RESOLUTION] = strdup(q3_choice);
return tuple;
}
#ifdef HAVE_DBUS
static char *
-get_filename_for_profile_path ( cf_filter_data_t *data,
- DBusConnection *con,
+get_filename_for_profile_path (cf_filter_data_t *data,
+ DBusConnection *con,
const char *object_path)
{
cf_logfunc_t log = data->logfunc;
/* Common routines for accessing the colord CMS framework */
#include <cups/raster.h>
-#include <ppd/ppd.h>
#include <cupsfilters/filter.h>
-char **cfColordGetQualifierForPPD(ppd_file_t *ppd);
+char **cfColordGetQualifier(cf_filter_data_t *data,
+ const char *color_space,
+ const char *media_type,
+ int x_res,
+ int y_res);
char *cfColordGetProfileForDeviceID(cf_filter_data_t *data,
const char *device_id,
const char **qualifier_tuple);
#include "colormanager.h"
#include <cupsfilters/colord.h>
#include <cupsfilters/filter.h>
+#include <cupsfilters/raster.h>
#define CM_MAX_FILE_LENGTH 1024
-/* Private function prototypes */
-static int get_colord_printer_cm_status (cf_filter_data_t *data);
-static char *get_colord_printer_id (cf_filter_data_t *data);
-static int get_colord_profile (cf_filter_data_t *data,
- char **profile,
- ppd_file_t *ppd);
-static char *get_ppd_icc_fallback (cf_filter_data_t *data,
- ppd_file_t *ppd,
- char **qualifier);
-
-
-
/* Commonly-used calibration numbers */
double adobergb_wp[3] = {0.95045471, 1.0, 1.08905029};
{
cf_logfunc_t log = data->logfunc;
void *ld = data->logdata;
- int is_cm_off = 0; /* color management status flag */
+ int is_printer_cm_disabled = 0; /* color management status flag */
+ char printer_id[CM_MAX_FILE_LENGTH] = ""; /* colord printer id */
+
+
+ /* If invalid input, we leave color management alone */
+ if (data->printer == NULL) {
+ if(log) log(ld, CF_LOGLEVEL_DEBUG,
+ "Color Manager: Invalid printer name.");
+ return 0;
+ }
+ /* Create printer id string for colord */
+ snprintf(printer_id, CM_MAX_FILE_LENGTH, "cups-%s", data->printer);
- /* Request color management status from colord */
- is_cm_off = get_colord_printer_cm_status(data);
+ /* Check if device is inhibited/disabled in colord */
+ is_printer_cm_disabled = cfColordGetInhibitForDeviceID (data, printer_id);
- if (is_cm_off)
+ if (is_printer_cm_disabled)
if(log) log(ld, CF_LOGLEVEL_DEBUG,
"Color Manager: Color management disabled by OS.");
- return is_cm_off;
-
+ return is_printer_cm_disabled;
}
/* Get printer ICC profile from the system's color manager */
int
cfCmGetPrinterIccProfile(cf_filter_data_t *data,
- char **icc_profile, /* ICC Profile Path */
- ppd_file_t *ppd) /* Optional PPD file for fallback profile */
+ const char *color_space,
+ const char *media_type,
+ int x_res,
+ int y_res,
+ char **profile) /* ICC Profile Path */
{
cf_logfunc_t log = data->logfunc;
void *ld = data->logdata;
- int profile_set = 0; /* 'is profile found' flag */
+ const char *val;
+ int is_profile_set = 0; /* profile-is-found flag */
+ char **qualifier = NULL; /* color qualifier strings */
+ char *icc_profile = NULL; /* icc profile path */
+ char printer_id[CM_MAX_FILE_LENGTH] = ""; /* colord printer id */
+ if (data->printer == NULL || profile == NULL) {
+ if(log) log(ld, CF_LOGLEVEL_DEBUG,
+ "Color Manager: Invalid input - Unable to find profile.");
+ return -1;
+ }
+
+ /* Get color qualifier triple */
+ qualifier = cfColordGetQualifier(data, color_space, media_type,
+ x_res, y_res);
- /* Request a profile from colord */
- profile_set = get_colord_profile(data, icc_profile, ppd);
- if(log) log(ld, CF_LOGLEVEL_DEBUG,
- "Color Manager: ICC Profile: %s", *icc_profile ?
- *icc_profile : "None");
+ if (qualifier != NULL) {
+ /* Create printer id string for colord */
+ snprintf(printer_id, CM_MAX_FILE_LENGTH, "cups-%s", data->printer);
- return profile_set;
+ /* Get profile from colord using qualifiers */
+ icc_profile = cfColordGetProfileForDeviceID(data,
+ (const char *)printer_id,
+ (const char **)qualifier);
+ }
+ /* Do we have a profile? */
+ if (icc_profile)
+ is_profile_set = 1;
+ /* If not, get fallback profile from option */
+ else if ((val = cupsGetOption("cm-fallback-profile",
+ data->num_options, data->options)) != NULL &&
+ val[0] != '\0')
+ {
+ is_profile_set = 1;
+ icc_profile = strdup(val);
+ }
+ else
+ icc_profile = NULL;
+
+ /* If a profile is found, we give it to the caller */
+ if (is_profile_set)
+ *profile = strdup(icc_profile);
+ else
+ *profile = NULL;
+
+ if (qualifier != NULL) {
+ for (int i=0; qualifier[i] != NULL; i++)
+ free(qualifier[i]);
+ free(qualifier);
+ }
+
+ if (icc_profile != NULL)
+ free(icc_profile);
+
+ if(log) log(ld, CF_LOGLEVEL_DEBUG,
+ "Color Manager: ICC Profile: %s",
+ *profile ? *profile : "None");
+
+ return is_profile_set;
}
/* Find the "cm-calibration" CUPS option */
cf_cm_calibration_t
-cfCmGetCupsColorCalibrateMode(cf_filter_data_t *data,
- cups_option_t *options, /* Options from CUPS */
- int num_options) /* Options from CUPS */
+cfCmGetCupsColorCalibrateMode(cf_filter_data_t *data)
{
-
- cf_logfunc_t log = data->logfunc;
- void *ld = data->logdata;
+ int num_options = 0;
+ cups_option_t *options = NULL;
+ cf_logfunc_t log = data->logfunc;
+ void *ld = data->logdata;
cf_cm_calibration_t status; /* color management status */
+ num_options = cfJoinJobOptionsAndAttrs(data, num_options, &options);
+
/* Find the string in CUPS options and */
if (cupsGetOption(CF_CM_CALIBRATION_STRING, num_options, options) != NULL)
status = CF_CM_CALIBRATION_ENABLED;
if(log) log(ld, CF_LOGLEVEL_DEBUG,
"Color Manager: %s", status ?
- "Calibration Mode/Enabled" : "Calibration Mode/Off");
+ "Calibration Mode/Enabled" : "Calibration Mode/Off");
+ cupsFreeOptions(num_options, options);
+
return status;
-
}
{
return blackpoint_default;
}
-
-
-
-
-/*
- * Private functions
- */
-
-
-static char *
-get_colord_printer_id( cf_filter_data_t *data)
-{
-
- cf_logfunc_t log = data->logfunc;
- void *ld = data->logdata;
- if (data->printer == NULL) {
- if(log) log(ld, CF_LOGLEVEL_DEBUG,
- "Color Manager: Invalid printer name.");
- return 0;
- }
-
- /* Create printer id string for colord */
- char* printer_id = (char*)malloc(CM_MAX_FILE_LENGTH);
- snprintf (printer_id, CM_MAX_FILE_LENGTH, "cups-%s", data->printer);
-
- return printer_id;
-
-}
-
-
-static int
-get_colord_printer_cm_status( cf_filter_data_t *data)
-{
-
- cf_logfunc_t log = data->logfunc;
- void *ld = data->logdata;
-
- /* If invalid input, we leave color management alone */
- if (data->printer == NULL) {
- if(log) log(ld, CF_LOGLEVEL_DEBUG,
- "Color Manager: Invalid printer name.");
- return 0;
- } else if (!strcmp(data->printer, "(null)"))
- return 0;
-
- int is_printer_cm_disabled = 0; /* color management status flag */
- char *printer_id = 0; /* colord printer id string */
-
-
- /* Check if device is inhibited/disabled in colord */
- printer_id = get_colord_printer_id(data);
- is_printer_cm_disabled = cfColordGetInhibitForDeviceID (data, printer_id);
-
- if (printer_id != NULL)
- free(printer_id);
-
- return is_printer_cm_disabled;
-
-}
-
-static int
-get_colord_profile(cf_filter_data_t *data,
- char **profile, /* Requested icc profile path */
- ppd_file_t *ppd) /* PPD file */
-{
-
- cf_logfunc_t log = data->logfunc;
- void *ld = data->logdata;
-
- if (data->printer == NULL || profile == 0) {
- if(log) log(ld, CF_LOGLEVEL_DEBUG,
- "Color Manager: Invalid input - Unable to find profile.");
- return -1;
- }
-
- int is_profile_set = 0; /* profile-is-found flag */
- char **qualifier = NULL; /* color qualifier strings */
- char *icc_profile = NULL; /* icc profile path */
- char *printer_id = NULL; /* colord printer id */
-
-
- /* Get color qualifier triple */
- qualifier = cfColordGetQualifierForPPD(ppd);
-
- if (qualifier != NULL) {
- printer_id = get_colord_printer_id(data);
- /* Get profile from colord using qualifiers */
- icc_profile = cfColordGetProfileForDeviceID (data,
- (const char *)printer_id,
- (const char **)qualifier);
- }
-
- if (icc_profile)
- is_profile_set = 1;
- else if (ppd) {
- /* Get optional fallback PPD profile */
- icc_profile = get_ppd_icc_fallback(data, ppd, qualifier);
- if (icc_profile)
- is_profile_set = 1;
- }
-
- /* If a profile is found, we give it to the caller */
- if (is_profile_set)
- *profile = strdup(icc_profile);
- else
- *profile = 0;
-
- if (printer_id != NULL)
- free(printer_id);
-
- if (qualifier != NULL) {
- for (int i=0; qualifier[i] != NULL; i++)
- free(qualifier[i]);
- free(qualifier);
- }
-
- if (icc_profile != NULL)
- free(icc_profile);
-
- return is_profile_set;
-
-}
-
-
-#ifndef CUPSDATA
-#define CUPSDATA "/usr/share/cups"
-#endif
-
-/* From gstoraster */
-static char *
-get_ppd_icc_fallback (cf_filter_data_t *data, ppd_file_t *ppd, char **qualifier)
-{
-
- cf_logfunc_t log = data->logfunc;
- void *ld = data->logdata;
- char full_path[1024];
- char *icc_profile = NULL;
- char qualifer_tmp[1024];
- const char *profile_key;
- ppd_attr_t *attr;
-
- /* get profile attr, falling back to CUPS */
- profile_key = "APTiogaProfile";
- attr = ppdFindAttr(ppd, profile_key, NULL);
- if (attr == NULL) {
- profile_key = "cupsICCProfile";
- attr = ppdFindAttr(ppd, profile_key, NULL);
- }
-
- /* create a string for a quick comparion */
- snprintf(qualifer_tmp, sizeof(qualifer_tmp),
- "%s.%s.%s",
- qualifier[0],
- qualifier[1],
- qualifier[2]);
-
- /* neither */
- if (attr == NULL) {
- if(log) log(ld, CF_LOGLEVEL_INFO,
- "Color Manager: no profiles specified in PPD");
-
- goto out;
- }
-
- /* try to find a profile that matches the qualifier exactly */
- for (;attr != NULL; attr = ppdFindNextAttr(ppd, profile_key, NULL)) {
- if(log) log(ld, CF_LOGLEVEL_INFO,
- "Color Manager: found profile %s in PPD with qualifier '%s'",
- attr->value, attr->spec);
-
- /* invalid entry */
- if (attr->spec == NULL || attr->value == NULL)
- continue;
-
- /* expand to a full path if not already specified */
- if (attr->value[0] != '/')
- snprintf(full_path, sizeof(full_path),
- "%s/profiles/%s", CUPSDATA, attr->value);
- else {
- strncpy(full_path, attr->value, sizeof(full_path) - 1);
- if (strlen(attr->value) > 1023)
- full_path[1023] = '\0';
- }
-
- /* check the file exists */
- if (access(full_path, 0)) {
- if(log) log(ld, CF_LOGLEVEL_INFO,
- "Color Manager: found profile %s in PPD that does not exist",
- full_path);
- continue;
- }
-
- /* matches the qualifier */
- if (strcmp(qualifer_tmp, attr->spec) == 0) {
- icc_profile = strdup(full_path);
- goto out;
- }
- }
-
- /* no match */
- if (attr == NULL) {
- if(log) log(ld, CF_LOGLEVEL_INFO,
- "Color Manager: no profiles in PPD for qualifier '%s'",
- qualifer_tmp);
- goto out;
- }
-
-out:
- return icc_profile;
-}
-
#include <cups/raster.h>
-#include <ppd/ppd.h>
#include <cupsfilters/filter.h>
extern
-cf_cm_calibration_t cfCmGetCupsColorCalibrateMode(cf_filter_data_t *data,
- cups_option_t *options,
- int num_options);
+cf_cm_calibration_t cfCmGetCupsColorCalibrateMode(cf_filter_data_t *data);
extern int cfCmGetPrinterIccProfile(cf_filter_data_t *data,
- char **icc_profile,
- ppd_file_t *ppd);
+ const char *color_space,
+ const char *media_type,
+ int x_res,
+ int y_res,
+ char **icc_profile);
extern int cfCmIsPrinterCmDisabled(cf_filter_data_t *data);
# include <time.h>
# include <math.h>
# include "filter.h"
-# include <ppd/ppd.h>
# if defined(WIN32) || defined(__EMX__)
# include <io.h>
* Prototypes...
*/
-/*
- * Attribute function...
- */
-
-extern ppd_attr_t *cfFindAttr(ppd_file_t *ppd, const char *name,
- const char *colormodel,
- const char *media,
- const char *resolution,
- char *spec, int specsize,
- cf_logfunc_t log,
- void *ld);
-
/*
* Byte checking functions...
*/
extern cf_lut_t *cfLutNew(int num_vals, const float *vals,
cf_logfunc_t log, void *ld);
extern void cfLutDelete(cf_lut_t *lut);
-extern cf_lut_t *cfLutLoad(ppd_file_t *ppd,
- const char *colormodel,
- const char *media,
- const char *resolution,
- const char *ink,
- cf_logfunc_t log,
- void *ld);
/*
extern void cfRGBDoRGB(cf_rgb_t *rgb,
const unsigned char *input,
unsigned char *output, int num_pixels);
-extern cf_rgb_t *cfRGBLoad(ppd_file_t *ppd,
- const char *colormodel,
- const char *media,
- const char *resolution,
- cf_logfunc_t log,
- void *ld);
extern cf_rgb_t *cfRGBNew(int num_samples, cf_sample_t *samples,
int cube_size, int num_channels);
extern void cfCMYKDoRGB(const cf_cmyk_t *cmyk,
const unsigned char *input,
short *output, int num_pixels);
-extern cf_cmyk_t *cfCMYKLoad(ppd_file_t *ppd,
- const char *colormodel,
- const char *media,
- const char *resolution,
- cf_logfunc_t log,
- void *ld);
- extern void cfCMYKSetBlack(cf_cmyk_t *cmyk,
+extern void cfCMYKSetBlack(cf_cmyk_t *cmyk,
float lower, float upper,
cf_logfunc_t log, void *ld);
extern void cfCMYKSetCurve(cf_cmyk_t *cmyk, int channel,
float gamval, float density,
cf_logfunc_t log, void *ld);
extern void cfCMYKSetInkLimit(cf_cmyk_t *cmyk, float limit);
- extern void cfCMYKSetLtDk(cf_cmyk_t *cmyk, int channel,
+extern void cfCMYKSetLtDk(cf_cmyk_t *cmyk, int channel,
float light, float dark,
cf_logfunc_t log, void *ld);
#include <sys/wait.h>
#include <cups/file.h>
#include <cups/array.h>
-#include <ppd/ppd.h>
extern char **environ;
}
-/*
- * 'cfFilterCUPSWrapper()' - Wrapper function to use a filter function as
- * classic CUPS filter
- */
-
-int /* O - Exit status */
-cfFilterCUPSWrapper(
- int argc, /* I - Number of command-line args */
- char *argv[], /* I - Command-line arguments */
- cf_filter_function_t filter, /* I - Filter function */
- void *parameters, /* I - Filter function parameters */
- int *JobCanceled) /* I - Var set to 1 when job canceled */
+static cf_filter_data_ext_t *
+get_filter_data_ext_entry(cups_array_t *ext_array,
+ const char *name)
{
- int inputfd; /* Print file descriptor*/
- int inputseekable; /* Is the input seekable (actual file
- not stdin)? */
- int num_options; /* Number of print options */
- cups_option_t *options; /* Print options */
- cf_filter_data_t filter_data;
- int retval = 0;
+ cf_filter_data_ext_t *entry;
+ if (!ext_array || !name)
+ return (NULL);
- /*
- * Make sure status messages are not buffered...
- */
+ for (entry = (cf_filter_data_ext_t *)cupsArrayFirst(ext_array);
+ entry;
+ entry = (cf_filter_data_ext_t *)cupsArrayNext(ext_array))
+ if (strcmp(entry->name, name) == 0)
+ break;
- setbuf(stderr, NULL);
+ return (entry);
+}
- /*
- * Ignore broken pipe signals...
- */
- signal(SIGPIPE, SIG_IGN);
+void * /* O - Extension record which got
+ replaced, NULL if there was
+ no record under this name,
+ the added record is the one
+ there, or no record was
+ added. If not NULL the
+ returned record should usually
+ be deleted or freed. */
+cfFilterDataAddExt(cf_filter_data_t *data, /* I - Filter data record */
+ const char *name, /* I - Name of extension */
+ void *ext) /* I - Extension record to be added*/
+{
+ cf_filter_data_ext_t *entry;
+ void *old_ext = NULL;
- /*
- * Check command-line...
- */
+ if (!data || !name || !ext)
+ return (NULL);
- if (argc < 6 || argc > 7)
- {
- fprintf(stderr, "Usage: %s job-id user title copies options [file]\n",
- argv[0]);
- return (1);
- }
+ if (data->extension == NULL)
+ data->extension = cupsArrayNew(NULL, NULL);
- /*
- * If we have 7 arguments, print the file named on the command-line.
- * Otherwise, send stdin instead...
- */
+ if (data->extension == NULL)
+ return (NULL);
- if (argc == 6)
+ if ((entry = get_filter_data_ext_entry(data->extension, name)) != NULL)
{
- inputfd = 0; /* stdin */
- inputseekable = 0;
+ old_ext = entry->ext;
+ entry->ext = ext;
}
else
{
- /*
- * Try to open the print file...
- */
-
- if ((inputfd = open(argv[6], O_RDONLY)) < 0)
+ entry = (cf_filter_data_ext_t *)calloc(1, sizeof(cf_filter_data_ext_t));
+ if (entry)
{
- if (!JobCanceled)
- {
- fprintf(stderr, "DEBUG: Unable to open \"%s\": %s\n", argv[6],
- strerror(errno));
- fprintf(stderr, "ERROR: Unable to open print file");
- }
-
- return (1);
+ entry->name = strdup(name);
+ entry->ext = ext;
+ cupsArrayAdd(data->extension, entry);
}
-
- inputseekable = 1;
}
- /*
- * Process command-line options...
- */
-
- options = NULL;
- num_options = cupsParseOptions(argv[5], 0, &options);
-
- /*
- * Create data record to call filter function and load PPD file
- */
-
- if ((filter_data.printer = getenv("PRINTER")) == NULL)
- filter_data.printer = argv[0];
- filter_data.job_id = atoi(argv[1]);
- filter_data.job_user = argv[2];
- filter_data.job_title = argv[3];
- filter_data.copies = atoi(argv[4]);
- filter_data.job_attrs = NULL; /* We use command line options */
- filter_data.printer_attrs = NULL; /* We use the queue's PPD file */
- filter_data.num_options = num_options;
- filter_data.options = options; /* Command line options from 5th arg */
- filter_data.ppdfile = getenv("PPD"); /* PPD file name in the "PPD"
- environment variable. */
- filter_data.back_pipe[0] = 3; /* CUPS uses file descriptor 3 for */
- filter_data.back_pipe[1] = 3; /* the back channel */
- filter_data.side_pipe[0] = 4; /* CUPS uses file descriptor 4 for */
- filter_data.side_pipe[1] = 4; /* the side channel */
- filter_data.logfunc = cfCUPSLogFunc; /* Logging scheme of CUPS */
- filter_data.logdata = NULL;
- filter_data.iscanceledfunc = cfCUPSIsCanceledFunc; /* Job-is-canceled
- function */
- filter_data.iscanceleddata = JobCanceled;
-
- /*
- * Load and prepare the PPD file
- */
-
- retval = cfFilterLoadPPD(&filter_data);
-
- /*
- * Fire up the filter function (output to stdout, file descriptor 1)
- */
+ return (old_ext);
+}
- if (!retval)
- retval = filter(inputfd, 1, inputseekable, &filter_data, parameters);
- /*
- * Clean up
- */
+void *
+cfFilterDataGetExt(cf_filter_data_t *data,
+ const char *name)
+{
+ cf_filter_data_ext_t *entry;
- cupsFreeOptions(num_options, options);
- cfFilterFreePPD(&filter_data);
+ if (!data || !name || data->extension == NULL)
+ return (NULL);
- return retval;
+ if ((entry = get_filter_data_ext_entry(data->extension, name)) != NULL)
+ return (entry->ext);
+ else
+ return NULL;
}
-/*
- * 'cfFilterLoadPPD()' - When preparing the data structure for calling
- * one or more filter functions. Load the PPD
- * file specified by the file name in the
- * "ppdfile" field of the data structure. If the
- * file name is NULL do nothing. If the PPD got
- * successfully loaded also set up its cache,
- * and mark default settings and if supplied in
- * the data structure, also option settings.
- */
-
-int /* O - Error status */
-cfFilterLoadPPD(cf_filter_data_t *data) /* I - Job and printer data */
+void *
+cfFilterDataRemoveExt(cf_filter_data_t *data,
+ const char *name)
{
- cf_logfunc_t log = data->logfunc; /* Log function */
- void *ld = data->logdata; /* log function data */
+ cf_filter_data_ext_t *entry;
+ void *ext = NULL;
- if (data->ppdfile == NULL)
- {
- data->ppd = NULL;
- return (0);
- }
+ if (!data || !name || data->extension == NULL)
+ return (NULL);
- if ((data->ppd = ppdOpenFile(data->ppdfile)) == NULL)
+ if ((entry = get_filter_data_ext_entry(data->extension, name)) != NULL)
{
- if (log) log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterLoadPPD: Could not load PPD file %s: %s",
- data->ppdfile, strerror(errno));
- return (1);
+ ext = entry->ext;
+ cupsArrayRemove(data->extension, entry);
+ free(entry->name);
+ free(entry);
+ if (cupsArrayCount(data->extension) == 0)
+ {
+ cupsArrayDelete(data->extension);
+ data->extension = NULL;
+ }
+ return (ext);
}
-
- data->ppd->cache = ppdCacheCreateWithPPD(data->ppd);
- ppdMarkDefaults(data->ppd);
- ppdMarkOptions(data->ppd, data->num_options, data->options);
-
- return (0);
-}
-
-
-/*
- * 'cfFilterFreePPD()' - After being done with the filter functions
- * Free the memory used by the PPD file data in
- * the data structure. If the pomiter to the PPD
- * file data "ppd" is NULL, do nothing.
- */
-
-void
-cfFilterFreePPD(cf_filter_data_t *data) /* I - Job and printer data */
-{
- if (data->ppd == NULL)
- return;
-
- /* ppdClose() frees not only the main data structure but also the cache */
- ppdClose(data->ppd);
+ else
+ return NULL;
}
}
-/*
- * 'get_env_var()' - Auxiliary function for cfFilterExternalCUPS(), gets value of
- * an environment variable in a list of environment variables
- * as used by the execve() function
- */
-
-static char * /* O - The value, NULL if variable is not in list */
-get_env_var(char *name, /* I - Name of environment variable to read */
- char **env) /* I - List of environment variable serttings */
-{
- int i = 0;
-
-
- if (env)
- for (i = 0; env[i]; i ++)
- if (strncmp(env[i], name, strlen(name)) == 0 &&
- strlen(env[i]) > strlen(name) &&
- env[i][strlen(name)] == '=')
- return (env[i] + strlen(name) + 1);
-
- return (NULL);
-}
-
-
-/*
- * 'add_env_var()' - Auxiliary function for cfFilterExternalCUPS(), adds/sets
- * an environment variable in a list of environment variables
- * as used by the execve() function
- */
-
-static int /* O - Index of where the new value got inserted in
- the list */
-add_env_var(char *name, /* I - Name of environment variable to set */
- char *value, /* I - Value of environment variable to set */
- char ***env) /* I - List of environment variable serttings */
-{
- char *p;
- int i = 0,
- name_len;
-
-
- if (!name || !env || !name[0])
- return (-1);
-
- /* Assemble a "VAR=VALUE" string and the string length of "VAR" */
- if ((p = strchr(name, '=')) != NULL)
- {
- /* User supplied "VAR=VALUE" as name and NULL as value */
- if (value)
- return (-1);
- name_len = p - name;
- p = strdup(name);
- }
- else
- {
- /* User supplied variable name and value as the name and as the value */
- name_len = strlen(name);
- p = (char *)calloc(strlen(name) + (value ? strlen(value) : 0) + 2,
- sizeof(char));
- sprintf(p, "%s=%s", name, (value ? value : ""));
- }
-
- /* Check whether we already have this variable in the list and update its
- value if it is there */
- if (*env)
- for (i = 0; (*env)[i]; i ++)
- if (strncmp((*env)[i], p, name_len) == 0 && (*env)[i][name_len] == '=')
- {
- free((*env)[i]);
- (*env)[i] = p;
- return (i);
- }
-
- /* Add the variable as new item to the list */
- *env = (char **)realloc(*env, (i + 2) * sizeof(char *));
- (*env)[i] = p;
- (*env)[i + 1] = NULL;
- return (i);
-}
-
-
-/*
- * 'sanitize_device_uri()' - Remove authentication info from a device URI
- */
-
-static char * /* O - Sanitized URI */
-sanitize_device_uri(const char *uri, /* I - Device URI */
- char *buf, /* I - Buffer for output */
- size_t bufsize) /* I - Size of buffer */
-{
- char *start, /* Start of data after scheme */
- *slash, /* First slash after scheme:// */
- *ptr; /* Pointer into user@host:port part */
-
-
- /* URI not supplied */
- if (!uri)
- return (NULL);
-
- /* Copy the device URI to a temporary buffer so we can sanitize any auth
- * info in it... */
- strncpy(buf, uri, bufsize);
-
- /* Find the end of the scheme:// part... */
- if ((ptr = strchr(buf, ':')) != NULL)
- {
- for (start = ptr + 1; *start; start ++)
- if (*start != '/')
- break;
-
- /* Find the next slash (/) in the URI... */
- if ((slash = strchr(start, '/')) == NULL)
- slash = start + strlen(start); /* No slash, point to the end */
-
- /* Check for an @ sign before the slash... */
- if ((ptr = strchr(start, '@')) != NULL && ptr < slash)
- {
- /* Found an @ sign and it is before the resource part, so we have
- an authentication string. Copy the remaining URI over the
- authentication string... */
- memmove(start, ptr + 1, strlen(ptr + 1) + 1);
- }
- }
-
- /* Return the sanitized URI... */
- return (buf);
-}
-
-
-/*
- * 'cfFilterExternalCUPS()' - Filter function which calls an external,
- * classic CUPS filter, for example a
- * (proprietary) printer driver which cannot
- * be converted to a filter function or is to
- * awkward or risky to convert for example
- * when the printer hardware is not available
- * for testing
- */
-
-int /* O - Error status */
-cfFilterExternalCUPS(int inputfd, /* I - File descriptor input stream */
- int outputfd, /* I - File descriptor output stream */
- int inputseekable, /* I - Is input stream seekable? */
- cf_filter_data_t *data, /* I - Job and printer data */
- void *parameters) /* I - Filter-specific parameters */
-{
- cf_filter_external_cups_t *params = (cf_filter_external_cups_t *)parameters;
- int i;
- int is_backend = 0; /* Do we call a CUPS backend? */
- int pid, /* Process ID of filter */
- stderrpid, /* Process ID for stderr logging process */
- wpid; /* PID reported as terminated */
- int fd; /* Temporary file descriptor */
- int backfd, sidefd; /* file descriptors for back and side
- channels */
- int stderrpipe[2]; /* Pipe to log stderr */
- cups_file_t *fp; /* File pointer to read log lines */
- char buf[2048]; /* Log line buffer */
- cf_loglevel_t log_level; /* Log level of filter's log message */
- char *ptr1, *ptr2,
- *msg, /* Filter log message */
- *filter_name; /* Filter name for logging */
- char filter_path[1024]; /* Full path of the filter */
- char **argv, /* Command line args for filter */
- **envp = NULL; /* Environment variables for filter */
- int num_all_options = 0;
- cups_option_t *all_options = NULL;
- char job_id_str[16],
- copies_str[16],
- *options_str = NULL;
- cups_option_t *opt;
- int status = 65536;
- int wstatus;
- cf_logfunc_t log = data->logfunc;
- void *ld = data->logdata;
- cf_filter_iscanceledfunc_t iscanceled = data->iscanceledfunc;
- void *icd = data->iscanceleddata;
-
-
- if (!params->filter || !params->filter[0]) {
- if (log) log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterExternalCUPS: Filter executable path/command not specified");
- return (1);
- }
-
- /* Check whether back/side channel FDs are valid and not all-zero
- from calloc'ed filter_data */
- if (data->back_pipe[0] == 0 && data->back_pipe[1] == 0)
- data->back_pipe[0] = data->back_pipe[1] = -1;
- if (data->side_pipe[0] == 0 && data->side_pipe[1] == 0)
- data->side_pipe[0] = data->side_pipe[1] = -1;
-
- /* Select the correct end of the back/side channel pipes:
- [0] for filters, [1] for backends */
- is_backend = (params->is_backend ? 1 : 0);
- backfd = data->back_pipe[is_backend];
- sidefd = data->side_pipe[is_backend];
-
- /* Filter name for logging */
- if ((filter_name = strrchr(params->filter, '/')) != NULL)
- filter_name ++;
- else
- filter_name = (char *)params->filter;
-
- /*
- * Ignore broken pipe signals...
- */
-
- signal(SIGPIPE, SIG_IGN);
-
- /*
- * Copy the current environment variables and add some important ones
- * needed for correct execution of the CUPS filter (which is not running
- * out of CUPS here)
- */
-
- /* Some default environment variables from CUPS, will get overwritten
- if also defined in the environment in which the caller is started
- or in the parameters */
- add_env_var("CUPS_DATADIR", CUPS_DATADIR, &envp);
- add_env_var("CUPS_SERVERBIN", CUPS_SERVERBIN, &envp);
- add_env_var("CUPS_SERVERROOT", CUPS_SERVERROOT, &envp);
- add_env_var("CUPS_STATEDIR", CUPS_STATEDIR, &envp);
- add_env_var("SOFTWARE", "CUPS/2.5.99", &envp); /* Last CUPS with PPDs */
-
- /* Copy the environment in which the caller got started */
- if (environ)
- for (i = 0; environ[i]; i ++)
- add_env_var(environ[i], NULL, &envp);
-
- /* Set the environment variables given by the parameters */
- if (params->envp)
- for (i = 0; params->envp[i]; i ++)
- add_env_var(params->envp[i], NULL, &envp);
-
- /* Add CUPS_SERVERBIN to the beginning of PATH */
- ptr1 = get_env_var("PATH", envp);
- ptr2 = get_env_var("CUPS_SERVERBIN", envp);
- if (ptr2 && ptr2[0])
- {
- if (ptr1 && ptr1[0])
- {
- snprintf(buf, sizeof(buf), "%s/%s:%s",
- ptr2, params->is_backend ? "backend" : "filter", ptr1);
- ptr1 = buf;
- }
- else
- ptr1 = ptr2;
- add_env_var("PATH", ptr1, &envp);
- }
-
- if (params->is_backend < 2) /* Not needed in discovery mode of backend */
- {
- /* Print queue name from filter data */
- if (data->printer)
- add_env_var("PRINTER", data->printer, &envp);
- else
- add_env_var("PRINTER", "Unknown", &envp);
-
- /* PPD file path/name from filter data, required for most CUPS filters */
- if (data->ppdfile)
- add_env_var("PPD", data->ppdfile, &envp);
-
- /* Device URI from parameters */
- if (params->is_backend && params->device_uri)
- add_env_var("DEVICE_URI", (char *)params->device_uri, &envp);
- }
-
- /* Determine full path for the filter */
- if (params->filter[0] == '/' ||
- (ptr1 = get_env_var("CUPS_SERVERBIN", envp)) == NULL || !ptr1[0])
- strncpy(filter_path, params->filter, sizeof(filter_path) - 1);
- else
- snprintf(filter_path, sizeof(filter_path), "%s/%s/%s", ptr1,
- params->is_backend ? "backend" : "filter", params->filter);
-
- /* Log the resulting list of environment variable settings
- (with any authentication info removed)*/
- if (log)
- {
- for (i = 0; envp[i]; i ++)
- if (!strncmp(envp[i], "AUTH_", 5))
- log(ld, CF_LOGLEVEL_DEBUG, "cfFilterExternalCUPS (%s): envp[%d]: AUTH_%c****",
- filter_name, i, envp[i][5]);
- else if (!strncmp(envp[i], "DEVICE_URI=", 11))
- log(ld, CF_LOGLEVEL_DEBUG, "cfFilterExternalCUPS (%s): envp[%d]: DEVICE_URI=%s",
- filter_name, i, sanitize_device_uri(envp[i] + 11,
- buf, sizeof(buf)));
- else
- log(ld, CF_LOGLEVEL_DEBUG, "cfFilterExternalCUPS (%s): envp[%d]: %s",
- filter_name, i, envp[i]);
- }
-
- if (params->is_backend < 2) {
- /*
- * Filter or backend for job execution
- */
-
- /*
- * Join the options from the filter data and from the parameters
- * If an option is present in both filter data and parameters, the
- * value in the filter data has priority
- */
-
- for (i = 0, opt = params->options; i < params->num_options; i ++, opt ++)
- num_all_options = cupsAddOption(opt->name, opt->value, num_all_options,
- &all_options);
- for (i = 0, opt = data->options; i < data->num_options; i ++, opt ++)
- num_all_options = cupsAddOption(opt->name, opt->value, num_all_options,
- &all_options);
-
- /*
- * Create command line arguments for the CUPS filter
- */
-
- argv = (char **)calloc(7, sizeof(char *));
-
- /* Numeric parameters */
- snprintf(job_id_str, sizeof(job_id_str) - 1, "%d",
- data->job_id > 0 ? data->job_id : 1);
- snprintf(copies_str, sizeof(copies_str) - 1, "%d",
- data->copies > 0 ? data->copies : 1);
-
- /* Options, build string of "Name1=Value1 Name2=Value2 ..." but use
- "Name" and "noName" instead for boolean options */
- for (i = 0, opt = all_options; i < num_all_options; i ++, opt ++) {
- if (strcasecmp(opt->value, "true") == 0 ||
- strcasecmp(opt->value, "false") == 0) {
- options_str =
- (char *)realloc(options_str,
- ((options_str ? strlen(options_str) : 0) +
- strlen(opt->name) +
- (strcasecmp(opt->value, "false") == 0 ? 2 : 0) + 2) *
- sizeof(char));
- if (i == 0)
- options_str[0] = '\0';
- sprintf(options_str + strlen(options_str), " %s%s",
- (strcasecmp(opt->value, "false") == 0 ? "no" : ""), opt->name);
- } else {
- options_str =
- (char *)realloc(options_str,
- ((options_str ? strlen(options_str) : 0) +
- strlen(opt->name) + strlen(opt->value) + 3) *
- sizeof(char));
- if (i == 0)
- options_str[0] = '\0';
- sprintf(options_str + strlen(options_str), " %s=%s", opt->name, opt->value);
- }
- }
-
- /* Find DEVICE_URI environment variable */
- if (params->is_backend && !params->device_uri)
- for (i = 0; envp[i]; i ++)
- if (strncmp(envp[i], "DEVICE_URI=", 11) == 0)
- break;
-
- /* Add items to array */
- argv[0] = strdup((params->is_backend && params->device_uri ?
- (char *)sanitize_device_uri(params->device_uri,
- buf, sizeof(buf)) :
- (params->is_backend && envp[i] ?
- (char *)sanitize_device_uri(envp[i] + 11,
- buf, sizeof(buf)) :
- (data->printer ? data->printer :
- (char *)params->filter))));
- argv[1] = job_id_str;
- argv[2] = data->job_user ? data->job_user : "Unknown";
- argv[3] = data->job_title ? data->job_title : "Untitled";
- argv[4] = copies_str;
- argv[5] = options_str ? options_str + 1 : "";
- argv[6] = NULL;
-
- /* Log the arguments */
- if (log)
- for (i = 0; argv[i]; i ++)
- log(ld, CF_LOGLEVEL_DEBUG, "cfFilterExternalCUPS (%s): argv[%d]: %s",
- filter_name, i, argv[i]);
- } else {
- /*
- * Backend in device discovery mode
- */
-
- argv = (char **)calloc(2, sizeof(char *));
- argv[0] = strdup((char *)params->filter);
- argv[1] = NULL;
- }
-
- /*
- * Execute the filter
- */
-
- if (pipe(stderrpipe) < 0) {
- if (log) log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterExternalCUPS (%s): Could not create pipe for stderr: %s",
- filter_name, strerror(errno));
- return (1);
- }
-
- if ((pid = fork()) == 0) {
- /*
- * Child process goes here...
- *
- * Update stdin/stdout/stderr as needed...
- */
-
- if (inputfd != 0) {
- if (inputfd < 0) {
- inputfd = open("/dev/null", O_RDONLY);
- if (log) log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterExternalCUPS (%s): No input file descriptor supplied for CUPS filter - %s",
- filter_name, strerror(errno));
- }
-
- if (inputfd > 0) {
- fcntl_add_cloexec(inputfd);
- if (dup2(inputfd, 0) < 0) {
- if (log) log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterExternalCUPS (%s): Failed to connect input file descriptor with CUPS filter's stdin - %s",
- filter_name, strerror(errno));
- goto fd_error;
- } else
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterExternalCUPS (%s): Connected input file descriptor %d to CUPS filter's stdin.",
- filter_name, inputfd);
- close(inputfd);
- }
- } else
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterExternalCUPS (%s): Input comes from stdin, letting the filter grab stdin directly",
- filter_name);
-
- if (outputfd != 1) {
- if (outputfd < 0)
- outputfd = open("/dev/null", O_WRONLY);
-
- if (outputfd > 1) {
- fcntl_add_cloexec(outputfd);
- dup2(outputfd, 1);
- close(outputfd);
- }
- }
-
- if (strcasestr(params->filter, "gziptoany")) {
- /* Send stderr to the Nirwana if we are running gziptoany, as
- gziptoany emits a false "PAGE: 1 1" */
- if ((fd = open("/dev/null", O_RDWR)) > 2) {
- fcntl_add_cloexec(fd);
- dup2(fd, 2);
- close(fd);
- } else
- close(fd);
- } else {
- /* Send stderr into pipe for logging */
- fcntl_add_cloexec(stderrpipe[1]);
- dup2(stderrpipe[1], 2);
- fcntl_add_nonblock(2);
- }
- close(stderrpipe[0]);
- close(stderrpipe[1]);
-
- if (params->is_backend < 2) { /* Not needed in discovery mode of backend */
- /* Back channel */
- if (backfd != 3 && backfd >= 0) {
- dup2(backfd, 3);
- close(backfd);
- fcntl_add_nonblock(3);
- } else if (backfd < 0) {
- if ((backfd = open("/dev/null", O_RDWR)) > 3) {
- dup2(backfd, 3);
- close(backfd);
- } else
- close(backfd);
- fcntl_add_nonblock(3);
- }
-
- /* Side channel */
- if (sidefd != 4 && sidefd >= 0) {
- dup2(sidefd, 4);
- close(sidefd);
- fcntl_add_nonblock(4);
- } else if (sidefd < 0) {
- if ((sidefd = open("/dev/null", O_RDWR)) > 4) {
- dup2(sidefd, 4);
- close(sidefd);
- } else
- close(sidefd);
- fcntl_add_nonblock(4);
- }
- }
-
- /*
- * Execute command...
- */
-
- execve(filter_path, argv, envp);
-
- if (log) log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterExternalCUPS (%s): Execution of %s %s failed - %s",
- filter_name, params->is_backend ? "backend" : "filter",
- filter_path, strerror(errno));
-
- fd_error:
- exit(errno);
- } else if (pid > 0) {
- if (log) log(ld, CF_LOGLEVEL_INFO,
- "cfFilterExternalCUPS (%s): %s (PID %d) started.",
- filter_name, filter_path, pid);
- } else {
- if (log) log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterExternalCUPS (%s): Unable to fork process for %s %s",
- filter_name, params->is_backend ? "backend" : "filter",
- filter_path);
- close(stderrpipe[0]);
- close(stderrpipe[1]);
- status = 1;
- goto out;
- }
- if (inputfd >= 0)
- close(inputfd);
- if (outputfd >= 0)
- close(outputfd);
-
- /*
- * Log the filter's stderr
- */
-
- if ((stderrpid = fork()) == 0) {
- /*
- * Child process goes here...
- */
-
- close(stderrpipe[1]);
- fp = cupsFileOpenFd(stderrpipe[0], "r");
- while (cupsFileGets(fp, buf, sizeof(buf)))
- if (log) {
- if (strncmp(buf, "DEBUG: ", 7) == 0) {
- log_level = CF_LOGLEVEL_DEBUG;
- msg = buf + 7;
- } else if (strncmp(buf, "DEBUG2: ", 8) == 0) {
- log_level = CF_LOGLEVEL_DEBUG;
- msg = buf + 8;
- } else if (strncmp(buf, "INFO: ", 6) == 0) {
- log_level = CF_LOGLEVEL_INFO;
- msg = buf + 6;
- } else if (strncmp(buf, "WARNING: ", 9) == 0) {
- log_level = CF_LOGLEVEL_WARN;
- msg = buf + 9;
- } else if (strncmp(buf, "ERROR: ", 7) == 0) {
- log_level = CF_LOGLEVEL_ERROR;
- msg = buf + 7;
- } else if (strncmp(buf, "PAGE: ", 6) == 0 ||
- strncmp(buf, "ATTR: ", 6) == 0 ||
- strncmp(buf, "STATE: ", 7) == 0 ||
- strncmp(buf, "PPD: ", 5) == 0) {
- log_level = CF_LOGLEVEL_CONTROL;
- msg = buf;
- } else {
- log_level = CF_LOGLEVEL_DEBUG;
- msg = buf;
- }
- if (log_level == CF_LOGLEVEL_CONTROL)
- log(ld, log_level, msg);
- else
- log(ld, log_level, "cfFilterExternalCUPS (%s): %s", filter_name, msg);
- }
- cupsFileClose(fp);
- /* No need to close the fd stderrpipe[0], as cupsFileClose(fp) does this
- already */
- /* Ignore errors of the logging process */
- exit(0);
- } else if (stderrpid > 0) {
- if (log) log(ld, CF_LOGLEVEL_INFO,
- "cfFilterExternalCUPS (%s): Logging (PID %d) started.",
- filter_name, stderrpid);
- } else {
- if (log) log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterExternalCUPS (%s): Unable to fork process for logging",
- filter_name);
- close(stderrpipe[0]);
- close(stderrpipe[1]);
- status = 1;
- goto out;
- }
-
- close(stderrpipe[0]);
- close(stderrpipe[1]);
-
- /*
- * Wait for filter and logging processes to finish
- */
-
- status = 0;
-
- while (pid > 0 || stderrpid > 0) {
- if ((wpid = wait(&wstatus)) < 0) {
- if (errno == EINTR && iscanceled && iscanceled(icd)) {
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterExternalCUPS (%s): Job canceled, killing %s ...",
- filter_name, params->is_backend ? "backend" : "filter");
- kill(pid, SIGTERM);
- pid = -1;
- kill(stderrpid, SIGTERM);
- stderrpid = -1;
- break;
- } else
- continue;
- }
-
- /* How did the filter terminate */
- if (wstatus) {
- if (WIFEXITED(wstatus)) {
- /* Via exit() anywhere or return() in the main() function */
- if (log) log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterExternalCUPS (%s): %s (PID %d) stopped with status %d",
- filter_name,
- (wpid == pid ?
- (params->is_backend ? "Backend" : "Filter") :
- "Logging"),
- wpid, WEXITSTATUS(wstatus));
- } else {
- /* Via signal */
- if (log) log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterExternalCUPS (%s): %s (PID %d) crashed on signal %d",
- filter_name,
- (wpid == pid ?
- (params->is_backend ? "Backend" : "Filter") :
- "Logging"),
- wpid, WTERMSIG(wstatus));
- }
- status = 1;
- } else {
- if (log) log(ld, CF_LOGLEVEL_INFO,
- "cfFilterExternalCUPS (%s): %s (PID %d) exited with no errors.",
- filter_name,
- (wpid == pid ?
- (params->is_backend ? "Backend" : "Filter") : "Logging"),
- wpid);
- }
- if (wpid == pid)
- pid = -1;
- else if (wpid == stderrpid)
- stderrpid = -1;
- }
-
- /*
- * Clean up
- */
-
- out:
- cupsFreeOptions(num_all_options, all_options);
- if (options_str)
- free(options_str);
- free(argv[0]);
- free(argv);
- for (i = 0; envp[i]; i ++)
- free(envp[i]);
- free(envp);
-
- return (status);
-}
-
-
/*
* 'cfFilterOpenBackAndSidePipes()' - Open the pipes for the back
* channel and the side channel, so
if (log) log(ld, CF_LOGLEVEL_DEBUG,
"Closed the pipes for back and side channels");
}
-
-
-/*
- * 'cfFilterSetCommonOptions()' - Set common filter options for media size, etc.
- * based on PPD file
- */
-
-void
-cfFilterSetCommonOptions(
- ppd_file_t *ppd, /* I - PPD file */
- int num_options, /* I - Number of options */
- cups_option_t *options, /* I - Options */
- int change_size, /* I - Change page size? */
- int *Orientation, /* I/O - Basic page parameters */
- int *Duplex,
- int *LanguageLevel,
- int *ColorDevice,
- float *PageLeft,
- float *PageRight,
- float *PageTop,
- float *PageBottom,
- float *PageWidth,
- float *PageLength,
- cf_logfunc_t log, /* I - Logging function,
- NULL for no logging */
- void *ld) /* I - User data for logging function,
- can be NULL */
-{
- ppd_size_t *pagesize; /* Current page size */
- const char *val; /* Option value */
-
-
- *Orientation = 0; /* 0 = portrait, 1 = landscape, etc. */
- *Duplex = 0; /* Duplexed? */
- *LanguageLevel = 1; /* Language level of printer */
- *ColorDevice = 1; /* Color printer? */
- *PageLeft = 18.0f; /* Left margin */
- *PageRight = 594.0f; /* Right margin */
- *PageBottom = 36.0f; /* Bottom margin */
- *PageTop = 756.0f; /* Top margin */
- *PageWidth = 612.0f; /* Total page width */
- *PageLength = 792.0f; /* Total page length */
-
- if ((pagesize = ppdPageSize(ppd, NULL)) != NULL)
- {
- int corrected = 0;
- if (pagesize->width > 0)
- *PageWidth = pagesize->width;
- else
- {
- if (log) log(ld, CF_LOGLEVEL_ERROR,
- "Invalid value for page width: %.0f",
- pagesize->width);
- corrected = 1;
- }
- if (pagesize->length > 0)
- *PageLength = pagesize->length;
- else
- {
- if (log) log(ld, CF_LOGLEVEL_ERROR,
- "Invalid value for page length: %.0f",
- pagesize->length);
- corrected = 1;
- }
- if (pagesize->top >= 0 && pagesize->top <= *PageLength)
- *PageTop = pagesize->top;
- else
- {
- if (log) log(ld, CF_LOGLEVEL_ERROR,
- "Invalid value for page top margin: %.0f",
- pagesize->top);
- if (*PageLength >= *PageBottom)
- *PageTop = *PageLength - *PageBottom;
- else
- *PageTop = *PageLength;
- corrected = 1;
- }
- if (pagesize->bottom >= 0 && pagesize->bottom <= *PageLength)
- *PageBottom = pagesize->bottom;
- else
- {
- if (log) log(ld, CF_LOGLEVEL_ERROR,
- "Invalid value for page bottom margin: %.0f",
- pagesize->bottom);
- if (*PageLength <= *PageBottom)
- *PageBottom = 0.0f;
- corrected = 1;
- }
- if (*PageBottom == *PageTop)
- {
- if (log) log(ld, CF_LOGLEVEL_ERROR,
- "Invalid values for page margins: Bottom: %.0f; Top: %.0f",
- *PageBottom, *PageTop);
- *PageTop = *PageLength - *PageBottom;
- if (*PageBottom == *PageTop)
- {
- *PageBottom = 0.0f;
- *PageTop = *PageLength;
- }
- corrected = 1;
- }
- if (*PageBottom > *PageTop)
- {
- if (log) log(ld, CF_LOGLEVEL_ERROR,
- "Invalid values for page margins: Bottom: %.0f; Top: %.0f",
- *PageBottom, *PageTop);
- float swap = *PageBottom;
- *PageBottom = *PageTop;
- *PageTop = swap;
- corrected = 1;
- }
-
- if (pagesize->left >= 0 && pagesize->left <= *PageWidth)
- *PageLeft = pagesize->left;
- else
- {
- if (log) log(ld, CF_LOGLEVEL_ERROR,
- "Invalid value for page left margin: %.0f",
- pagesize->left);
- if (*PageWidth <= *PageLeft)
- *PageLeft = 0.0f;
- corrected = 1;
- }
- if (pagesize->right >= 0 && pagesize->right <= *PageWidth)
- *PageRight = pagesize->right;
- else
- {
- if (log) log(ld, CF_LOGLEVEL_ERROR,
- "Invalid value for page right margin: %.0f",
- pagesize->right);
- if (*PageWidth >= *PageLeft)
- *PageRight = *PageWidth - *PageLeft;
- else
- *PageRight = *PageWidth;
- corrected = 1;
- }
- if (*PageLeft == *PageRight)
- {
- if (log) log(ld, CF_LOGLEVEL_ERROR,
- "Invalid values for page margins: Left: %.0f; Right: %.0f",
- *PageLeft, *PageRight);
- *PageRight = *PageWidth - *PageLeft;
- if (*PageLeft == *PageRight)
- {
- *PageLeft = 0.0f;
- *PageRight = *PageWidth;
- }
- corrected = 1;
- }
- if (*PageLeft > *PageRight)
- {
- if (log) log(ld, CF_LOGLEVEL_ERROR,
- "Invalid values for page margins: Left: %.0f; Right: %.0f",
- *PageLeft, *PageRight);
- float swap = *PageLeft;
- *PageLeft = *PageRight;
- *PageRight = swap;
- corrected = 1;
- }
-
- if (corrected)
- {
- if (log) log(ld, CF_LOGLEVEL_ERROR,
- "PPD Page = %.0fx%.0f; %.0f,%.0f to %.0f,%.0f",
- pagesize->width, pagesize->length, pagesize->left,
- pagesize->bottom, pagesize->right, pagesize->top);
- if (log) log(ld, CF_LOGLEVEL_ERROR,
- "Corrected Page = %.0fx%.0f; %.0f,%.0f to %.0f,%.0f",
- *PageWidth, *PageLength, *PageLeft,
- *PageBottom, *PageRight, *PageTop);
- }
- else
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "Page = %.0fx%.0f; %.0f,%.0f to %.0f,%.0f",
- pagesize->width, pagesize->length, pagesize->left,
- pagesize->bottom, pagesize->right, pagesize->top);
- }
-
- if (ppd != NULL)
- {
- *ColorDevice = ppd->color_device;
- *LanguageLevel = ppd->language_level;
- }
-
- if ((val = cupsGetOption("landscape", num_options, options)) != NULL)
- {
- if (strcasecmp(val, "no") != 0 && strcasecmp(val, "off") != 0 &&
- strcasecmp(val, "false") != 0)
- {
- if (ppd && ppd->landscape > 0)
- *Orientation = 1;
- else
- *Orientation = 3;
- }
- }
- else if ((val = cupsGetOption("orientation-requested",
- num_options, options)) != NULL)
- {
- /*
- * Map IPP orientation values to 0 to 3:
- *
- * 3 = 0 degrees = 0
- * 4 = 90 degrees = 1
- * 5 = -90 degrees = 3
- * 6 = 180 degrees = 2
- */
-
- *Orientation = atoi(val) - 3;
- if (*Orientation >= 2)
- *Orientation ^= 1;
- }
-
- if ((val = cupsGetOption("page-left", num_options, options)) != NULL)
- {
- switch (*Orientation & 3)
- {
- case 0 :
- *PageLeft = (float)atof(val);
- break;
- case 1 :
- *PageBottom = (float)atof(val);
- break;
- case 2 :
- *PageRight = *PageWidth - (float)atof(val);
- break;
- case 3 :
- *PageTop = *PageLength - (float)atof(val);
- break;
- }
- }
-
- if ((val = cupsGetOption("page-right", num_options, options)) != NULL)
- {
- switch (*Orientation & 3)
- {
- case 0 :
- *PageRight = *PageWidth - (float)atof(val);
- break;
- case 1 :
- *PageTop = *PageLength - (float)atof(val);
- break;
- case 2 :
- *PageLeft = (float)atof(val);
- break;
- case 3 :
- *PageBottom = (float)atof(val);
- break;
- }
- }
-
- if ((val = cupsGetOption("page-bottom", num_options, options)) != NULL)
- {
- switch (*Orientation & 3)
- {
- case 0 :
- *PageBottom = (float)atof(val);
- break;
- case 1 :
- *PageLeft = (float)atof(val);
- break;
- case 2 :
- *PageTop = *PageLength - (float)atof(val);
- break;
- case 3 :
- *PageRight = *PageWidth - (float)atof(val);
- break;
- }
- }
-
- if ((val = cupsGetOption("page-top", num_options, options)) != NULL)
- {
- switch (*Orientation & 3)
- {
- case 0 :
- *PageTop = *PageLength - (float)atof(val);
- break;
- case 1 :
- *PageRight = *PageWidth - (float)atof(val);
- break;
- case 2 :
- *PageBottom = (float)atof(val);
- break;
- case 3 :
- *PageLeft = (float)atof(val);
- break;
- }
- }
-
- if (change_size)
- cfFilterUpdatePageVars(*Orientation, PageLeft, PageRight,
- PageTop, PageBottom, PageWidth, PageLength);
-
- if (ppdIsMarked(ppd, "Duplex", "DuplexNoTumble") ||
- ppdIsMarked(ppd, "Duplex", "DuplexTumble") ||
- ppdIsMarked(ppd, "JCLDuplex", "DuplexNoTumble") ||
- ppdIsMarked(ppd, "JCLDuplex", "DuplexTumble") ||
- ppdIsMarked(ppd, "EFDuplex", "DuplexNoTumble") ||
- ppdIsMarked(ppd, "EFDuplex", "DuplexTumble") ||
- ppdIsMarked(ppd, "EFDuplexing", "DuplexNoTumble") ||
- ppdIsMarked(ppd, "EFDuplexing", "DuplexTumble") ||
- ppdIsMarked(ppd, "ARDuplex", "DuplexNoTumble") ||
- ppdIsMarked(ppd, "ARDuplex", "DuplexTumble") ||
- ppdIsMarked(ppd, "KD03Duplex", "DuplexNoTumble") ||
- ppdIsMarked(ppd, "KD03Duplex", "DuplexTumble"))
- *Duplex = 1;
-
- return;
-}
-
-
-/*
- * 'cfFilterUpdatePageVars()' - Update the page variables for the orientation.
- */
-
-void
-cfFilterUpdatePageVars(int Orientation,
- float *PageLeft, float *PageRight,
- float *PageTop, float *PageBottom,
- float *PageWidth, float *PageLength)
-{
- float temp; /* Swapping variable */
-
-
- switch (Orientation & 3)
- {
- case 0 : /* Portait */
- break;
-
- case 1 : /* Landscape */
- temp = *PageLeft;
- *PageLeft = *PageBottom;
- *PageBottom = temp;
-
- temp = *PageRight;
- *PageRight = *PageTop;
- *PageTop = temp;
-
- temp = *PageWidth;
- *PageWidth = *PageLength;
- *PageLength = temp;
- break;
-
- case 2 : /* Reverse Portrait */
- temp = *PageWidth - *PageLeft;
- *PageLeft = *PageWidth - *PageRight;
- *PageRight = temp;
-
- temp = *PageLength - *PageBottom;
- *PageBottom = *PageLength - *PageTop;
- *PageTop = temp;
- break;
-
- case 3 : /* Reverse Landscape */
- temp = *PageWidth - *PageLeft;
- *PageLeft = *PageWidth - *PageRight;
- *PageRight = temp;
-
- temp = *PageLength - *PageBottom;
- *PageBottom = *PageLength - *PageTop;
- *PageTop = temp;
-
- temp = *PageLeft;
- *PageLeft = *PageBottom;
- *PageBottom = temp;
-
- temp = *PageRight;
- *PageRight = *PageTop;
- *PageTop = temp;
-
- temp = *PageWidth;
- *PageWidth = *PageLength;
- *PageLength = temp;
- break;
- }
-}
# include <cups/cups.h>
# include <cups/raster.h>
-# include <ppd/ppd.h>
/*
char *job_title; /* Job title or NULL */
int copies; /* Number of copies
(1 if filter(s) should not treat it) */
+ char *content_type; /* Input MIME type (CUPS env variable
+ CONTENT_TYPE) or NULL */
+ char *final_content_type; /* Output MIME type (CUPS env variable
+ FINAL_CONTENT_TYPE) or NULL */
ipp_t *job_attrs; /* IPP attributes passed along with the job */
ipp_t *printer_attrs; /* Printer capabilities in IPP format
(what is answered to get-printer-attributes */
+ cups_page_header2_t *header; /* CUPS/PWG Raster header (optional) */
int num_options;
cups_option_t *options; /* Job options as key/value pairs */
- char *ppdfile; /* PPD file name */
- ppd_file_t *ppd; /* PPD file data */
int back_pipe[2]; /* File descriptors of backchannel pipe */
int side_pipe[2]; /* File descriptors of sidechannel pipe */
+ cups_array_t *extension; /* Extension data */
cf_logfunc_t logfunc; /* Logging function, NULL for no logging */
void *logdata; /* User data for logging function, can be NULL */
cf_filter_iscanceledfunc_t iscanceledfunc; /* Function returning 1 when
NULL */
} cf_filter_data_t;
+typedef struct cf_filter_data_ext_s {
+ char* name;
+ void *ext;
+} cf_filter_data_ext_t;
+
typedef int (*cf_filter_function_t)(int inputfd, int outputfd,
int inputseekable, cf_filter_data_t *data,
void *parameters);
CF_FILTER_OUT_FORMAT_PXL /* PCL-XL */
} cf_filter_out_format_t;
-typedef struct cf_filter_external_cups_s { /* Parameters for the
- cfFilterExternalCUPS() filter
- function */
- const char *filter; /* Path/Name of the CUPS filter to be called by
- this filter function, required */
- int is_backend; /* 0 if we call a filter, 1 if we call a CUPS
- backend, 2 if we call a CUPS backend in
- device discovery mode */
- const char *device_uri; /* Device URI when calling a CUPS Backend for
- processing a job, optional, alternatively
- DEVICE_URI environment variable can get set
- in envp */
- int num_options; /* Extra options for the 5th command line */
- cups_option_t *options; /* argument, options of filter_data have
- priority, 0/NULL if none */
- char **envp; /* Additional environment variables, the already
- defined ones stay valid but can be overwritten
- by these ones, NULL if none */
-} cf_filter_external_cups_t;
-
typedef struct cf_filter_filter_in_chain_s { /* filter entry for CUPS array to
be supplied to cfFilterChain()
filter function */
universal function, and also
parameters for
cfFilterTextToPDF() */
- char *input_format;
- char *output_format;
+ char *actual_output_type;
cf_filter_texttopdf_parameter_t texttopdf_params;
} cf_filter_universal_parameter_t;
extern int cfCUPSIsCanceledFunc(void *data);
-extern int cfFilterCUPSWrapper(int argc,
- char *argv[],
- cf_filter_function_t filter,
- void *parameters,
- int *JobCanceled);
+extern void *cfFilterDataAddExt(cf_filter_data_t *data, const char *name,
+ void *ext);
-extern int cfFilterLoadPPD(cf_filter_data_t *data);
+extern void *cfFilterDataGetExt(cf_filter_data_t *data, const char *name);
-extern void cfFilterFreePPD(cf_filter_data_t *data);
+extern void *cfFilterDataRemoveExt(cf_filter_data_t *data, const char *name);
extern int cfFilterTee(int inputfd,
/* Parameters: Unsorted (!) CUPS array of cf_filter_filter_in_chain_t*
List of filters to execute in a chain, next filter takes output of
previous filter as input, all get the same filter data, parameters
- from the array */
-
-
-extern int cfFilterExternalCUPS(int inputfd,
- int outputfd,
- int inputseekable,
- cf_filter_data_t *data,
- void *parameters);
-
-/* Parameters: cf_filter_external_cups_t*
- Path/Name of the CUPS filter to be called by this filter function,
- extra options for the 5th command line argument, and extra environment
- variables */
+ are supplied individually in the array */
extern int cfFilterOpenBackAndSidePipes(cf_filter_data_t *data);
cf_filter_data_t *data,
void *parameters);
-/* Parameters: cf_filter_out_format_t*
- Ouput format: PDF, raster-only PDF, PCLm, PostScript, CUPS Raster,
+/* Requires specification of output format via data->final_content_type
+
+ Output formats: PDF, raster-only PDF, PCLm, PostScript, CUPS Raster,
PWG Raster, Apple Raster, PCL-XL
- Note: With the CF_FILTER_OUT_FORMAT_APPLE_RASTER selection and a
- Ghostscript version without "appleraster" output device (9.55.x and
- older) the output is actually CUPS Raster but information about
- available color spaces and depths is taken from the urf-supported
- printer IPP attribute or appropriate PPD file attribute. This mode
- is for further processing with rastertopwg. With Ghostscript
- supporting Apple Raster output (9.56.0 and newer), we actually
- produce Apple Raster and no further filter is required. */
+
+ Note: With the Apple Raster selection and a Ghostscript version
+ without "appleraster" output device (9.55.x and older) the output
+ is actually CUPS Raster but information about available color
+ spaces and depths is taken from the urf-supported printer IPP
+ attribute. This mode is for further processing with
+ rastertopwg. With Ghostscript supporting Apple Raster output
+ (9.56.0 and newer), we actually produce Apple Raster and no further
+ filter is required. */
extern int cfFilterBannerToPDF(int inputfd,
void *parameters);
-extern int cfFilterImageToPS(int inputfd,
- int outputfd,
- int inputseekable,
- cf_filter_data_t *data,
- void *parameters);
-
-
extern int cfFilterImageToRaster(int inputfd,
int outputfd,
int inputseekable,
cf_filter_data_t *data,
void *parameters);
-/* Parameters: cf_filter_out_format_t* Ouput format: CUPS Raster, PWG
- Raster, Apple Raster, PCLM
+/* Requires specification of output format via data->final_content_type
+
+ Output formats: CUPS Raster, PWG Raster, Apple Raster, PCLM
+
Note: On the Apple Raster, PWG Raster, and PCLm selection the
output is actually CUPS Raster but information about available
color spaces and depths is taken from the urf-supported or
- pwg-raster-document-type-supported printer IPP attributes or
- appropriate PPD file attributes. This mode is for further
+ pwg-raster-document-type-supported printer IPP attributes or from a
+ supplied CUPS Raster sample header. This mode is for further
processing with rastertopwg or rastertopclm. This can change in the
future when we add Apple Raster and PWG Raster output support to
this filter function. */
cf_filter_data_t *data,
void *parameters);
-/* Parameters: cf_filter_out_format_t*
- Ouput format: CUPS Raster, PWG Raster, Apple Raster, PCLm
+/* Requires specification of output format via data->final_content_type
+
+ Output formats: CUPS Raster, PWG Raster, Apple Raster, PCLm
+
Note: With CUPS Raster, Apple Raster, or PCLm selections the output
is actually PWG Raster but information about available color spaces
- and depths is taken from the pseudo-PostScript in the PPDs options,
- urf-supported printer IPP attribute or the appropriate PPD file
- attribute (PCLM is always sRGB 8-bit). These modes are for further
+ and depths is taken from the urf-supported printer IPP attribute,
+ the pclm- attributes, or from a supplied CUPS Raster sample header
+ (PCLM is always sGray/sRGB 8-bit). These modes are for further
processing with pwgtoraster or rastertopclm. This can change in the
future when MuPDF adds further output formats. */
cf_filter_data_t *data,
void *parameters);
-/* Parameters: cf_filter_out_format_t*
- Ouput format: CUPS Raster, Apple Raster, or PWG Raster */
+/* Requires specification of output format via data->final_content_type
+
+ Output formats: CUPS Raster, Apple Raster, or PWG Raster */
extern int cfFilterPDFToPDF(int inputfd,
cf_filter_data_t *data,
void *parameters);
-/* Parameters: const char*
- For CUPS value of FINAL_CONTENT_TYPE environment variable, generally
- MIME type of the final output format of the filter chain for this job
- (not the output of the cfFilterPDFToPDF() filter function) */
+/* (Optional) Specification of output format via
+ data->final_content_type is used for determining whether this
+ filter function does page logging for CUPS (output of "PAGE: XX YY"
+ log messages) or not and also to determine whether the printer or
+ driver generates copies or whether we have to send the pages
+ repeatedly.
-
-extern int cfFilterPDFToPS(int inputfd,
- int outputfd,
- int inputseekable,
- cf_filter_data_t *data,
- void *parameters);
+ Alternatively, the options "pdf-filter-page-logging",
+ "hardware-copies", and "hardware-collate" can be used to manually
+ do these selections. */
extern int cfFilterPDFToRaster(int inputfd,
cf_filter_data_t *data,
void* parameters);
-/* Parameters: cf_filter_out_format_t*
- Ouput format: CUPS Raster, PWG Raster, Apple Raster, PCLm
+/* Requires specification of output format via data->final_content_type
+
+ Output formats: CUPS Raster, PWG Raster, Apple Raster, PCLm
+
Note: With PCLm selection the output is actually CUPS Raster but
color space and depth will be 8-bit sRGB or SGray, the only color
spaces supported by PCLm. This mode is for further processing with
rastertopclm. */
-extern int cfFilterPSToPS(int inputfd,
- int outputfd,
- int inputseekable,
- cf_filter_data_t *data,
- void *parameters);
-
-
extern int cfFilterPWGToRaster(int inputfd,
int outputfd,
int inputseekable,
cf_filter_data_t *data,
void *parameters);
-/* Parameters: cf_filter_out_format_t*
- Ouput format: CUPS Raster, PWG Raster, Apple Raster, PCLm
- Note: On the PCLM selection the output is actually CUPS Raster
- but information about available color spaces and depths is taken from
- the pclm-... printer IPP attributes or appropriate PPD file
- attribute. This mode is for further processing with rastertopclm. */
+/* Requires specification of output format via data->final_content_type
+
+ Output formats: CUPS Raster, PWG Raster, Apple Raster, PCLm
+
+ Note: On the PCLM selection the output is actually CUPS Raster but
+ information about available color spaces and depths is taken from
+ the pclm-... printer IPP attributes. This mode is for further
+ processing with rastertopclm. */
extern int cfFilterRasterToPDF(int inputfd,
cf_filter_data_t *data,
void *parameters);
-/* Parameters: cf_filter_out_format_t*
- Ouput format: PDF, PCLm */
+/* Requires specification of output format via data->final_content_type
-
-extern int cfFilterRasterToPS(int inputfd,
- int outputfd,
- int inputseekable,
- cf_filter_data_t *data,
- void *parameters);
+ Output formats: PDF, PCLm */
extern int cfFilterRasterToPWG(int inputfd,
cf_filter_data_t *data,
void *parameters);
-/* Parameters: cf_filter_out_format_t*
- Ouput format: Apple Raster or PWG Raster */
+/* Requires specification of output format via data->final_content_type
+
+ Output formats: Apple Raster or PWG Raster */
extern int cfFilterTextToPDF(int inputfd,
void *parameters);
/* Parameters: cf_filter_texttopdf_parameter_t*
+
Data directory (fonts, charsets), charset, content type (for prettyprint),
classification (for overprint/watermark) */
cf_filter_data_t *data,
void *parameters);
-/* Parameters: cf_filter_universal_parameter_t
- Contains : Input_type: CONTENT_TYPE environment variable of CUPS
- Output type: FINAL_CONTENT TYPE environment variable of CUPS
- texttopdf_params: parameters for texttopdf */
-
-
-extern void cfFilterSetCommonOptions(ppd_file_t *ppd,
- int num_options,
- cups_option_t *options,
- int change_size,
- int *Orientation,
- int *Duplex,
- int *LanguageLevel,
- int *ColorDevice,
- float *PageLeft,
- float *PageRight,
- float *PageTop,
- float *PageBottom,
- float *PageWidth,
- float *PageLength,
- cf_logfunc_t log,
- void *ld);
-
-
-extern void cfFilterUpdatePageVars(int Orientation,
- float *PageLeft, float *PageRight,
- float *PageTop, float *PageBottom,
- float *PageWidth, float *PageLength);
+/* Requires specification of input format via data->content_type and
+ job's final output format via data->final_content_type
+
+ Parameters: cf_filter_universal_parameter_t
+
+ Contains: actual_output_type: Format which the filter should
+ actually produce if different from job's final output
+ format, otherwise NULL to produce the job's final output
+ format
+ texttopdf_params: parameters for texttopdf */
# ifdef __cplusplus
if (is_empty && buf[0] != '\n') is_empty = 0;
if (strncmp(buf,"%PDF",4) == 0) type = GS_DOC_TYPE_PDF;
if (strncmp(buf,"%!",2) == 0) type = GS_DOC_TYPE_PS;
+ if (type != GS_DOC_TYPE_UNKNOWN) break;
}
if (is_empty) type = GS_DOC_TYPE_EMPTY;
rewind(fp);
}
static void
-add_pdf_header_options(gs_page_header *h, cups_array_t *gs_args,
- cf_filter_out_format_t outformat, int pxlcolor)
+header_to_gs_args(gs_page_header *h, cups_array_t *gs_args,
+ cf_filter_out_format_t outformat, int pxlcolor)
{
int i;
char tmpstr[1024];
cups_cspace_t cspace = -1;
int bytes;
int fd;
- int cm_disabled;
+ int cm_disabled = 0;
int i;
int num_options;
int status = 1;
- ppd_file_t *ppd = NULL;
ipp_t *printer_attrs = data->printer_attrs;
ipp_t *job_attrs = data->job_attrs;
struct sigaction sa;
cf_cm_calibration_t cm_calibrate;
int pxlcolor = 0; /* 1 if printer is color printer otherwise 0. */
- ppd_attr_t *attr;
ipp_attribute_t *ipp_attr;
cf_logfunc_t log = data->logfunc;
void *ld = data->logdata;
void *icd = data->iscanceleddata;
- /* Note: With the CF_FILTER_OUT_FORMAT_APPLE_RASTER selection and a
- Ghostscript version without "appleraster" output device (9.55.x
- and older) the output is actually CUPS Raster but information
- about available color spaces and depths is taken from the
- urf-supported printer IPP attribute or appropriate PPD file
- attribute. This mode is for further processing with
- rastertopwg. With Ghostscript supporting Apple Raster output
- (9.56.0 and newer), we actually produce Apple Raster and no
- further filter is required. */
-
- if (parameters) {
+ if (parameters)
+ {
outformat = *(cf_filter_out_format_t *)parameters;
if (outformat != CF_FILTER_OUT_FORMAT_PDF &&
outformat != CF_FILTER_OUT_FORMAT_PDF_IMAGE &&
outformat != CF_FILTER_OUT_FORMAT_APPLE_RASTER &&
outformat != CF_FILTER_OUT_FORMAT_PXL)
outformat = CF_FILTER_OUT_FORMAT_CUPS_RASTER;
- } else
- outformat = CF_FILTER_OUT_FORMAT_CUPS_RASTER;
+ }
+ else
+ {
+ t = data->final_content_type;
+ if (t)
+ {
+ if (strcasestr(t, "pwg"))
+ outformat = CF_FILTER_OUT_FORMAT_PWG_RASTER;
+ else if (strcasestr(t, "urf"))
+ outformat = CF_FILTER_OUT_FORMAT_APPLE_RASTER;
+ else if (strcasestr(t, "pclm"))
+ outformat = CF_FILTER_OUT_FORMAT_PCLM;
+ else if (strcasestr(t, "pcl-xl"))
+ outformat = CF_FILTER_OUT_FORMAT_PXL;
+ else if (strcasestr(t, "pdf"))
+ outformat = CF_FILTER_OUT_FORMAT_PDF;
+ else
+ outformat = CF_FILTER_OUT_FORMAT_CUPS_RASTER;
+ }
+ else
+ outformat = CF_FILTER_OUT_FORMAT_CUPS_RASTER;
+ }
+
+ /* Note: With the CF_FILTER_OUT_FORMAT_APPLE_RASTER selection and a
+ Ghostscript version without "appleraster" output device (9.55.x
+ and older) the output is actually CUPS Raster but information
+ about available color spaces and depths is taken from the
+ urf-supported printer IPP attribute. This mode is for further
+ processing with rastertopwg. With Ghostscript supporting Apple
+ Raster output (9.56.0 and newer), we actually produce Apple
+ Raster and no further filter is required. */
if (log) log(ld, CF_LOGLEVEL_DEBUG,
"cfFilterGhostscript: Output format: %s",
num_options = data->num_options;
options = data->options;
- ppd = data->ppd;
-
/*
* Environment variables for Ghostscript call ...
*/
num_env ++;
}
- if (data->ppdfile)
- {
- snprintf(tmpstr, sizeof(tmpstr), "PPD=%s", data->ppdfile);
- envp[num_env] = strdup(tmpstr);
- num_env ++;
- }
-
if ((t = getenv("RIP_MAX_CACHE")) != NULL)
{
snprintf(tmpstr, sizeof(tmpstr), "RIP_MAX_CACHE=%s", t);
"cfFilterGhostscript: Streaming mode, no checks for input format, zero-page input, instructions from previous filter");
}
- /* Find print-rendering-intent */
- cfGetPrintRenderIntent(data, &h);
- if(log) log(ld, CF_LOGLEVEL_DEBUG,
- "Print rendering intent = %s", h.cupsRenderingIntent);
-
- /* Check status of color management in CUPS */
- cm_calibrate = cfCmGetCupsColorCalibrateMode(data, options, num_options);
-
- if (cm_calibrate == CF_CM_CALIBRATION_ENABLED)
- cm_disabled = 1;
- else
- cm_disabled = cfCmIsPrinterCmDisabled(data);
-
- if (!cm_disabled)
- cfCmGetPrinterIccProfile(data, &icc_profile, ppd);
-
/* Ghostscript parameters */
gs_args = cupsArrayNew(NULL, NULL);
if (!gs_args) {
strdup("-dColorConversionStrategy=/LeaveColorUnchanged"));
}
- cspace = icc_profile ? CUPS_CSPACE_RGB : -1;
+ /* Generate a pseudo Raster header to collect all data from the
+ printer and job attributes and also from the options which is
+ relevant for the Raster output. The header is not actually
+ inserted into the output Raster stream, but instead, converted to
+ command line options for Ghostscript by the header_to_gs_args()
+ function. Then Ghostscript generates the actual headers by
+ itself.
+
+ Ghostscript especially uses the sizes of each input page as
+ output page sizes and not the page size requested on the call of
+ this filter function. This means, for avoiding to send pages of
+ unsupported size to the printer, to pass the input data through
+ cfFilterPDFToPDF() before applying the cfFilterGhostscript()
+ filter function. */
+
+ cspace = -1;
cfRasterPrepareHeader(&h, data, outformat, outformat, 0, &cspace);
+ /* Find print-rendering-intent */
+ h.cupsRenderingIntent[0] = '\0';
+ cfGetPrintRenderIntent(data, h.cupsRenderingIntent,
+ sizeof(h.cupsRenderingIntent));
+ if(log) log(ld, CF_LOGLEVEL_DEBUG,
+ "Print rendering intent = %s", h.cupsRenderingIntent);
+
+ /* Check status of color management in CUPS */
+ cm_calibrate = cfCmGetCupsColorCalibrateMode(data);
+
+ if (cm_calibrate == CF_CM_CALIBRATION_ENABLED)
+ cm_disabled = 1;
+ else
+ cm_disabled = cfCmIsPrinterCmDisabled(data);
+
+ if (!cm_disabled)
+ cfCmGetPrinterIccProfile(data, cfRasterColorSpaceString(h.cupsColorSpace),
+ h.MediaType, h.HWResolution[0], h.HWResolution[1],
+ &icc_profile);
+
/* Special Ghostscript options for raster-only PDF output */
/* We use PCLm instead of general raster PDF here if the printer
char c;
ipp_attr = NULL;
- attr = NULL;
if (outformat == CF_FILTER_OUT_FORMAT_PCLM || /* PCLm forced */
/* PCLm supported according to printer IPP attributes */
(printer_attrs &&
(ipp_attr =
ippFindAttribute(printer_attrs, "pclm-source-resolution-supported",
- IPP_TAG_ZERO)) != NULL) ||
- /* PCLm supported according to PPD file */
- (ppd &&
- (attr =
- ppdFindAttr(ppd, "cupsPclmSourceResolutionSupported", 0)) != NULL)) {
+ IPP_TAG_ZERO)) != NULL)) {
outformat = CF_FILTER_OUT_FORMAT_PCLM;
correct if needed */
res_x = h.HWResolution[0];
res_y = h.HWResolution[1];
- if (attr)
- res_str = attr->value;
- else if (ipp_attr) {
+ if (ipp_attr) {
ippAttributeString(ipp_attr, tmpstr, sizeof(tmpstr));
res_str = tmpstr;
}
if (best_res_x > 0 && best_res_y > 0) {
snprintf(tmpstr, sizeof(tmpstr), "-r%dx%d", best_res_x, best_res_y);
cupsArrayAdd(gs_args, strdup(tmpstr));
- } else if ((printer_attrs &&
- (ipp_attr =
- ippFindAttribute(printer_attrs,
- "pclm-source-resolution-default",
- IPP_TAG_ZERO)) != NULL) ||
- (ppd &&
- (attr =
- ppdFindAttr(ppd,
- "cupsPclmSourceResolutionDefault", 0)) != NULL)){
- if (attr)
- res_str = attr->value;
- else if (ipp_attr) {
- ippAttributeString(ipp_attr, tmpstr, sizeof(tmpstr));
- res_str = tmpstr;
- }
- if (res_str)
- if ((n = sscanf(res_str, "%d%c%d",
- &best_res_x, &c, &best_res_y)) > 0) {
- if (n < 3 || (c != 'x' && c != 'X'))
- best_res_y = best_res_x;
- if (best_res_x > 0 && best_res_y > 0) {
- snprintf(tmpstr, sizeof(tmpstr), "-r%dx%d",
- best_res_x, best_res_y);
- cupsArrayAdd(gs_args, strdup(tmpstr));
- }
+ } else if (printer_attrs &&
+ (ipp_attr =
+ ippFindAttribute(printer_attrs,
+ "pclm-source-resolution-default",
+ IPP_TAG_ZERO)) != NULL) {
+ ippAttributeString(ipp_attr, tmpstr, sizeof(tmpstr));
+ if ((n = sscanf(tmpstr, "%d%c%d",
+ &best_res_x, &c, &best_res_y)) > 0) {
+ if (n < 3 || (c != 'x' && c != 'X'))
+ best_res_y = best_res_x;
+ if (best_res_x > 0 && best_res_y > 0) {
+ snprintf(tmpstr, sizeof(tmpstr), "-r%dx%d",
+ best_res_x, best_res_y);
+ cupsArrayAdd(gs_args, strdup(tmpstr));
}
+ }
}
if (best_res_x <= 0 || best_res_y <= 0) {
snprintf(tmpstr, sizeof(tmpstr), "-r%dx%d", res_x, res_y);
/* Strip/Band Height */
n = 0;
- if ((printer_attrs &&
- (ipp_attr =
- ippFindAttribute(printer_attrs,
- "pclm-strip-height-preferred",
- IPP_TAG_ZERO)) != NULL) ||
- (ppd &&
- (attr =
- ppdFindAttr(ppd,
- "cupsPclmStripHeightPreferred", 0)) != NULL)) {
- if (attr)
- n = atoi(attr->value);
- else if (ipp_attr)
- n = ippGetInteger(ipp_attr, 0);
- }
+ if (printer_attrs &&
+ (ipp_attr =
+ ippFindAttribute(printer_attrs,
+ "pclm-strip-height-preferred",
+ IPP_TAG_ZERO)) != NULL)
+ n = ippGetInteger(ipp_attr, 0);
if (n <= 0) n = 16;
snprintf(tmpstr, sizeof(tmpstr), "-dStripHeight=%d", n);
cupsArrayAdd(gs_args, strdup(tmpstr));
/* Compression method */
- if ((printer_attrs &&
- (ipp_attr =
- ippFindAttribute(printer_attrs,
- "pclm-compression-method-preferred",
- IPP_TAG_ZERO)) != NULL) ||
- (ppd &&
- (attr =
- ppdFindAttr(ppd,
- "cupsPclmCompressionMethodPreferred", 0)) != NULL)) {
- if (attr)
- res_str = attr->value;
- else if (ipp_attr) {
- ippAttributeString(ipp_attr, tmpstr, sizeof(tmpstr));
- res_str = tmpstr;
- }
- if (res_str) {
- if (strcasestr(res_str, "flate"))
- cupsArrayAdd(gs_args, strdup("-sCompression=Flate"));
- else if (strcasestr(res_str, "rle"))
- cupsArrayAdd(gs_args, strdup("-sCompression=RLE"));
- else if (strcasestr(res_str, "jpeg"))
- cupsArrayAdd(gs_args, strdup("-sCompression=JPEG"));
- else
- cupsArrayAdd(gs_args, strdup("-sCompression=Flate"));
- } else
+ if (printer_attrs &&
+ (ipp_attr =
+ ippFindAttribute(printer_attrs,
+ "pclm-compression-method-preferred",
+ IPP_TAG_ZERO)) != NULL) {
+ ippAttributeString(ipp_attr, tmpstr, sizeof(tmpstr));
+ if (strcasestr(tmpstr, "flate"))
+ cupsArrayAdd(gs_args, strdup("-sCompression=Flate"));
+ else if (strcasestr(tmpstr, "rle"))
+ cupsArrayAdd(gs_args, strdup("-sCompression=RLE"));
+ else if (strcasestr(tmpstr, "jpeg"))
+ cupsArrayAdd(gs_args, strdup("-sCompression=JPEG"));
+ else
cupsArrayAdd(gs_args, strdup("-sCompression=Flate"));
} else
cupsArrayAdd(gs_args, strdup("-sCompression=Flate"));
/* Ghostscript output device and color/gray */
n = 0;
- if (ppd) {
- if ((attr = ppdFindAttr(ppd,"ColorDevice", 0)) != 0 &&
- (!strcasecmp(attr->value, "true") ||
- !strcasecmp(attr->value, "on") ||
- !strcasecmp(attr->value, "yes")))
- /* Color printer, according to PPD */
- n = 1;
- } else if (printer_attrs) {
- if (((ipp_attr =
- ippFindAttribute(printer_attrs,
- "color-supported", IPP_TAG_ZERO)) != NULL &&
- ippGetBoolean(ipp_attr, 0))) {
+ if (printer_attrs) {
+ if ((ipp_attr =
+ ippFindAttribute(printer_attrs,
+ "color-supported", IPP_TAG_ZERO)) != NULL &&
+ ippGetBoolean(ipp_attr, 0)) {
/* Color printer, according to printer attributes */
n = 1;
}
if (outformat == CF_FILTER_OUT_FORMAT_PXL)
{
- if (ppd)
- {
- {
- if ((attr = ppdFindAttr(ppd,"ColorDevice", 0)) != 0 &&
- (!strcasecmp(attr->value, "true") ||
- !strcasecmp(attr->value, "on") ||
- !strcasecmp(attr->value, "yes")))
- /* Color PCL XL printer, according to PPD */
- pxlcolor = 1;
- }
- }
- else if (printer_attrs)
+ if (printer_attrs)
{
- if (((ipp_attr =
- ippFindAttribute(printer_attrs,
- "color-supported", IPP_TAG_BOOLEAN)) != NULL &&
- ippGetBoolean(ipp_attr, 0))) {
+ if ((ipp_attr =
+ ippFindAttribute(printer_attrs,
+ "color-supported", IPP_TAG_BOOLEAN)) != NULL &&
+ ippGetBoolean(ipp_attr, 0)) {
/* Color PCL XL printer, according to printer attributes */
pxlcolor = 1;
}
!strncasecmp(val, "Rgbw", 4) ||
!strncasecmp(val, "Rgb", 3) ||
!strcasecmp(val, "auto"))
- {
pxlcolor = 1;
- }
else if(!strncasecmp(val, "Device", 6))
{
const char *ptr = val + 6;
if(strtol(ptr, (char **)&ptr, 10)>1) /* Printer seems to support
more then 1 color */
- {
pxlcolor = 1;
- }
}
}
}
h.Orientation = CUPS_ORIENT_0;
/* get all the data from the header and pass it to ghostscript */
- add_pdf_header_options (&h, gs_args, outformat, pxlcolor);
+ header_to_gs_args(&h, gs_args, outformat, pxlcolor);
+
+ /* CUPS Raster versions: 2 = compressed; 3 = uncompressed */
+ /* Requires Ghostscript 9.57 or later */
+ if (outformat == CF_FILTER_OUT_FORMAT_CUPS_RASTER &&
+ (t = cupsGetOption("cups-raster-version",
+ num_options, options)) != NULL &&
+ (!strcmp(t, "2") || !strcmp(t, "3")))
+ {
+ snprintf(tmpstr, sizeof(tmpstr), "-dcupsRasterVersion=%s", t);
+ cupsArrayAdd(gs_args, strdup(tmpstr));
+ }
+
+ /* Back side orientation for duplex printing: Normal, ManualTumble,
+ Rotated, Flipped */
+ /* When printing duplex, margins on the back side meeds to get swapped? */
+ /* Requires Ghostscript 9.57 or later */
+ if (h.Duplex)
+ {
+ int backside;
+ /* analyze options relevant to Duplex */
+ /* APDuplexRequiresFlippedMargin */
+ enum {
+ FM_NO,
+ FM_FALSE,
+ FM_TRUE
+ } flippedMargin;
+
+ backside = cfGetBackSideOrientation(data);
+
+ t = NULL;
+ flippedMargin = FM_NO;
+
+ if (backside >= 0)
+ {
+ flippedMargin = (backside & 16 ? FM_TRUE :
+ (backside & 8 ? FM_FALSE :
+ FM_NO));
+ backside &= 7;
+
+ if (backside == CF_BACKSIDE_MANUAL_TUMBLE)
+ t = "ManualTumble";
+ else if (backside == CF_BACKSIDE_ROTATED)
+ t = "Rotated";
+ else if (backside == CF_BACKSIDE_FLIPPED)
+ t = "Flipped";
+ else
+ t = "Normal";
+ }
+
+ if (t != NULL)
+ {
+ snprintf(tmpstr, sizeof(tmpstr), "-scupsBackSideOrientation=%s", t);
+ cupsArrayAdd(gs_args, strdup(tmpstr));
+ }
+
+ if (flippedMargin == FM_TRUE)
+ cupsArrayAdd(gs_args, strdup("-dcupsBackSideFlipMargins"));
+ }
+
+ /* Manual Copies needed (no device copies functionality available) */
+ /* Requires Ghostscript 9.57 or later */
+ if ((t = cupsGetOption("hardware-copies",
+ num_options, options)) != NULL &&
+ (!strcasecmp(t, "false") || !strcasecmp(t, "off") ||
+ !strcasecmp(t, "no")))
+ cupsArrayAdd(gs_args, strdup("-dcupsManualCopies"));
/* CUPS font path */
- if ((t = getenv("CUPS_FONTPATH")) == NULL)
- t = CUPS_FONTPATH;
- snprintf(tmpstr, sizeof(tmpstr), "-I%s", t);
- cupsArrayAdd(gs_args, strdup(tmpstr));
+ if ((t = cupsGetOption("cups-fontpath",
+ num_options, options)) != NULL &&
+ t[0] != '\0')
+ {
+ snprintf(tmpstr, sizeof(tmpstr), "-I%s", t);
+ cupsArrayAdd(gs_args, strdup(tmpstr));
+ }
/* Set the device output ICC profile */
if (icc_profile != NULL && icc_profile[0] != '\0') {
cupsArrayAdd(gs_args, strdup(tmpstr));
}
- if ((t = cupsGetOption("profile", num_options, options)) != NULL) {
+ if (!cm_disabled &&
+ (t = cupsGetOption("profile", num_options, options)) != NULL) {
snprintf(tmpstr, sizeof(tmpstr), "<</cupsProfile(%s)>>setpagedevice", t);
cupsArrayAdd(gs_args, strdup(tmpstr));
}
- /* Do we have a "center-of-pixel" command line option or
- "CenterOfPixel" PPD option set to "true"? In this case let
- Ghostscript use the center-of-pixel rule instead of the
- PostScript-standard any-part-of-pixel rule when filling a
- path. This improves the accuracy of graphics (like bar codes for
- example) on low-resolution printers (like label printers with
- typically 203 dpi). See
+ /* Do we have a "center-of-pixel" or "CenterOfPixel" command line
+ option set to "true"? In this case let Ghostscript use the
+ center-of-pixel rule instead of the PostScript-standard
+ any-part-of-pixel rule when filling a path. This improves the
+ accuracy of graphics (like bar codes for example) on
+ low-resolution printers (like label printers with typically 203
+ dpi). See
https://bugs.linuxfoundation.org/show_bug.cgi?id=1373 */
- if (((t = cupsGetOption("CenterOfPixel", num_options, options)) == NULL &&
- (t = cupsGetOption("center-of-pixel", num_options, options)) == NULL &&
- ppd && (attr = ppdFindAttr(ppd,"DefaultCenterOfPixel", NULL)) != NULL &&
- (!strcasecmp(attr->value, "true") ||
- !strcasecmp(attr->value, "on") ||
- !strcasecmp(attr->value, "yes"))) ||
- (t && (!strcasecmp(t, "true") || !strcasecmp(t, "on") ||
- !strcasecmp(t, "yes")))) {
+ if (((t = cupsGetOption("CenterOfPixel", num_options, options)) != NULL ||
+ (t = cupsGetOption("center-of-pixel", num_options, options)) != NULL) &&
+ (!strcasecmp(t, "true") || !strcasecmp(t, "on") ||
+ !strcasecmp(t, "yes"))) {
if (log) log(ld, CF_LOGLEVEL_DEBUG,
"cfFilterGhostscript: Ghostscript using Center-of-Pixel method to "
"fill paths.");
#include <cups/cups.h>
#include <string.h>
#include <ctype.h>
+#include <stdio.h>
#define DEBUG_printf(x)
#define DEBUG_puts(x)
*/
# include <cups/cups.h>
-# include <ppd/ppd.h>
# include <cups/backend.h>
# include <cups/sidechannel.h>
# include <string.h>
#include "config.h"
#include <cupsfilters/filter.h>
#include <cupsfilters/image.h>
-#include <cupsfilters/ppdgenerator.h>
+#include <cupsfilters/ipp.h>
#include <cupsfilters/raster.h>
+#include <cupsfilters/ipp.h>
#include <cupsfilters/image-private.h>
#include <math.h>
#include <ctype.h>
Collate, /* Collate copies? */
Copies, /* Number of copies */
Reverse, /* Output order */
- EvenDuplex; /* cupsEvenDuplex */
+ EvenDuplex; /* Duplex needs even number of pages? */
int Orientation, /* 0 = portrait, 1 = landscape, etc. */
Duplex, /* Duplexed? */
- LanguageLevel, /* Language level of printer */
Color; /* Print in color? */
float PageLeft, /* Left margin */
PageRight, /* Right margin */
cf_ib_t *row; /* Current row */
float gammaval; /* Gamma correction value */
float brightness; /* Gamma correction value */
- ppd_file_t *ppd; /* PPD file */
char linebuf[LINEBUFSIZE];
FILE *outputfp;
} imagetopdf_doc_t;
* Local functions...
*/
-static void emit_jcl_options(imagetopdf_doc_t *doc, FILE *fp, int copies);
#ifdef OUT_AS_HEX
static void out_hex(imagetopdf_doc_t *doc, cf_ib_t *, int, int);
#else
static int out_page_contents(imagetopdf_doc_t *doc, int contentsObj);
static int out_image(imagetopdf_doc_t *doc, int imgObj);
-static void emit_jcl_options(imagetopdf_doc_t *doc, FILE *fp, int copies)
-{
- int section;
- ppd_choice_t **choices;
- int i;
- char buf[1024];
- ppd_attr_t *attr;
- int pdftopdfjcl = 0;
- int datawritten = 0;
-
- if (doc->ppd == 0) return;
- if ((attr = ppdFindAttr(doc->ppd,"pdftopdfJCLBegin",NULL)) != NULL) {
- int n = strlen(attr->value);
- pdftopdfjcl = 1;
- for (i = 0;i < n;i++) {
- if (attr->value[i] == '\r' || attr->value[i] == '\n') {
- /* skip new line */
- continue;
- }
- fputc(attr->value[i],fp);
- datawritten = 1;
- }
- }
-
- snprintf(buf,sizeof(buf),"%d",copies);
- if (ppdFindOption(doc->ppd,"Copies") != NULL) {
- ppdMarkOption(doc->ppd,"Copies",buf);
- } else {
- if ((attr = ppdFindAttr(doc->ppd,"pdftopdfJCLCopies",buf)) != NULL) {
- fputs(attr->value,fp);
- datawritten = 1;
- } else if (pdftopdfjcl) {
- fprintf(fp,"Copies=%d;",copies);
- datawritten = 1;
- }
- }
- for (section = (int)PPD_ORDER_ANY;
- section <= (int)PPD_ORDER_PROLOG;section++) {
- int n;
-
- n = ppdCollect(doc->ppd,(ppd_section_t)section,&choices);
- for (i = 0;i < n;i++) {
- snprintf(buf,sizeof(buf),"pdftopdfJCL%s",
- ((ppd_option_t *)(choices[i]->option))->keyword);
- if ((attr = ppdFindAttr(doc->ppd,buf,choices[i]->choice)) != NULL) {
- fputs(attr->value,fp);
- datawritten = 1;
- } else if (pdftopdfjcl) {
- fprintf(fp,"%s=%s;",
- ((ppd_option_t *)(choices[i]->option))->keyword,
- choices[i]->choice);
- datawritten = 1;
- }
- }
- }
- if (datawritten) fputc('\n',fp);
-}
-
static void set_offset(imagetopdf_doc_t *doc, int obj)
{
doc->objects[obj].offset = doc->currentOffset;
return (0);
}
-/*
- * Copied ppd_decode() from CUPS which is not exported to the API
- */
-
-static int /* O - Length of decoded string */
-ppd_decode(char *string) /* I - String to decode */
-{
- char *inptr, /* Input pointer */
- *outptr; /* Output pointer */
-
-
- inptr = string;
- outptr = string;
-
- while (*inptr != '\0')
- if (*inptr == '<' && isxdigit(inptr[1] & 255))
- {
- /*
- * Convert hex to 8-bit values...
- */
-
- inptr ++;
- while (isxdigit(*inptr & 255))
- {
- if (isalpha(*inptr))
- *outptr = (tolower(*inptr) - 'a' + 10) << 4;
- else
- *outptr = (*inptr - '0') << 4;
-
- inptr ++;
-
- if (!isxdigit(*inptr & 255))
- break;
-
- if (isalpha(*inptr))
- *outptr |= tolower(*inptr) - 'a' + 10;
- else
- *outptr |= *inptr - '0';
-
- inptr ++;
- outptr ++;
- }
-
- while (*inptr != '>' && *inptr != '\0')
- inptr ++;
- while (*inptr == '>')
- inptr ++;
- }
- else
- *outptr++ = *inptr++;
-
- *outptr = '\0';
-
- return ((int)(outptr - string));
-}
-
/*
* 'cfFilterImageToPDF()' - Filter function to convert many common image file
* formats into PDF
imagetopdf_doc_t doc; /* Document information */
cups_page_header2_t h; /* CUPS Raster page header, to */
/* accommodate results of command */
- /* line parsing for PPD-less queue */
- ppd_choice_t *choice; /* PPD option choice */
- int num_options = 0; /* Number of print options */
- cups_option_t *options = NULL; /* Print options */
+ /* line and IPP parsing */
+ int num_options = 0; /* Number of print options */
+ cups_option_t *options = NULL; /* Print options */
const char *val; /* Option value */
float zoom; /* Zoom facter */
int xppi, yppi; /* Pixels-per-inch */
int hue, sat; /* Hue and saturation adjustment */
- int emit_jcl;
int pdf_printer = 0;
char tempfile[1024]; /* Name of file to print */
FILE *fp; /* Input file */
int deviceCopies = 1;
int deviceCollate = 0;
int deviceReverse = 0;
- ppd_attr_t *attr;
int pl, pr;
int fillprint = 0; /* print-scaling = fill */
int cropfit = 0; /* -o crop-to-fit = true */
ipp_t *printer_attrs = data->printer_attrs;
ipp_t *job_attrs = data->job_attrs;
ipp_attribute_t *ipp;
- int min_length = __INT32_MAX__, /* ppd->custom_min[1] */
- min_width = __INT32_MAX__, /* ppd->custom_min[0] */
- max_length = 0, /* ppd->custom_max[1] */
- max_width=0; /* ppd->custom_max[0] */
- float customLeft = 0.0, /* ppd->custom_margin[0] */
- customBottom = 0.0, /* ppd->custom_margin[1] */
- customRight = 0.0, /* ppd->custom_margin[2] */
- customTop = 0.0; /* ppd->custom_margin[3] */
+ cups_cspace_t cspace = (cups_cspace_t)(-1);
+ int min_length = __INT32_MAX__,
+ min_width = __INT32_MAX__,
+ max_length = 0,
+ max_width = 0;
+ float customLeft = 0.0,
+ customBottom = 0.0,
+ customRight = 0.0,
+ customTop = 0.0;
char defSize[41];
*/
if (printer_attrs != NULL) {
- int left, right, top, bottom;
- cfGenerateSizes(printer_attrs, &ipp, &min_length, &min_width,
- &max_length, &max_width, &bottom, &left, &right, &top,
- defSize);
+ int left, bottom, right, top;
+ cfGenerateSizes(printer_attrs, CF_GEN_SIZES_DEFAULT, NULL, &ipp,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ &min_width, &min_length, &max_width, &max_length,
+ &left, &bottom, &right, &top, defSize, NULL);
customLeft = left*72.0/2540.0;
+ customBottom = bottom*72.0/2540.0;
customRight = right*72.0/2540.0;
customTop = top*72.0/2540.0;
- customBottom = bottom*72.0/2540.0;
}
* Process job options...
*/
- doc.ppd = data->ppd;
- cfFilterSetCommonOptions(doc.ppd, num_options, options, 0,
- &doc.Orientation, &doc.Duplex,
- &doc.LanguageLevel, &doc.Color,
- &doc.PageLeft, &doc.PageRight,
- &doc.PageTop, &doc.PageBottom,
- &doc.PageWidth, &doc.PageLength,
- log, ld);
-
- /* The cfFilterSetCommonOptions() does not set doc.Color
- according to option settings (user's demand for color/gray),
- so we parse the options and set the mode here */
- cfRasterParseIPPOptions(&h, data, 0, 1);
- if (doc.Color)
- doc.Color = h.cupsNumColors <= 1 ? 0 : 1;
- if (!doc.ppd) {
- /* Without PPD use also the other findings of cfRasterParseIPPOptions() */
- doc.Orientation = h.Orientation;
- doc.Duplex = h.Duplex;
- doc.PageWidth = h.cupsPageSize[0] != 0.0 ? h.cupsPageSize[0] :
- (float)h.PageSize[0];
- doc.PageLength = h.cupsPageSize[1] != 0.0 ? h.cupsPageSize[1] :
- (float)h.PageSize[1];
- doc.PageLeft = h.cupsImagingBBox[0] != 0.0 ? h.cupsImagingBBox[0] :
- (float)h.ImagingBoundingBox[0];
- doc.PageBottom = h.cupsImagingBBox[1] != 0.0 ? h.cupsImagingBBox[1] :
- (float)h.ImagingBoundingBox[1];
- doc.PageRight = h.cupsImagingBBox[2] != 0.0 ? h.cupsImagingBBox[2] :
- (float)h.ImagingBoundingBox[2];
- doc.PageTop = h.cupsImagingBBox[3] != 0.0 ? h.cupsImagingBBox[3] :
- (float)h.ImagingBoundingBox[3];
- doc.Flip = h.MirrorPrint ? 1 : 0;
- doc.Collate = h.Collate ? 1 : 0;
- doc.Copies = h.NumCopies;
- }
+ /* To find the correct output color space, resolution page size, ...
+ and to parse all releveant command line options we run
+ cfRasterPrepareHeader() here and afterwards we simply take the
+ needed parameters from the header. */
+ cfRasterPrepareHeader(&h, data, CF_FILTER_OUT_FORMAT_CUPS_RASTER,
+ CF_FILTER_OUT_FORMAT_CUPS_RASTER, 0, &cspace);
+ doc.Color = h.cupsNumColors <= 1 ? 0 : 1;
+ doc.Orientation = h.Orientation;
+ doc.Duplex = h.Duplex;
+ doc.PageWidth = h.cupsPageSize[0] != 0.0 ? h.cupsPageSize[0] :
+ (float)h.PageSize[0];
+ doc.PageLength = h.cupsPageSize[1] != 0.0 ? h.cupsPageSize[1] :
+ (float)h.PageSize[1];
+ doc.PageLeft = h.cupsImagingBBox[0] != 0.0 ? h.cupsImagingBBox[0] :
+ (float)h.ImagingBoundingBox[0];
+ doc.PageBottom = h.cupsImagingBBox[1] != 0.0 ? h.cupsImagingBBox[1] :
+ (float)h.ImagingBoundingBox[1];
+ doc.PageRight = h.cupsImagingBBox[2] != 0.0 ? h.cupsImagingBBox[2] :
+ (float)h.ImagingBoundingBox[2];
+ doc.PageTop = h.cupsImagingBBox[3] != 0.0 ? h.cupsImagingBBox[3] :
+ (float)h.ImagingBoundingBox[3];
+ doc.Flip = h.MirrorPrint ? 1 : 0;
+ doc.Collate = h.Collate ? 1 : 0;
+ doc.Copies = data->copies;
- if (doc.Copies == 1
- && (choice = ppdFindMarkedChoice(doc.ppd,"Copies")) != NULL) {
- doc.Copies = atoi(choice->choice);
- }
if (doc.Copies == 0) doc.Copies = 1;
- if ((val = cupsGetOption("Duplex",num_options,options)) != 0 &&
- (!strcasecmp(val, "true") || !strcasecmp(val, "on") ||
- !strcasecmp(val, "yes"))) {
- /* for compatiblity */
- if (ppdFindOption(doc.ppd,"Duplex") != NULL) {
- ppdMarkOption(doc.ppd,"Duplex","True");
- ppdMarkOption(doc.ppd,"Duplex","On");
- doc.Duplex = 1;
- }
- } else if ((val = cupsGetOption("sides",num_options,options)) != 0 &&
- (!strcasecmp(val, "two-sided-long-edge") ||
- !strcasecmp(val, "two-sided-short-edge"))) {
- /* for compatiblity */
- if (ppdFindOption(doc.ppd,"Duplex") != NULL) {
- ppdMarkOption(doc.ppd,"Duplex","True");
- ppdMarkOption(doc.ppd,"Duplex","On");
- doc.Duplex = 1;
- }
- }
- if ((val = cupsGetOption("OutputOrder",num_options,options)) != 0 ||
- (val = cupsGetOption("outputorder", num_options, options))!=NULL) {
- if (!strcasecmp(val, "Reverse")) {
- doc.Reverse = 1;
- }
- } else if (doc.ppd) {
- /*
- * Figure out the right default output order from the PPD file...
- */
-
- if ((choice = ppdFindMarkedChoice(doc.ppd,"OutputOrder")) != 0) {
- doc.Reverse = !strcasecmp(choice->choice,"Reverse");
- } else if ((choice = ppdFindMarkedChoice(doc.ppd,"OutputBin")) != 0 &&
- (attr = ppdFindAttr(doc.ppd,"PageStackOrder",choice->choice)) != 0 &&
- attr->value) {
- doc.Reverse = !strcasecmp(attr->value,"Reverse");
- } else if ((attr = ppdFindAttr(doc.ppd,"DefaultOutputOrder",0)) != 0 &&
- attr->value) {
- doc.Reverse = !strcasecmp(attr->value,"Reverse");
- }
+ /* Do we need to print the pages in reverse order? */
+ if ((val = cupsGetOption("OutputOrder", num_options, options)) != NULL ||
+ (val = cupsGetOption("output-order", num_options, options)) != NULL ||
+ (val = cupsGetOption("page-delivery", num_options, options)) != NULL)
+ {
+ doc.Reverse = (strcasecmp(val, "Reverse") == 0 ||
+ strcasecmp(val, "reverse-order") == 0);
}
- else if(printer_attrs){
- /* If PPD file is NULL, we use printer attrs to determine if we need to print in reverse order */
- char *defaultoutbin = strdup("");
- const char* outbin;
- if ((ipp = ippFindAttribute(printer_attrs, "output-bin-default", IPP_TAG_ZERO))
- != NULL)
- defaultoutbin = strdup(ippGetString(ipp, 0, NULL));
- /* Find out on which position of the list of output bins the default one is,
- if there is no default bin, take the first of this list */
- int i = 0;
- if ((ipp = ippFindAttribute(printer_attrs, "output-bin-supported",
- IPP_TAG_ZERO)) != NULL) {
- int count = ippGetCount(ipp);
- for (i = 0; i < count; i ++) {
- outbin = ippGetString(ipp, i, NULL);
- if (outbin == NULL)
- continue;
- if (defaultoutbin == NULL) {
- defaultoutbin = strdup(outbin);
- break;
- } else if (strcasecmp(outbin, defaultoutbin) == 0)
- break;
- }
- }
- void *outbin_properties_octet;
- int octet_str_len;
- char outbin_properties[1024];
- int outputorderinfofound = 0;
- int faceupdown = 0;
- int firsttolast = 0;
- if ((ipp = ippFindAttribute(printer_attrs, "printer-output-tray",
- IPP_TAG_STRING)) != NULL &&
- i < ippGetCount(ipp)) {
- outbin_properties_octet = ippGetOctetString(ipp, i, &octet_str_len);
- memset(outbin_properties, 0, sizeof(outbin_properties));
- memcpy(outbin_properties, outbin_properties_octet,
- ((size_t)octet_str_len < sizeof(outbin_properties) - 1 ?
- (size_t)octet_str_len : sizeof(outbin_properties) - 1));
- if (strcasestr(outbin_properties, "pagedelivery=faceUp")) {
- outputorderinfofound = 1;
- faceupdown = -1;
- }
- if (strcasestr(outbin_properties, "stackingorder=lastToFirst"))
- firsttolast = -1;
- }
- if (outputorderinfofound == 0 && defaultoutbin &&
- strcasestr(defaultoutbin, "face-up"))
- faceupdown = -1;
- if (defaultoutbin)
- free (defaultoutbin);
- if (firsttolast * faceupdown < 0)
- doc.Reverse = 1;;
- }
+ else
+ doc.Reverse = cfIPPReverseOutput(printer_attrs, job_attrs);
/* adjust to even page when duplex */
- if (((val = cupsGetOption("cupsEvenDuplex",num_options,options)) != 0 &&
- (!strcasecmp(val, "true") || !strcasecmp(val, "on") ||
- !strcasecmp(val, "yes"))) ||
- ((attr = ppdFindAttr(doc.ppd,"cupsEvenDuplex",0)) != 0 &&
- (!strcasecmp(attr->value, "true")
- || !strcasecmp(attr->value, "on") ||
- !strcasecmp(attr->value, "yes")))) {
+ if ((val = cupsGetOption("even-duplex", num_options, options)) != 0 &&
+ (!strcasecmp(val, "true") || !strcasecmp(val, "on") ||
+ !strcasecmp(val, "yes")))
doc.EvenDuplex = 1;
- }
- if ((val = cupsGetOption("multiple-document-handling",
- num_options, options)) != NULL)
- {
+ // Collate
+ if ((val = cupsGetOption("Collate", num_options, options)) != NULL &&
+ (!strcasecmp(val, "true") || !strcasecmp(val, "on") ||
+ !strcasecmp(val, "yes")))
+ doc.Collate = 1;
+ else if ((val = cupsGetOption("sheet-collate", num_options, options)) != NULL)
+ doc.Collate = (strcasecmp(val, "uncollated") != 0);
+ else if (((val = cupsGetOption("multiple-document-handling",
+ num_options, options)) != NULL &&
+ (strcasecmp(val, "separate-documents-collated-copies") == 0 ||
+ strcasecmp(val, "separate-documents-uncollated-copies") == 0 ||
+ strcasecmp(val, "single-document") == 0 ||
+ strcasecmp(val, "single-document-new-sheet") == 0)) ||
+ (val = cfIPPAttrEnumValForPrinter(printer_attrs, job_attrs,
+ "multiple-document-handling")) !=
+ NULL)
/*
- * This IPP attribute is unnecessarily complicated...
+ * This IPP attribute is unnecessarily complicated:
*
- * single-document, separate-documents-collated-copies, and
- * single-document-new-sheet all require collated copies.
+ * single-document, separate-documents-collated-copies,
+ * single-document-new-sheet:
+ * -> collate (true)
*
- * separate-documents-uncollated-copies allows for uncollated copies.
+ * separate-documents-uncollated-copies:
+ * -> can be uncollated (false)
*/
-
- doc.Collate = strcasecmp(val, "separate-documents-uncollated-copies") != 0;
- }
-
- if ((val = cupsGetOption("Collate", num_options, options)) != NULL ||
- (val = cupsGetOption("collate", num_options, options))) {
- if (strcasecmp(val, "True") == 0) {
- doc.Collate = 1;
- }
- } else {
- if ((choice = ppdFindMarkedChoice(doc.ppd,"Collate")) != NULL
- && (!strcasecmp(choice->choice,"true")
- || !strcasecmp(choice->choice, "on")
- || !strcasecmp(choice->choice, "yes"))) {
- doc.Collate = 1;
- }
- else if((ipp = ippFindAttribute(printer_attrs, "multiple-document-handling-default",
- IPP_TAG_ZERO))!=NULL){
- ippAttributeString(ipp, buf, sizeof(buf));
- val = buf;
- doc.Collate = strcasecmp(val, "separate-documents-uncollated-copies") != 0;
- }
- /* Still if we are having no clue about collate, pick any random value(1st in this case)
- from supported options */
- else if((ipp = ippFindAttribute(printer_attrs, "multiple-document-handling-supported",
- IPP_TAG_ZERO))!=NULL){
- ippAttributeString(ipp, buf, sizeof(buf));
- int i=0;
- for(i=0; buf[i]!='\0';i++){
- if(buf[i]==' ' || buf[i]==','){
- buf[i] = '\0';
- break;
- }
- }
- val = buf;
- doc.Collate = strcasecmp(val, "separate-documents-uncollated-copies") != 0;
- }
- }
+ doc.Collate =
+ (strcasecmp(val, "separate-documents-uncollated-copies") != 0);
if ((val = cupsGetOption("gamma", num_options, options)) != NULL)
doc.gammaval = atoi(val) * 0.001f;
strcasecmp(val, "True") == 0)
doc.Flip = 1;
- if ((val = cupsGetOption("emit-jcl", num_options, options)) != NULL &&
- (!strcasecmp(val, "false") || !strcasecmp(val, "off") ||
- !strcasecmp(val, "no") || !strcmp(val, "0")))
- emit_jcl = 0;
- else
- emit_jcl = 1;
-
-
/*
* Open the input image to print...
int fidelity = 0;
int document_large = 0;
- if (doc.ppd && (doc.ppd->custom_margins[0] || doc.ppd->custom_margins[1] ||
- doc.ppd->custom_margins[2] || doc.ppd->custom_margins[3]))
- // In case of custom margins
- margin_defined = 1;
- else if(customBottom!=0 || customLeft!=0 || customRight!=0 || customTop!=0)
- margin_defined = 1;
- if (doc.PageLength != doc.PageTop - doc.PageBottom ||
+ if (customLeft != 0 || customRight != 0 ||
+ customBottom != 0 || customTop != 0 ||
+ doc.PageLength != doc.PageTop - doc.PageBottom ||
doc.PageWidth != doc.PageRight - doc.PageLeft)
margin_defined = 1;
* Update the page size for custom sizes...
*/
- /* If size if specified by user, use it, else default size from
- printer_attrs*/
- if ((ipp = ippFindAttribute(job_attrs, "media-size", IPP_TAG_ZERO)) != NULL ||
- (val = cupsGetOption("MediaSize", num_options, options)) != NULL ||
- (ipp = ippFindAttribute(job_attrs, "page-size", IPP_TAG_ZERO)) != NULL ||
- (val = cupsGetOption("PageSize", num_options, options)) != NULL ) {
- if (val == NULL) {
- ippAttributeString(ipp, buf, sizeof(buf));
- strcpy(defSize, buf);
- }
- else
- snprintf(defSize, sizeof(defSize), "%s", val);
- }
-
-
+ strcpy(defSize, h.cupsPageSizeName);
- if (((choice = ppdFindMarkedChoice(doc.ppd, "PageSize")) != NULL &&
- strcasecmp(choice->choice, "Custom") == 0) ||
- strncasecmp(defSize, "custom", 6)==0)
+ if ((strncasecmp(defSize, "Custom", 6)) == 0 ||
+ strcasestr(defSize, "_custom_"))
{
float width, /* New width in points */
length; /* New length in points */
- char s[255]; /* New custom page size... */
/*
/*
* Add margins to page size...
*/
- if(doc.ppd!=NULL){
- width += doc.ppd->custom_margins[0] + doc.ppd->custom_margins[2];
- length += doc.ppd->custom_margins[1] + doc.ppd->custom_margins[3];
- }
- else{
- width += customLeft + customRight;
- length += customTop + customBottom;
- }
+
+ width += customLeft + customRight;
+ length += customTop + customBottom;
+
/*
* Enforce minimums...
*/
- if(doc.ppd!=NULL)
- {
- if(width<doc.ppd->custom_min[0])
- width = doc.ppd->custom_min[0];
- if(length<doc.ppd->custom_min[1])
- length = doc.ppd->custom_min[1];
- }
- else{
- if(width<min_width)
- width = min_width;
- if(length<min_length)
- length = min_length;
- }
+ if (width < min_width)
+ width = min_width;
+ if (length < min_length)
+ length = min_length;
if (log) log(ld, CF_LOGLEVEL_DEBUG,
"cfFilterImageToPDF: Updated custom page size to %.2f x %.2f "
* Set the new custom size...
*/
- sprintf(s, "Custom.%.0fx%.0f", width, length);
- ppdMarkOption(doc.ppd, "PageSize", s);
+ strcpy(h.cupsPageSizeName, "Custom");
+
+ h.cupsPageSize[0] = width + 0.5;
+ h.cupsPageSize[1] = length + 0.5;
+ h.PageSize[0] = width + 0.5;
+ h.PageSize[1] = length + 0.5;
/*
* Update page variables...
doc.PageWidth = width;
doc.PageLength = length;
- if (doc.ppd != NULL)
- doc.PageLeft = doc.ppd->custom_margins[0];
- else
- doc.PageLeft = customLeft;
- if (doc.ppd != NULL)
- doc.PageRight = width - doc.ppd->custom_margins[2];
- else
- doc.PageRight = width - customRight;
- if (doc.ppd != NULL)
- doc.PageBottom = doc.ppd->custom_margins[1];
- else
- doc.PageBottom = customBottom;
- if (doc.ppd != NULL)
- doc.PageTop = length - doc.ppd->custom_margins[3];
- else
- doc.PageTop = length - customTop;
+ doc.PageLeft = customLeft;
+ doc.PageRight = width - customRight;
+ doc.PageBottom = customBottom;
+ doc.PageTop = length - customTop;
}
if (doc.Copies == 1) {
/* collate is not needed */
doc.Collate = 0;
- ppdMarkOption(doc.ppd,"Collate","False");
}
+
if (!doc.Duplex) {
/* evenDuplex is not needed */
doc.EvenDuplex = 0;
}
- /* check collate device */
- if (doc.Collate) {
- if ((choice = ppdFindMarkedChoice(doc.ppd,"Collate")) != NULL &&
- !strcasecmp(choice->choice,"true")) {
- ppd_option_t *opt;
-
- if ((opt = ppdFindOption(doc.ppd,"Collate")) != NULL &&
- !opt->conflicted) {
- deviceCollate = 1;
- } else {
- ppdMarkOption(doc.ppd,"Collate","False");
- }
+ // Check options for caller's instructions about hardware copies/collate
+ if ((val = cupsGetOption("hardware-copies",
+ num_options, options)) != NULL)
+ {
+ if (!strcasecmp(val, "true") || !strcasecmp(val, "on") ||
+ !strcasecmp(val, "yes"))
+ {
+ // Use hardware copies according to the caller's instructions
+ deviceCopies = doc.Copies;
+ doc.Copies = 1;
}
}
- /* check OutputOrder device */
- if (doc.Reverse) {
- if (ppdFindOption(doc.ppd,"OutputOrder") != NULL) {
- deviceReverse = 1;
- }
+ else if (data->final_content_type &&
+ (strcasestr(data->final_content_type, "/pdf") ||
+ strcasestr(data->final_content_type, "/vnd.cups-pdf")))
+ {
+ // Caller did not tell us whether the printer does Hardware copies
+ // or not, so we assume hardware copies on PDF printers, and software
+ // copies on other (usually raster) printers or if we do not know the
+ // final output format.
+ deviceCopies = doc.Copies;
+ doc.Copies = 1;
}
- if (doc.ppd != NULL &&
- !doc.ppd->manual_copies && doc.Collate && !deviceCollate) {
+
+ if (deviceCopies > 1 && doc.Collate)
+ {
+ if ((val = cupsGetOption("hardware-collate",
+ num_options, options)) != NULL)
+ {
+ // Use hardware collate according to the caller's instructions
+ if (!strcasecmp(val, "true") || !strcasecmp(val, "on") ||
+ !strcasecmp(val, "yes"))
+ deviceCollate = 1;
+ }
+ else
+ // Check output format MIME type whether it is
+ // of a driverless IPP printer (PDF, Apple Raster, PWG Raster, PCLm).
+ // These printers do always hardware collate if they do hardware copies.
+ // https://github.com/apple/cups/issues/5433
+ deviceCollate = (data->final_content_type &&
+ (strcasestr(data->final_content_type, "/pdf") ||
+ strcasestr(data->final_content_type, "/vnd.cups-pdf") ||
+ strcasestr(data->final_content_type, "/pwg-raster") ||
+ strcasestr(data->final_content_type, "/urf") ||
+ strcasestr(data->final_content_type, "/PCLm")));
+ }
+
+ if (deviceCopies && doc.Collate && !deviceCollate)
+ {
/* Copying by device , software collate is impossible */
/* Enable software copying */
- doc.ppd->manual_copies = 1;
+ doc.Copies = deviceCopies;
+ deviceCopies = 1;
}
- if (doc.Copies > 1 && (doc.ppd == NULL || doc.ppd->manual_copies)
- && doc.Duplex) {
- /* Enable software collate , or same pages are printed in both sides */
- doc.Collate = 1;
- if (deviceCollate) {
- deviceCollate = 0;
- ppdMarkOption(doc.ppd,"Collate","False");
- }
+
+ if (doc.Copies > 1 && deviceCopies == 1 && doc.Duplex)
+ {
+ /* Enable software collate, or same pages are printed in both sides */
+ doc.Collate = 1;
+ if (deviceCollate)
+ deviceCollate = 0;
}
- if (doc.Duplex && doc.Collate && !deviceCollate) {
- /* Enable evenDuplex or the first page may be printed other side of the
- end of precedings */
+
+ if (doc.Duplex && doc.Collate && !deviceCollate)
+ /* Enable evenDuplex or the first page of the second copy may be
+ printed on the back side of the end of the first copy */
doc.EvenDuplex = 1;
- }
- if (doc.Duplex && doc.Reverse && !deviceReverse) {
+
+ if (doc.Duplex && doc.Reverse && !deviceReverse)
/* Enable evenDuplex or the first page may be empty. */
doc.EvenDuplex = 1;
- }
+
/* change feature for software */
- if (deviceCollate) {
+ if (deviceCollate)
doc.Collate = 0;
- }
+
if (deviceReverse) {
doc.Reverse = 0;
}
- if (doc.ppd != NULL) {
- if (doc.ppd->manual_copies) {
- /* sure disable hardware copying */
- ppdMarkOption(doc.ppd,"Copies","1");
- ppdMarkOption(doc.ppd,"JCLCopies","1");
- } else {
- /* change for hardware copying */
- deviceCopies = doc.Copies;
- doc.Copies = 1;
- }
- }
/*
* See if we need to collate, and if so how we need to do it...
/* collate is not needed, disable it */
deviceCollate = 0;
doc.Collate = 0;
- ppdMarkOption(doc.ppd,"Collate","False");
}
if (((doc.xpages*doc.ypages) % 2) == 0) {
doc.EvenDuplex = 0;
}
- /*
- * Write any "exit server" options that have been selected...
- */
-
- ppdEmit(doc.ppd, doc.outputfp, PPD_ORDER_EXIT);
-
- /*
- * Write any JCL commands that are needed to print PostScript code...
- */
-
- if (doc.ppd && emit_jcl) {
- /* pdftopdf only adds JCL to the job if the printer is a native PDF
- printer and the PPD is for this mode, having the "*JCLToPDFInterpreter:"
- keyword. We need to read this keyword manually from the PPD and replace
- the content of ppd->jcl_ps by the value of this keyword, so that
- ppdEmitJCL() actalually adds JCL based on the presence on
- "*JCLToPDFInterpreter:". */
- ppd_attr_t *attr;
- char buf[1024];
- int devicecopies_done = 0;
- char *old_jcl_ps = doc.ppd->jcl_ps;
- /* If there is a "Copies" option in the PPD file, assure that hardware
- copies are implemented as described by this option */
- if (ppdFindOption(doc.ppd,"Copies") != NULL && deviceCopies > 1)
- {
- snprintf(buf,sizeof(buf),"%d",deviceCopies);
- ppdMarkOption(doc.ppd,"Copies",buf);
- devicecopies_done = 1;
- }
- if ((attr = ppdFindAttr(doc.ppd,"JCLToPDFInterpreter",NULL)) != NULL)
- {
- if (deviceCopies > 1 && devicecopies_done == 0 && /* HW copies */
- strncmp(doc.ppd->jcl_begin, "\033%-12345X@", 10) == 0) /* PJL */
- {
- /* Add a PJL command to implement the hardware copies */
- const size_t size = strlen(attr->value) + 1 + 30;
- doc.ppd->jcl_ps = (char *)malloc(size * sizeof(char));
- if (deviceCollate)
- {
- snprintf(doc.ppd->jcl_ps, size, "@PJL SET QTY=%d\n%s",
- deviceCopies, attr->value);
- }
- else
- {
- snprintf(doc.ppd->jcl_ps, size, "@PJL SET COPIES=%d\n%s",
- deviceCopies, attr->value);
- }
- }
- else
- doc.ppd->jcl_ps = strdup(attr->value);
- ppd_decode(doc.ppd->jcl_ps);
- pdf_printer = 1;
- }
- else
- {
- doc.ppd->jcl_ps = NULL;
- pdf_printer = 0;
- }
- ppdEmitJCL(doc.ppd, doc.outputfp, data->job_id, data->job_user,
- data->job_title);
- emit_jcl_options(&doc, doc.outputfp, deviceCopies);
- free(doc.ppd->jcl_ps);
- doc.ppd->jcl_ps = old_jcl_ps; /* cups uses pool allocator, not free() */
- }
-
/*
* Start sending the document with any commands needed...
*/
* Close files...
*/
- if (emit_jcl)
- {
- if (doc.ppd && doc.ppd->jcl_end)
- ppdEmitJCLEnd(doc.ppd, doc.outputfp);
- }
-
cfImageClose(doc.img);
fclose(doc.outputfp);
close(outputfd);
#include <cupsfilters/filter.h>
#include <cupsfilters/raster.h>
#include <cupsfilters/colormanager.h>
-#include <cupsfilters/ppdgenerator.h>
+#include <cupsfilters/ipp.h>
#include <cupsfilters/image-private.h>
#include <unistd.h>
#include <math.h>
Copies; /* Number of copies */
int Orientation, /* 0 = portrait, 1 = landscape, etc. */
Duplex, /* Duplexed? */
- LanguageLevel, /* Language level of printer */
Color; /* Print in color? */
float PageLeft, /* Left margin */
PageRight, /* Right margin */
int xc0, yc0, /* Corners of the page in image
coords */
xc1, yc1;
- ppd_file_t *ppd; /* PPD file */
- ppd_choice_t *choice; /* PPD option choice */
cups_cspace_t cspace = -1; /* CUPS color space */
- char *resolution, /* Output resolution */
- *media_type; /* Media type */
- ppd_profile_t *profile; /* Color profile */
- ppd_profile_t userprofile; /* User-specified profile */
+ char *media_type; /* Media type */
cups_raster_t *ras; /* Raster stream */
cups_page_header2_t header; /* Page header */
int num_options = 0; /* Number of print options */
int fd; /* File descriptor for temp file */
char buf[BUFSIZ];
int bytes;
- cf_cm_calibration_t cm_calibrate; /* Are we color calibrating the
+ cf_cm_calibration_t cm_calibrate; /* Are we color calibrating the
device? */
- int cm_disabled; /* Color management disabled? */
+ int cm_disabled = 0;/* Color management disabled? */
int fillprint = 0; /* print-scaling = fill */
int cropfit = 0; /* -o crop-to-fit */
cf_logfunc_t log = data->logfunc;
ipp_t *printer_attrs = data->printer_attrs;
ipp_t *job_attrs = data->job_attrs;
ipp_attribute_t *ipp;
- int min_length = __INT32_MAX__, /* ppd->custom_min[1] */
- min_width = __INT32_MAX__, /* ppd->custom_min[0] */
- max_length = 0, /* ppd->custom_max[1] */
- max_width=0; /* ppd->custom_max[0] */
- float customLeft = 0.0, /* ppd->custom_margin[0] */
- customBottom = 0.0, /* ppd->custom_margin[1] */
- customRight = 0.0, /* ppd->custom_margin[2] */
- customTop = 0.0; /* ppd->custom_margin[3] */
+ int min_length = __INT32_MAX__,
+ min_width = __INT32_MAX__;
+ float customLeft = 0.0,
+ customBottom = 0.0,
+ customRight = 0.0,
+ customTop = 0.0;
char defSize[41];
cf_filter_out_format_t outformat;
/* Note: With the CF_FILTER_OUT_FORMAT_APPLE_RASTER,
- CF_FILTER_OUT_FORMAT_PWG_RASTER, or CF_FILTER_OUT_FORMAT_PCLM selections the
- output is actually CUPS Raster but information about available
- color spaces and depths are taken from the urf-supported or
- pwg-raster-document-type-supported printer IPP attributes or
- appropriate PPD file attributes (PCLM is always sRGB
- 8-bit). These modes are for further processing with rastertopwg
- or rastertopclm. This can change in the future when we add Apple
- Raster and PWG Raster output support to this filter. */
-
- if (parameters) {
- outformat = *(cf_filter_out_format_t *)parameters;
- if (outformat != CF_FILTER_OUT_FORMAT_PCLM &&
- outformat != CF_FILTER_OUT_FORMAT_CUPS_RASTER &&
- outformat != CF_FILTER_OUT_FORMAT_PWG_RASTER &&
- outformat != CF_FILTER_OUT_FORMAT_APPLE_RASTER)
- outformat = CF_FILTER_OUT_FORMAT_CUPS_RASTER;
- } else
- outformat = CF_FILTER_OUT_FORMAT_CUPS_RASTER;
+ CF_FILTER_OUT_FORMAT_PWG_RASTER, or CF_FILTER_OUT_FORMAT_PCLM
+ selections the output is actually CUPS Raster but information
+ about available color spaces and depths are taken from the
+ urf-supported or pwg-raster-document-type-supported printer IPP
+ attributes (PCLM is always sRGB 8-bit). These modes are for
+ further processing with rastertopwg or rastertopclm. This can
+ change in the future when we add Apple Raster and PWG Raster
+ output support to this filter. */
+
+ outformat = CF_FILTER_OUT_FORMAT_CUPS_RASTER;
+ val = data->final_content_type;
+ if (val) {
+ if (strcasestr(val, "pwg"))
+ outformat = CF_FILTER_OUT_FORMAT_PWG_RASTER;
+ else if (strcasestr(val, "urf"))
+ outformat = CF_FILTER_OUT_FORMAT_APPLE_RASTER;
+ else if (strcasestr(val, "pclm"))
+ outformat = CF_FILTER_OUT_FORMAT_PCLM;
+ }
if (log) log(ld, CF_LOGLEVEL_DEBUG,
"cfFilterImageToRaster: Final output format: %s",
(outformat == CF_FILTER_OUT_FORMAT_APPLE_RASTER ? "Apple Raster" :
"PCLm"))));
- if (printer_attrs != NULL) {
- int left, right, top, bottom;
- cfGenerateSizes(printer_attrs, &ipp, &min_length, &min_width,
- &max_length, &max_width, &bottom, &left, &right, &top,
- defSize);
- customLeft = left*72.0/2540.0;
- customRight = right*72.0/2540.0;
- customTop = top*72.0/2540.0;
- customBottom = bottom*72.0/2540.0;
- }
-
/*
* Make sure status messages are not buffered...
*/
signal(SIGPIPE, SIG_IGN);
+ if (printer_attrs != NULL) {
+ int minw, minl, maxw, maxl;
+ int left, bottom, right, top;
+ cfGenerateSizes(printer_attrs, CF_GEN_SIZES_DEFAULT, NULL, &ipp,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ &minw, &minl, &maxw, &maxl,
+ &left, &bottom, &right, &top,
+ defSize, NULL);
+ min_width = minw * 72 / 2540;
+ min_length = minl * 72 / 2540;
+ customLeft = left * 72.0 / 2540.0;
+ customBottom = bottom * 72.0 / 2540.0;
+ customRight = right * 72.0 / 2540.0;
+ customTop = top * 72.0 / 2540.0;
+ }
+
/*
* Initialize data structure
*/
*/
cfRasterPrepareHeader(&header, data, outformat,
- CF_FILTER_OUT_FORMAT_CUPS_RASTER, 1, &cspace);
- ppd = data->ppd;
+ CF_FILTER_OUT_FORMAT_CUPS_RASTER, 1, &cspace);
doc.Orientation = header.Orientation;
doc.Duplex = header.Duplex;
- doc.LanguageLevel = 1;
doc.Color = header.cupsNumColors>1?1:0;
doc.PageLeft = header.cupsImagingBBox[0] != 0.0 ?
header.cupsImagingBBox[0] :
/* Find print-rendering-intent */
- cfGetPrintRenderIntent(data, &header);
+ header.cupsRenderingIntent[0] = '\0';
+ cfGetPrintRenderIntent(data, header.cupsRenderingIntent,
+ sizeof(header.cupsRenderingIntent));
if(log) log(ld, CF_LOGLEVEL_DEBUG,
"cfFilterImageToRaster: Print rendering intent = %s",
header.cupsRenderingIntent);
if ((val = cupsGetOption("hue", num_options, options)) != NULL)
hue = atoi(val);
- if ((choice = ppdFindMarkedChoice(ppd, "MirrorPrint")) != NULL ||
- ((val = cupsGetOption("MirrorPrint", num_options, options)) != NULL) ||
- (ipp = ippFindAttribute(job_attrs, "mirror-print", IPP_TAG_ZERO)) !=
- NULL ||
+ if ((val = cupsGetOption("MirrorPrint", num_options, options)) != NULL ||
+ (val = cupsGetOption("mirror-print", num_options, options)) != NULL ||
+ (val = cupsGetOption("mirror", num_options, options)) != NULL ||
+ (ipp = ippFindAttribute(job_attrs, "mirror-print",
+ IPP_TAG_ZERO)) != NULL ||
(ipp = ippFindAttribute(printer_attrs, "mirror-print-default",
- IPP_TAG_ZERO))!=NULL)
+ IPP_TAG_ZERO)) != NULL)
{
- if (val != NULL)
- {
- /* We already found the value */
- }
- else if (ipp != NULL) {
+ if (val == NULL && ipp != NULL) {
ippAttributeString(ipp, buf, sizeof(buf));
val = buf;
}
- else
- {
- val = choice->choice;
- choice->marked = 0;
- }
}
- else
- val = cupsGetOption("mirror", num_options, options);
if (val && (!strcasecmp(val, "true") || !strcasecmp(val, "on") ||
!strcasecmp(val, "yes")))
doc.Flip = 1;
/*
- * Get the media type and resolution that have been chosen...
+ * Get the media type that have been chosen...
*/
- if ((choice = ppdFindMarkedChoice(ppd, "MediaType")) != NULL ||
- (val = cupsGetOption("MediaType", num_options, options)) != NULL ||
+ if ((val = cupsGetOption("MediaType", num_options, options)) != NULL ||
+ (val = cupsGetOption("media-type", num_options, options)) != NULL ||
(ipp = ippFindAttribute(job_attrs, "media-type", IPP_TAG_ZERO)) != NULL ||
(ipp = ippFindAttribute(printer_attrs, "media-type-supported",
- IPP_TAG_ZERO))!=NULL)
+ IPP_TAG_ZERO)) != NULL)
{
if (val != NULL)
- {
media_type = strdup(val);
- }
- else if(choice!=NULL)
- media_type = strdup(choice->choice);
- else if(ipp!=NULL){
+ else if (ipp != NULL)
media_type = strdup(ippGetString(ipp, 0, NULL));
- }
}
else
media_type = strdup("");
- if ((choice = ppdFindMarkedChoice(ppd, "Resolution")) != NULL)
- resolution = strdup(choice->choice);
- else if ((val = cupsGetOption("Resolution", num_options, options)) != NULL ||
- (ipp = ippFindAttribute(job_attrs, "printer-resolution",
- IPP_TAG_ZERO))!=NULL)
- {
- if (val == NULL) {
- ippAttributeString(ipp, buf, sizeof(buf));
- resolution = strdup(buf);
- }
- else
- {
- resolution = strdup(val);
- }
- }
- else if ((ipp = ippFindAttribute(printer_attrs, "printer-resolution-default",
- IPP_TAG_ZERO)) != NULL)
- {
- ippAttributeString(ipp, buf, sizeof(buf));
- resolution = strdup(buf);
- }
- else if((ipp = ippFindAttribute(printer_attrs,
- "printer-resolution-supported",
- IPP_TAG_ZERO)) != NULL)
- {
- ippAttributeString(ipp, buf, sizeof(buf));
- resolution = strdup(buf);
- for (i = 0; resolution[i] != '\0'; i++)
- {
- if (resolution[i]==' ' ||
- resolution[i]==',')
- {
- resolution[i] = '\0';
- break;
- }
- }
- }
- else
- resolution = strdup("300dpi");
- if(log) log(ld, CF_LOGLEVEL_DEBUG, "Resolution = %s", resolution);
-
/* support the "cm-calibration" option */
- cm_calibrate = cfCmGetCupsColorCalibrateMode(data, options, num_options);
+ cm_calibrate = cfCmGetCupsColorCalibrateMode(data);
if (cm_calibrate == CF_CM_CALIBRATION_ENABLED)
cm_disabled = 1;
}
/*
- * Find a color profile matching the current options...
+ * Apply a color profile...
*/
if ((val = cupsGetOption("profile", num_options, options)) != NULL &&
!cm_disabled)
{
- profile = &userprofile;
- sscanf(val, "%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f",
- &(userprofile.density), &(userprofile.gamma),
- userprofile.matrix[0] + 0, userprofile.matrix[0] + 1,
- userprofile.matrix[0] + 2,
- userprofile.matrix[1] + 0, userprofile.matrix[1] + 1,
- userprofile.matrix[1] + 2,
- userprofile.matrix[2] + 0, userprofile.matrix[2] + 1,
- userprofile.matrix[2] + 2);
-
- userprofile.density *= 0.001f;
- userprofile.gamma *= 0.001f;
- userprofile.matrix[0][0] *= 0.001f;
- userprofile.matrix[0][1] *= 0.001f;
- userprofile.matrix[0][2] *= 0.001f;
- userprofile.matrix[1][0] *= 0.001f;
- userprofile.matrix[1][1] *= 0.001f;
- userprofile.matrix[1][2] *= 0.001f;
- userprofile.matrix[2][0] *= 0.001f;
- userprofile.matrix[2][1] *= 0.001f;
- userprofile.matrix[2][2] *= 0.001f;
- }
- else if (ppd != NULL && !cm_disabled)
- {
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterImageToRaster: Searching for profile \"%s/%s\"...",
- resolution, media_type);
+ float density; /* Ink density to use */
+ float gamma; /* Gamma correction to use */
+ float matrix[3][3]; /* Transform matrix */
- for (i = 0, profile = ppd->profiles; i < ppd->num_profiles;
- i ++, profile ++)
- {
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterImageToRaster: \"%s/%s\" = ", profile->resolution,
- profile->media_type);
-
- if ((strcmp(profile->resolution, resolution) == 0 ||
- profile->resolution[0] == '-') &&
- (strcmp(profile->media_type, media_type) == 0 ||
- profile->media_type[0] == '-'))
- {
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterImageToRaster: MATCH");
- break;
- }
- else
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterImageToRaster: no.");
- }
-
- /*
- * If we found a color profile, use it!
- */
-
- if (i >= ppd->num_profiles)
- profile = NULL;
+ sscanf(val, "%f,%f,%f,%f,%f,%f,%f,%f,%f,%f,%f",
+ &(density), &(gamma),
+ matrix[0] + 0, matrix[0] + 1, matrix[0] + 2,
+ matrix[1] + 0, matrix[1] + 1, matrix[1] + 2,
+ matrix[2] + 0, matrix[2] + 1, matrix[2] + 2);
+
+ density *= 0.001f;
+ gamma *= 0.001f;
+
+ matrix[0][0] *= 0.001f;
+ matrix[0][1] *= 0.001f;
+ matrix[0][2] *= 0.001f;
+ matrix[1][0] *= 0.001f;
+ matrix[1][1] *= 0.001f;
+ matrix[1][2] *= 0.001f;
+ matrix[2][0] *= 0.001f;
+ matrix[2][1] *= 0.001f;
+ matrix[2][2] *= 0.001f;
+
+ cfImageSetProfile(density, gamma, matrix);
}
- else
- profile = NULL;
-
- if (profile)
- cfImageSetProfile(profile->density, profile->gamma, profile->matrix);
cfImageSetRasterColorSpace(header.cupsColorSpace);
int fidelity = 0;
int document_large = 0;
- if (ppd != NULL && (ppd->custom_margins[0] || ppd->custom_margins[1] ||
- ppd->custom_margins[2] || ppd->custom_margins[3]))
- margin_defined = 1;
- else{
- if(customLeft!=0 || customRight!=0 || customBottom!=0 || customTop!=0)
- margin_defined = 1;
- }
-
- if (doc.PageLength != doc.PageTop - doc.PageBottom ||
+ if (customLeft != 0 || customRight != 0 ||
+ customBottom != 0 || customTop != 0 ||
+ doc.PageLength != doc.PageTop - doc.PageBottom ||
doc.PageWidth != doc.PageRight - doc.PageLeft)
- {
margin_defined = 1;
- }
if ((val = cupsGetOption("ipp-attribute-fidelity",
num_options, options)) != NULL)
*/
/* If size if specified by user, use it, else default size from
- printer_attrs*/
- if ((ipp = ippFindAttribute(job_attrs, "media-size", IPP_TAG_ZERO)) != NULL ||
- (val = cupsGetOption("MediaSize", num_options, options)) != NULL ||
- (ipp = ippFindAttribute(job_attrs, "page-size", IPP_TAG_ZERO)) != NULL ||
- (val = cupsGetOption("PageSize", num_options, options)) != NULL ) {
- if (val == NULL) {
- ippAttributeString(ipp, buf, sizeof(buf));
- strcpy(defSize, buf);
- }
- else
- snprintf(defSize, sizeof(defSize), "%s", val);
- }
+ printer_attrs */
+ strcpy(defSize, header.cupsPageSizeName);
- if (((choice = ppdFindMarkedChoice(ppd, "PageSize")) != NULL &&
- strcasecmp(choice->choice, "Custom") == 0) ||
- (strncasecmp(defSize, "Custom", 6)) == 0)
+ if ((strncasecmp(defSize, "Custom", 6)) == 0 ||
+ strcasestr(defSize, "_custom_"))
{
float width, /* New width in points */
length; /* New length in points */
/*
* Add margins to page size...
*/
- if(ppd!=NULL){
- width += ppd->custom_margins[0] + ppd->custom_margins[2];
- length += ppd->custom_margins[1] + ppd->custom_margins[3];
- }
- else{
- width += customLeft + customRight;
- length += customBottom + customTop;
- }
+
+ width += customLeft + customRight;
+ length += customBottom + customTop;
+
/*
* Enforce minimums...
*/
- if (ppd != NULL)
- {
- if (width < ppd->custom_min[0])
- width = ppd->custom_min[0];
- }
- else
- {
- if (width < min_width)
- width = min_width;
- }
- if (ppd != NULL) {
- if (length < ppd->custom_min[1])
- length = ppd->custom_min[1];
- }
- else
- {
- if(length < min_length)
- length = min_length;
- }
-
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterImageToRaster: Updated custom page size to %.2f x %.2f "
- "inches...",
- width / 72.0, length / 72.0);
+
+ if (width < min_width)
+ width = min_width;
+ if(length < min_length)
+ length = min_length;
+
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "cfFilterImageToRaster: Updated custom page size to %.2f x %.2f "
+ "inches...",
+ width / 72.0, length / 72.0);
/*
* Set the new custom size...
doc.PageWidth = width;
doc.PageLength = length;
- if (ppd != NULL)
- doc.PageLeft = ppd->custom_margins[0];
- else
- doc.PageLeft = customLeft;
- if (ppd != NULL)
- doc.PageRight = width - ppd->custom_margins[2];
- else
- doc.PageRight = width - customRight;
- if (ppd != NULL)
- doc.PageBottom = ppd->custom_margins[1];
- else
- doc.PageBottom = customBottom;
- if (ppd != NULL)
- doc.PageTop = length - ppd->custom_margins[3];
- else
- doc.PageTop = length - customTop;
+ doc.PageLeft = customLeft;
+ doc.PageRight = width - customRight;
+ doc.PageBottom = customBottom;
+ doc.PageTop = length - customTop;
/*
* Remove margins from page size...
*/
- if (ppd != NULL)
- {
- width -= ppd->custom_margins[0] + ppd->custom_margins[2];
- length -= ppd->custom_margins[1] + ppd->custom_margins[3];
- }
- else
- {
- width -= customLeft + customRight;
- length -= customTop + customBottom;
- }
+
+ width -= customLeft + customRight;
+ length -= customTop + customBottom;
/*
* Set the bitmap size...
header.cupsWidth = width * header.HWResolution[0] / 72.0;
header.cupsHeight = length * header.HWResolution[1] / 72.0;
+
} else {
/*
* Set the bitmap size...
if (xpages == 1 && ypages == 1)
doc.Collate = 0;
- slowcollate = doc.Collate && ppdFindOption(ppd, "Collate") == NULL;
- if (ppd != NULL)
- slowcopies = ppd->manual_copies;
- else
- slowcopies = 1;
+ /* We should also check printer-attrs here, but printer-attrs shows
+ hardware copies ("copies-supported = 1-99") and hardware collate
+ ("multiple-document-handling-supported =
+ separate-documents-uncollated-copies,
+ separate-documents-collated-copies") even on cheapest raster
+ printers */
+ slowcollate = doc.Collate &&
+ ((val = cupsGetOption("hardware-collate", num_options, options)) == NULL ||
+ !strcasecmp(val, "false") || !strcasecmp(val, "off") ||
+ !strcasecmp(val, "no"));
+ slowcopies =
+ ((val = cupsGetOption("hardware-copies", num_options, options)) == NULL ||
+ !strcasecmp(val, "false") || !strcasecmp(val, "off") ||
+ !strcasecmp(val, "no"));
if (doc.Copies > 1 && !slowcollate && !slowcopies)
{
*/
canceled:
- free(resolution);
free(media_type);
free(row);
cupsRasterClose(ras);
USA.
***/
-#ifdef HAVE_CONFIG_H
+/*
+ * Include necessary headers.
+ */
+
#include <config.h>
-#endif
#include <ctype.h>
+#include <limits.h>
#include <stdlib.h>
-#include <cups/cups.h>
-#include <cups/backend.h>
-#include <cupsfilters/ipp.h>
-#include <cupsfilters/ppdgenerator.h>
#include <errno.h>
#include <stdio.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/types.h>
-
-#if (CUPS_VERSION_MAJOR > 1) || (CUPS_VERSION_MINOR > 5)
-#define HAVE_CUPS_1_6 1
-#endif
+#include <cups/cups.h>
+#include <cups/backend.h>
+#include <cups/dir.h>
+#include <cups/pwg.h>
+#include <cupsfilters/ipp.h>
enum resolve_uri_converter_type /**** Resolving DNS-SD based URI ****/
{
return (uri ? strdup(uri) : NULL);
}
-#ifdef HAVE_CUPS_1_6
/* Check how the driverless support is provided */
int
cfCheckDriverlessSupport(const char* uri)
*driverless_info = CF_DRVLESS_FULL;
/* Request printer properties via IPP, for example to
- - generate a PPD file for the printer
- (mainly driverless-capable printers)
- - generally find capabilities, options, and default settinngs,
- - printers status: Accepting jobs? Busy? With how many jobs? */
+ - Find capabilities, options, and default settings
+ - Printer's status: Accepting jobs? Busy? With how many jobs?
+ - Generate a PPD file for the printer
+ (mainly driverless-capable printers with CUPS 2.x) */
cf_get_printer_attributes_log[0] = '\0';
}
-#endif /* HAVE_CUPS_1_6 */
-
const char* /* O - Attribute value as string */
cfIPPAttrEnumValForPrinter(ipp_t *printer_attrs, /* I - Printer attributes, same
as to respond
const char *attr_name)/* I - Attribute name */
{
ipp_attribute_t *attr;
- char valuebuffer[65536],
- printer_attr_name[256];
+ char printer_attr_name[256];
int i;
+ const char *res;
+
if ((printer_attrs == NULL && job_attrs == NULL) || attr_name == NULL)
return NULL;
as string */
if (job_attrs == NULL ||
(attr = ippFindAttribute(job_attrs, attr_name, IPP_TAG_ZERO)) == NULL)
- valuebuffer[0] = '\0';
+ res = NULL;
else
- ippAttributeString(attr, valuebuffer, sizeof(valuebuffer));
+ res = ippGetString(attr, 0, NULL);
/* Check the printer properties if supplied to see whether the job attribute
value is valid or if the job attribute was not supplied. Use printer
default value of job attribute is invalid or not supplied
If no printer attributes are supplied (NULL), simply accept the job
attribute value */
- if (printer_attrs) {
- if (valuebuffer[0]) {
+ if (printer_attrs)
+ {
+ if (res && res[0])
+ {
/* Check whether value is valid according to printer attributes */
snprintf(printer_attr_name, sizeof(printer_attr_name) - 1,
"%s-supported", attr_name);
if ((attr = ippFindAttribute(printer_attrs, printer_attr_name,
IPP_TAG_ZERO)) != NULL) {
for (i = 0; i < ippGetCount(attr); i ++)
- if (strcasecmp(valuebuffer, ippGetString(attr, i, NULL)) == 0)
+ if (strcasecmp(res, ippGetString(attr, i, NULL)) == 0)
break; /* Job attribute value is valid */
- if (i == ippGetCount(attr))
- valuebuffer[0] = '\0'; /* Job attribute value is not valid */
+ if (i == ippGetCount(attr))
+ res = NULL; /* Job attribute value is not valid */
}
}
- if (!valuebuffer[0]) {
+ if (!res || !res[0])
+ {
/* Use default value from printer attributes */
snprintf(printer_attr_name, sizeof(printer_attr_name) - 1,
"%s-default", attr_name);
if ((attr = ippFindAttribute(printer_attrs, printer_attr_name,
IPP_TAG_ZERO)) != NULL)
- ippAttributeString(attr, valuebuffer, sizeof(valuebuffer));
+ res = ippGetString(attr, 0, NULL);
}
}
- return (valuebuffer[0] ? strdup(valuebuffer) : NULL);
+ return (res);
}
+
int /* O - 1: Success; 0: Error */
cfIPPAttrIntValForPrinter(ipp_t *printer_attrs, /* I - Printer attributes, same
as to respond
*value = val;
return retval;
}
+
+
+int /* O - 1: Success; 0: Error */
+cfIPPAttrResolutionForPrinter(ipp_t *printer_attrs,/* I - Printer attributes */
+ ipp_t *job_attrs, /* I - Job attributes */
+ const char *attr_name,/* I - Attribute name */
+ int *xres, /* O - X resolution (dpi) */
+ int *yres) /* O - Y resolution (dpi) */
+
+{
+ int i;
+ ipp_attribute_t *attr;
+ char printer_attr_name[256];
+ int retval, x, y;
+ ipp_res_t units;
+
+ if ((printer_attrs == NULL && job_attrs == NULL))
+ return 0;
+
+ if (attr_name == NULL)
+ attr_name = "printer-resolution";
+
+ /* Check whether job got supplied the named attribute and read out its value
+ as integer */
+ if (job_attrs == NULL ||
+ (attr = ippFindAttribute(job_attrs, attr_name, IPP_TAG_ZERO)) == NULL)
+ retval = 0;
+ else
+ {
+ retval = 1;
+ x = ippGetResolution(attr, 0, &y, &units);
+ if (units == IPP_RES_PER_CM)
+ {
+ /* Get resolutions in dpi */
+ x = (int)((float)x * 2.54);
+ y = (int)((float)y * 2.54);
+ }
+ }
+
+ /* Check the printer properties if supplied to see whether the job attribute
+ value is valid or if the job attribute was not supplied. Use printer
+ default value of job attribute is invalid or not supplied
+ If no printer attributes are supplied (NULL), simply accept the job
+ attribute value */
+ if (printer_attrs) {
+ if (retval == 1) {
+ /* Check whether value is valid according to printer attributes */
+ snprintf(printer_attr_name, sizeof(printer_attr_name) - 1,
+ "%s-supported", attr_name);
+ if ((attr = ippFindAttribute(printer_attrs, printer_attr_name,
+ IPP_TAG_RANGE)) != NULL)
+ {
+ for (i = 0; i < ippGetCount(attr); i ++)
+ {
+ int sx, sy;
+ ipp_res_t su;
+ sx = ippGetResolution(attr, i, &sy, &su);
+ if (su == IPP_RES_PER_CM)
+ {
+ /* Get resolutions in dpi */
+ sx = (int)((float)sx * 2.54);
+ sy = (int)((float)sy * 2.54);
+ }
+ if ((x - sx) * (x - sx) < 10 &&
+ (y - sy) * (y - sy) < 10)
+ break; /* Job attribute value is valid */
+ }
+ if (i == ippGetCount(attr))
+ retval = 0; /* Job attribute value is not valid */
+ }
+ }
+ if (retval == 0) {
+ /* Use default value from printer attributes */
+ snprintf(printer_attr_name, sizeof(printer_attr_name) - 1,
+ "%s-default", attr_name);
+ if ((attr = ippFindAttribute(printer_attrs, printer_attr_name,
+ IPP_TAG_ZERO)) != NULL) {
+ retval = 1;
+ x = ippGetResolution(attr, 0, &y, &units);
+ if (units == IPP_RES_PER_CM)
+ {
+ /* Get resolutions in dpi */
+ x = (int)((float)x * 2.54);
+ y = (int)((float)y * 2.54);
+ }
+ }
+ }
+ }
+
+ if (retval == 1)
+ {
+ *xres = x;
+ *yres = y;
+ }
+ return retval;
+}
+
+
+int
+cfIPPReverseOutput(ipp_t *printer_attrs,
+ ipp_t *job_attrs)
+{
+ int i;
+ ipp_attribute_t *attr1, *attr2;
+ const char *val1, *val2;
+ char buf[1024];
+ int length;
+
+ // Figure out the right default output order from the IPP attributes...
+ if ((val1 = cfIPPAttrEnumValForPrinter(printer_attrs, job_attrs,
+ "output-bin")) != NULL)
+ {
+ // Find corresponding "printer-output-tray" entry
+ if ((attr1 = ippFindAttribute(printer_attrs, "output-bin-supported",
+ IPP_TAG_ZERO)) != NULL &&
+ (attr2 = ippFindAttribute(printer_attrs, "printer-output-tray",
+ IPP_TAG_ZERO)) != NULL)
+ {
+ for (i = 0; i < ippGetCount(attr1) && i < ippGetCount(attr2); i ++)
+ {
+ if ((val2 = ippGetString(attr1, i, 0)) != NULL &&
+ strcmp(val1, val2) == 0)
+ {
+ if ((val2 =
+ (const char *)ippGetOctetString(attr2, i, &length)) != NULL)
+ {
+ if (length > (int)(sizeof(buf) - 1))
+ length = (int)(sizeof(buf) - 1);
+ memcpy(buf, val2, length);
+ buf[length] = '\0';
+ if (strcasestr(buf, "stackingorder=firstToLast"))
+ return (0);
+ if (strcasestr(buf, "stackingorder=lastToFirst"))
+ return (1);
+ if (strcasestr(buf, "pagedelivery=faceDown"))
+ return (0);
+ if (strcasestr(buf, "pagedelivery=faceUp"))
+ return (1);
+ }
+ break;
+ }
+ }
+ }
+ // Check whether output bin name is "face-down" or "face-up"
+ if (strcasestr(val1, "face-down"))
+ return (0);
+ if (strcasestr(val1, "face-up"))
+ return (1);
+ }
+
+ // No hint of whether to print in original or reverse order. Usually this
+ // happens for a fax-out queue, where one has no output bin. Use original
+ // order then.
+ return (0);
+}
+
+
+#ifndef HAVE_STRLCPY
+/*
+ * 'strlcpy()' - Safely copy two strings.
+ */
+
+size_t /* O - Length of string */
+strlcpy(char *dst, /* O - Destination string */
+ const char *src, /* I - Source string */
+ size_t size) /* I - Size of destination string buffer */
+{
+ size_t srclen; /* Length of source string */
+
+
+ /*
+ * Figure out how much room is needed...
+ */
+
+ size --;
+
+ srclen = strlen(src);
+
+ /*
+ * Copy the appropriate amount...
+ */
+
+ if (srclen > size)
+ srclen = size;
+
+ memmove(dst, src, srclen);
+ dst[srclen] = '\0';
+
+ return (srclen);
+}
+#endif /* !HAVE_STRLCPY */
+
+/*
+ * 'cfStrFormatd()' - Format a floating-point number.
+ */
+
+char * /* O - Pointer to end of string */
+cfStrFormatd(char *buf, /* I - String */
+ char *bufend, /* I - End of string buffer */
+ double number, /* I - Number to format */
+ struct lconv *loc) /* I - Locale data */
+{
+ char *bufptr, /* Pointer into buffer */
+ temp[1024], /* Temporary string */
+ *tempdec, /* Pointer to decimal point */
+ *tempptr; /* Pointer into temporary string */
+ const char *dec; /* Decimal point */
+ int declen; /* Length of decimal point */
+
+
+ /*
+ * Format the number using the "%.12f" format and then eliminate
+ * unnecessary trailing 0's.
+ */
+
+ snprintf(temp, sizeof(temp), "%.12f", number);
+ for (tempptr = temp + strlen(temp) - 1;
+ tempptr > temp && *tempptr == '0';
+ *tempptr-- = '\0');
+
+ /*
+ * Next, find the decimal point...
+ */
+
+ if (loc && loc->decimal_point) {
+ dec = loc->decimal_point;
+ declen = (int)strlen(dec);
+ } else {
+ dec = ".";
+ declen = 1;
+ }
+
+ if (declen == 1)
+ tempdec = strchr(temp, *dec);
+ else
+ tempdec = strstr(temp, dec);
+
+ /*
+ * Copy everything up to the decimal point...
+ */
+
+ if (tempdec) {
+ for (tempptr = temp, bufptr = buf;
+ tempptr < tempdec && bufptr < bufend;
+ *bufptr++ = *tempptr++);
+
+ tempptr += declen;
+
+ if (*tempptr && bufptr < bufend) {
+ *bufptr++ = '.';
+
+ while (*tempptr && bufptr < bufend)
+ *bufptr++ = *tempptr++;
+ }
+
+ *bufptr = '\0';
+ } else {
+ strlcpy(buf, temp, (size_t)(bufend - buf + 1));
+ bufptr = buf + strlen(buf);
+ }
+
+ return (bufptr);
+}
+
+
+int
+cfCompareResolutions(void *resolution_a,
+ void *resolution_b,
+ void *user_data)
+{
+ cf_res_t *res_a = (cf_res_t *)resolution_a;
+ cf_res_t *res_b = (cf_res_t *)resolution_b;
+ int i, a, b;
+
+ /* Compare the pixels per square inch */
+ a = res_a->x * res_a->y;
+ b = res_b->x * res_b->y;
+ i = (a > b) - (a < b);
+ if (i) return i;
+
+ /* Compare how much the pixel shape deviates from a square, the
+ more, the worse */
+ a = 100 * res_a->y / res_a->x;
+ if (a > 100) a = 10000 / a;
+ b = 100 * res_b->y / res_b->x;
+ if (b > 100) b = 10000 / b;
+ return (a > b) - (a < b);
+}
+
+void *
+cfCopyResolution(void *resolution,
+ void *user_data)
+{
+ cf_res_t *res = (cf_res_t *)resolution;
+ cf_res_t *copy;
+
+ copy = (cf_res_t *)calloc(1, sizeof(cf_res_t));
+ if (copy) {
+ copy->x = res->x;
+ copy->y = res->y;
+ }
+
+ return copy;
+}
+
+void
+cfFreeResolution(void *resolution,
+ void *user_data)
+{
+ cf_res_t *res = (cf_res_t *)resolution;
+
+ if (res) free(res);
+}
+
+cups_array_t *
+cfNewResolutionArray()
+{
+ return cupsArrayNew3(cfCompareResolutions, NULL, NULL, 0,
+ cfCopyResolution, cfFreeResolution);
+}
+
+cf_res_t *
+cfNewResolution(int x,
+ int y)
+{
+ cf_res_t *res = (cf_res_t *)calloc(1, sizeof(cf_res_t));
+ if (res) {
+ res->x = x;
+ res->y = y;
+ }
+ return res;
+}
+
+/* Read a single resolution from an IPP attribute, take care of
+ obviously wrong entries (printer firmware bugs), ignoring
+ resolutions of less than 60 dpi in at least one dimension and
+ fixing Brother's "600x2dpi" resolutions. */
+cf_res_t *
+cfIPPResToResolution(ipp_attribute_t *attr,
+ int index)
+{
+ cf_res_t *res = NULL;
+ int x = 0, y = 0;
+ ipp_res_t units;
+
+ if (attr) {
+ ipp_tag_t tag = ippGetValueTag(attr);
+ int count = ippGetCount(attr);
+
+ if (tag == IPP_TAG_RESOLUTION && index < count) {
+ x = ippGetResolution(attr, index, &y, &units);
+ if (units == IPP_RES_PER_CM)
+ {
+ x = (int)(x * 2.54);
+ y = (int)(y * 2.54);
+ }
+ if (y == 2) y = x; /* Brother quirk ("600x2dpi") */
+ if (x >= 60 && y >= 60)
+ res = cfNewResolution(x, y);
+ }
+ }
+
+ return res;
+}
+
+cups_array_t *
+cfIPPAttrToResolutionArray(ipp_attribute_t *attr)
+{
+ cups_array_t *res_array = NULL;
+ cf_res_t *res;
+ int i;
+
+ if (attr) {
+ ipp_tag_t tag = ippGetValueTag(attr);
+ int count = ippGetCount(attr);
+
+ if (tag == IPP_TAG_RESOLUTION && count > 0) {
+ res_array = cfNewResolutionArray();
+ if (res_array) {
+ for (i = 0; i < count; i ++)
+ if ((res = cfIPPResToResolution(attr, i)) != NULL) {
+ if (cupsArrayFind(res_array, res) == NULL)
+ cupsArrayAdd(res_array, res);
+ cfFreeResolution(res, NULL);
+ }
+ }
+ if (cupsArrayCount(res_array) == 0) {
+ cupsArrayDelete(res_array);
+ res_array = NULL;
+ }
+ }
+ }
+
+ return res_array;
+}
+
+/* Build up an array of common resolutions and most desirable default
+ resolution from multiple arrays of resolutions with an optional
+ default resolution.
+ Call this function with each resolution array you find as "new", and
+ in "current" an array of the common resolutions will be built up.
+ You do not need to create an empty array for "current" before
+ starting. Initialize it with NULL.
+ "current_default" holds the default resolution of the array "current".
+ It will get replaced by "new_default" if "current_default" is either
+ NULL or a resolution which is not in "current" any more.
+ "new" and "new_default" will be deleted/freed and set to NULL after
+ each, successful or unsuccssful operation.
+ Note that when calling this function the addresses of the pointers
+ to the resolution arrays and default resolutions have to be given
+ (call by reference) as all will get modified by the function. */
+
+int /* 1 on success, 0 on failure */
+cfJoinResolutionArrays(cups_array_t **current,
+ cups_array_t **new_arr,
+ cf_res_t **current_default,
+ cf_res_t **new_default)
+{
+ cf_res_t *res;
+ int retval;
+
+ if (current == NULL || new_arr == NULL || *new_arr == NULL ||
+ cupsArrayCount(*new_arr) == 0) {
+ retval = 0;
+ goto finish;
+ }
+
+ if (*current == NULL) {
+ /* We are adding the very first resolution array, simply make it
+ our common resolutions array */
+ *current = *new_arr;
+ if (current_default) {
+ if (*current_default)
+ free(*current_default);
+ *current_default = (new_default ? *new_default : NULL);
+ }
+ return 1;
+ } else if (cupsArrayCount(*current) == 0) {
+ retval = 1;
+ goto finish;
+ }
+
+ /* Dry run: Check whether the two arrays have at least one resolution
+ in common, if not, do not touch the original array */
+ for (res = cupsArrayFirst(*current);
+ res; res = cupsArrayNext(*current))
+ if (cupsArrayFind(*new_arr, res))
+ break;
+
+ if (res) {
+ /* Reduce the original array to the resolutions which are in both
+ the original and the new array, at least one resolution will
+ remain. */
+ for (res = cupsArrayFirst(*current);
+ res; res = cupsArrayNext(*current))
+ if (!cupsArrayFind(*new_arr, res))
+ cupsArrayRemove(*current, res);
+ if (current_default) {
+ /* Replace the current default by the new one if the current default
+ is not in the array any more or if it is NULL. If the new default
+ is not in the list or NULL in such a case, set the current default
+ to NULL */
+ if (*current_default && !cupsArrayFind(*current, *current_default)) {
+ free(*current_default);
+ *current_default = NULL;
+ }
+ if (*current_default == NULL && new_default && *new_default &&
+ cupsArrayFind(*current, *new_default))
+ *current_default = cfCopyResolution(*new_default, NULL);
+ }
+ retval = 1;
+ } else
+ retval = 0;
+
+ finish:
+ if (new_arr && *new_arr) {
+ cupsArrayDelete(*new_arr);
+ *new_arr = NULL;
+ }
+ if (new_default && *new_default) {
+ free(*new_default);
+ *new_default = NULL;
+ }
+ return retval;
+}
+
+
+/*
+ * 'pwg_compare_sizes()' - Compare two media sizes...
+ */
+
+static int /* O - Result of comparison */
+pwg_compare_sizes(cups_size_t *a, /* I - First media size */
+ cups_size_t *b) /* I - Second media size */
+{
+ return (strcmp(a->media, b->media));
+}
+
+
+/*
+ * 'pwg_copy_size()' - Copy a media size.
+ */
+
+static cups_size_t * /* O - New media size */
+pwg_copy_size(cups_size_t *size) /* I - Media size to copy */
+{
+ cups_size_t *newsize = (cups_size_t *)calloc(1, sizeof(cups_size_t));
+ /* New media size */
+
+ if (newsize)
+ memcpy(newsize, size, sizeof(cups_size_t));
+
+ return (newsize);
+}
+
+
+int /* O - 1: Requested page size supported
+ 2: Requested page size supported
+ when rotated by 90 degrees
+ 0: No page size requested
+ -1: Requested size unsupported */
+cfGetPageDimensions(ipp_t *printer_attrs, /* I - Printer attributes */
+ ipp_t *job_attrs, /* I - Job attributes */
+ int num_options, /* I - Number of options */
+ cups_option_t *options, /* I - Options */
+ cups_page_header2_t *header, /* I - Raster page header */
+ int transverse_fit, /* I - Accept transverse fit? */
+ float *width, /* O - Width (in pt, 1/72 inches) */
+ float *height, /* O - Height */
+ float *left, /* O - Left margin */
+ float *bottom, /* O - Bottom margin */
+ float *right, /* O - Right margin */
+ float *top, /* O - Top margin */
+ char *name, /* O - Page size name */
+ ipp_t **media_col_entry)/* O - media-col-database record of
+ match */
+{
+ int i;
+ const char *attr_name;
+ char size_name_buf[IPP_MAX_NAME + 1];
+ int size_requested = 0;
+ const char * const media_size_attr_names[] = {
+ "Jmedia-col",
+ "Jmedia-size",
+ "Jmedia",
+ "JPageSize",
+ "JMediaSize",
+ "J", /* A raster header with media dimensions */
+ "jmedia-col",
+ "jmedia-size",
+ "jmedia",
+ "jPageSize",
+ "jMediaSize",
+ "j", /* A raster header with media dimensions */
+ "Dmedia-col-default",
+ "Dmedia-default",
+ };
+
+
+ if (name == NULL)
+ name = size_name_buf;
+ name[0] = '\0';
+
+ if (media_col_entry)
+ *media_col_entry = NULL;
+
+ /*
+ * Media from job_attrs and options, defaults from printer_attrs...
+ */
+
+ /* Go through all job attributes and options which could contain the
+ page size, afterwards go through the page size defaults in the
+ printer attributes */
+ for (i = 0;
+ i < sizeof(media_size_attr_names) / sizeof(media_size_attr_names[0]);
+ i ++)
+ {
+ ipp_attribute_t *attr = NULL; /* Job attribute */
+ char valstr[8192]; /* Attribute value string */
+ const char *value = NULL; /* Option value */
+ const char *name_ptr = NULL; /* Pointer to page size name */
+ int num_media_col = 0; /* Number of media-col values */
+ cups_option_t *media_col = NULL; /* media-col values */
+ int ipp_width = 0,
+ ipp_height = 0,
+ ipp_left = -1,
+ ipp_bottom = -1,
+ ipp_right = -1,
+ ipp_top = -1;
+
+ attr_name = media_size_attr_names[i];
+ if (*attr_name == 'J' ||
+ (transverse_fit && *attr_name == 'j')) /* Job attribute/option */
+ {
+ if (*(attr_name + 1) == '\0')
+ {
+ if (header)
+ {
+ /* Raster header */
+ if (header->cupsPageSize[0] > 0.0)
+ ipp_width = (int)(header->cupsPageSize[0] * 2540.0 / 72.0);
+ else if (header->PageSize[0] > 0)
+ ipp_width = (int)(header->PageSize[0] * 2540 / 72);
+ if (header->cupsPageSize[1] > 0.0)
+ ipp_height = (int)(header->cupsPageSize[1] * 2540.0 / 72.0);
+ else if (header->PageSize[1] > 0)
+ ipp_height = (int)(header->PageSize[1] * 2540 / 72);
+ if (header->ImagingBoundingBox[3] > 0)
+ {
+ if (header->cupsImagingBBox[0] >= 0.0)
+ ipp_left = (int)(header->cupsImagingBBox[0] * 2540.0 / 72.0);
+ else if (header->ImagingBoundingBox[0] >= 0)
+ ipp_left = (int)(header->ImagingBoundingBox[0] * 2540 / 72);
+ if (header->cupsImagingBBox[1] >= 0.0)
+ ipp_bottom = (int)(header->cupsImagingBBox[1] * 2540.0 / 72.0);
+ else if (header->ImagingBoundingBox[1] >= 0)
+ ipp_bottom = (int)(header->ImagingBoundingBox[1] * 2540 / 72);
+ if (header->cupsImagingBBox[2] > 0.0)
+ ipp_right = ipp_width -
+ (int)(header->cupsImagingBBox[2] * 2540.0 / 72.0);
+ else if (header->ImagingBoundingBox[2] > 0)
+ ipp_right = ipp_width -
+ (int)(header->ImagingBoundingBox[2] * 2540 / 72);
+ if (header->cupsImagingBBox[3] > 0.0)
+ ipp_top = ipp_height -
+ (int)(header->cupsImagingBBox[3] * 2540.0 / 72.0);
+ else if (header->ImagingBoundingBox[3] > 0)
+ ipp_top = ipp_height -
+ (int)(header->ImagingBoundingBox[3] * 2540 / 72);
+ }
+ else
+ ipp_left = ipp_bottom = ipp_right = ipp_top = 0;
+ }
+ else
+ continue;
+ }
+ else if ((attr = ippFindAttribute(job_attrs, attr_name + 1,
+ IPP_TAG_ZERO)) != NULL)
+ {
+ /* String from IPP attribute */
+ ippAttributeString(attr, valstr, sizeof(valstr));
+ value = valstr;
+ }
+ else if ((value = cupsGetOption(attr_name + 1, num_options,
+ options)) == NULL)
+ continue;
+ }
+ else if (*attr_name == 'D') /* Printer default */
+ {
+ if (*(attr_name + 1))
+ {
+ if ((attr = ippFindAttribute(printer_attrs, attr_name + 1,
+ IPP_TAG_ZERO)) != NULL)
+ {
+ /* String from IPP attribute */
+ ippAttributeString(attr, valstr, sizeof(valstr));
+ value = valstr;
+ }
+ else
+ continue;
+ }
+ else
+ continue;
+ }
+ else
+ continue;
+
+ if (value)
+ {
+ if (*value == '{')
+ {
+ /*
+ * String is a dictionary -> "media-col" value...
+ */
+
+ num_media_col = cupsParseOptions(value, 0, &media_col);
+
+ /* Actual size in dictionary? */
+ if ((value = cupsGetOption("media-size", num_media_col, media_col))
+ != NULL)
+ {
+ int num_media_size; /* Number of media-size values */
+ cups_option_t *media_size; /* media-size values */
+ const char *x_dimension, /* x-dimension value */
+ *y_dimension; /* y-dimension value */
+
+ num_media_size = cupsParseOptions(value, 0, &media_size);
+
+ if ((x_dimension = cupsGetOption("x-dimension", num_media_size, media_size)) != NULL && (y_dimension = cupsGetOption("y-dimension", num_media_size, media_size)) != NULL)
+ {
+ ipp_width = atoi(x_dimension);
+ ipp_height = atoi(y_dimension);
+ }
+
+ cupsFreeOptions(num_media_size, media_size);
+ }
+ /* Name in dictionary? Use only if actual dimensions are not supplied */
+ if ((ipp_width <= 0 || ipp_height <= 0) &&
+ (name_ptr = cupsGetOption("media-size-name",
+ num_media_col, media_col)) == NULL)
+ {
+ cupsFreeOptions(num_media_col, media_col);
+ continue;
+ }
+
+ /* Grab margins from media-col */
+ if ((value = cupsGetOption("media-left-margin",
+ num_media_col, media_col))
+ != NULL)
+ ipp_left = atoi(value);
+ if ((value = cupsGetOption("media-bottom-margin",
+ num_media_col, media_col))
+ != NULL)
+ ipp_bottom = atoi(value);
+ if ((value = cupsGetOption("media-right-margin",
+ num_media_col, media_col))
+ != NULL)
+ ipp_right = atoi(value);
+ if ((value = cupsGetOption("media-top-margin",
+ num_media_col, media_col))
+ != NULL)
+ ipp_top = atoi(value);
+ }
+ else
+ {
+ /*
+ * String is not dictionary, check also if it contains commas (list
+ * of media properties supplied via "media" CUPS option
+ */
+
+ char *ptr;
+ name_ptr = value;
+ if (strchr(value, ','))
+ {
+ /* Comma-separated list of media properties, supplied with "media"
+ CUPS option */
+ if (value != valstr)
+ {
+ /* Copy string for further manipulation */
+ strlcpy(valstr, value, sizeof(valstr));
+ value = valstr;
+ name_ptr = value;
+ }
+ for (ptr = (char *)value; *ptr;)
+ {
+ ptr ++;
+ if (*ptr == ',' || *ptr == '\0')
+ {
+ /* End of item name */
+ if (*ptr == ',')
+ {
+ *ptr = '\0';
+ ptr ++;
+ }
+ /* Find PWG media entry for the name, if we find one, the name
+ is actually a page size name */
+ if (pwgMediaForPWG(name_ptr) ||
+ pwgMediaForPPD(name_ptr) ||
+ pwgMediaForLegacy(name_ptr))
+ /* This is a page size name */
+ break;
+ else if (*ptr)
+ /* Next item */
+ name_ptr = ptr;
+ else
+ /* No further item */
+ name_ptr = NULL;
+ }
+ }
+ }
+ }
+ }
+
+ /* Get name from media */
+ if (name_ptr)
+ {
+ if (ipp_left == 0 && ipp_bottom == 0 &&
+ ipp_right == 0 && ipp_top == 0)
+ snprintf(name, IPP_MAX_NAME, "%.29s.Borderless", name_ptr);
+ else
+ strlcpy(name, name_ptr, IPP_MAX_NAME);
+ }
+
+ /* Landscape/Transverse fit */
+ if (*attr_name == 'j') /* Only job attributes/options */
+ {
+ int swap;
+
+ swap = ipp_width;
+ ipp_width = ipp_height;
+ ipp_height = swap;
+
+ swap = ipp_left;
+ ipp_left = ipp_top;
+ ipp_top = ipp_right;
+ ipp_right = ipp_bottom;
+ ipp_bottom = swap;
+ }
+
+ cupsFreeOptions(num_media_col, media_col);
+
+ /* We have a valid request for a page size */
+ if (*attr_name == 'J' || *attr_name == 'j')
+ size_requested = 1;
+
+ /* Validate collected information */
+ /* If we have a size, we use the size as search term (name = "" then),
+ if we have no size but a name, use the name, always pass in margins
+ if available */
+ cfGenerateSizes(printer_attrs, CF_GEN_SIZES_SEARCH, NULL, NULL,
+ &ipp_width, &ipp_height,
+ &ipp_left, &ipp_bottom, &ipp_right, &ipp_top,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, name,
+ media_col_entry);
+
+ /* Return resulting numbers */
+ if (ipp_width > 0 && ipp_height > 0 &&
+ ipp_left >= 0 && ipp_bottom >= 0 &&
+ ipp_right >= 0 && ipp_top >= 0)
+ {
+ if (width)
+ *width = ipp_width * 72.0 / 2540.0;
+ if (height)
+ *height = ipp_height * 72.0 / 2540.0;
+
+ if (left)
+ *left = ipp_left * 72.0 / 2540.0;
+ if (bottom)
+ *bottom = ipp_bottom * 72.0 / 2540.0;
+ if (right)
+ *right = ipp_right * 72.0 / 2540.0;
+ if (top)
+ *top = ipp_top * 72.0 / 2540.0;
+
+ return (*attr_name == 'J' ? 1 :
+ (*attr_name == 'j' ? 2 :
+ (size_requested ? -1 : 0)));
+ }
+ else if (media_col_entry)
+ *media_col_entry = NULL;
+ }
+ return (size_requested ? -1 : 0);
+}
+
+
+void
+cfGenerateSizes(ipp_t *response,
+ cf_gen_sizes_mode_t mode,
+ cups_array_t **sizes,
+ ipp_attribute_t **defattr,
+ int *width,
+ int *length,
+ int *left,
+ int *bottom,
+ int *right,
+ int *top,
+ int *min_width,
+ int *min_length,
+ int *max_width,
+ int *max_length,
+ int *custom_left,
+ int *custom_bottom,
+ int *custom_right,
+ int *custom_top,
+ char *size_name,
+ ipp_t **media_col_entry)
+{
+ ipp_attribute_t *default_attr,
+ *attr, /* xxx-supported */
+ *x_dim, *y_dim, /* Media dimensions */
+ *name; /* Media size name */
+ ipp_t *media_col, /* Media collection */
+ *media_size; /* Media size collection */
+ int i, x = 0, y = 0, count = 0;
+ pwg_media_t *pwg, *pwg_by_name; /* PWG media size */
+ int local_min_width, local_min_length,
+ local_max_width, local_max_length;
+ int local_left, local_right, local_bottom, local_top;
+ ipp_attribute_t *margin; /* media-xxx-margin attribute */
+ const char *psname;
+ const char *entry_name;
+ char size_name_buf[IPP_MAX_NAME + 1] = "";
+ pwg_media_t *search = NULL;
+ int search_width = 0,
+ search_length = 0,
+ search_left = -1,
+ search_bottom = -1,
+ search_right = -1,
+ search_top = -1,
+ borderless = 0;
+ long long min_border_mismatch = LLONG_MAX,
+ border_mismatch;
+
+
+ if (media_col_entry)
+ *media_col_entry = NULL;
+
+ if (custom_left == NULL)
+ custom_left = &local_left;
+ if ((attr = ippFindAttribute(response, "media-left-margin-supported",
+ IPP_TAG_INTEGER)) != NULL) {
+ for (i = 1, *custom_left = ippGetInteger(attr, 0), count = ippGetCount(attr);
+ i < count; i ++)
+ if (ippGetInteger(attr, i) < *custom_left)
+ *custom_left = ippGetInteger(attr, i);
+ } else
+ *custom_left = 635;
+
+ if (custom_bottom == NULL)
+ custom_bottom = &local_bottom;
+ if ((attr = ippFindAttribute(response, "media-bottom-margin-supported",
+ IPP_TAG_INTEGER)) != NULL) {
+ for (i = 1, *custom_bottom = ippGetInteger(attr, 0), count = ippGetCount(attr);
+ i < count; i ++)
+ if (ippGetInteger(attr, i) < *custom_bottom)
+ *custom_bottom = ippGetInteger(attr, i);
+ } else
+ *custom_bottom = 1270;
+
+ if (custom_right == NULL)
+ custom_right = &local_right;
+ if ((attr = ippFindAttribute(response, "media-right-margin-supported",
+ IPP_TAG_INTEGER)) != NULL) {
+ for (i = 1, *custom_right = ippGetInteger(attr, 0), count = ippGetCount(attr);
+ i < count; i ++)
+ if (ippGetInteger(attr, i) < *custom_right)
+ *custom_right = ippGetInteger(attr, i);
+ } else
+ *custom_right = 635;
+
+ if (custom_top == NULL)
+ custom_top = &local_top;
+ if ((attr = ippFindAttribute(response, "media-top-margin-supported",
+ IPP_TAG_INTEGER)) != NULL) {
+ for (i = 1, *custom_top = ippGetInteger(attr, 0), count = ippGetCount(attr);
+ i < count; i ++)
+ if (ippGetInteger(attr, i) < *custom_top)
+ *custom_top = ippGetInteger(attr, i);
+ } else
+ *custom_top = 1270;
+
+ if (mode != CF_GEN_SIZES_DEFAULT)
+ {
+ if (min_width == NULL)
+ min_width = &local_min_width;
+ *min_width = 0;
+ if (min_length == NULL)
+ min_length = &local_min_length;
+ *min_length = 0;
+ if (max_width == NULL)
+ max_width = &local_max_width;
+ *max_width = 0;
+ if (max_length == NULL)
+ max_length = &local_max_length;
+ *max_length = 0;
+ }
+
+ if (size_name == NULL)
+ {
+ size_name = size_name_buf;
+ size_name[0] = '\0';
+ }
+ if (mode == CF_GEN_SIZES_DEFAULT)
+ size_name[0] = '\0';
+ if (defattr == NULL && mode == CF_GEN_SIZES_DEFAULT)
+ defattr = &default_attr;
+ if (defattr &&
+ (*defattr = ippFindAttribute(response, "media-col-default",
+ IPP_TAG_BEGIN_COLLECTION)) != NULL) {
+ if (mode == CF_GEN_SIZES_DEFAULT &&
+ (attr = ippFindAttribute(ippGetCollection(*defattr, 0), "media-size",
+ IPP_TAG_BEGIN_COLLECTION)) != NULL) {
+ media_size = ippGetCollection(attr, 0);
+ x_dim = ippFindAttribute(media_size, "x-dimension", IPP_TAG_INTEGER);
+ y_dim = ippFindAttribute(media_size, "y-dimension", IPP_TAG_INTEGER);
+
+ if ((margin = ippFindAttribute(ippGetCollection(*defattr, 0),
+ "media-bottom-margin", IPP_TAG_INTEGER))
+ != NULL)
+ local_bottom = ippGetInteger(margin, 0);
+ else
+ local_bottom = *custom_bottom;
+ if (bottom)
+ *bottom = local_bottom;
+
+ if ((margin = ippFindAttribute(ippGetCollection(*defattr, 0),
+ "media-left-margin", IPP_TAG_INTEGER))
+ != NULL)
+ local_left = ippGetInteger(margin, 0);
+ else
+ local_left = *custom_left;
+ if (left)
+ *left = local_left;
+
+ if ((margin = ippFindAttribute(ippGetCollection(*defattr, 0),
+ "media-right-margin", IPP_TAG_INTEGER))
+ != NULL)
+ local_right = ippGetInteger(margin, 0);
+ else
+ local_right = *custom_right;
+ if (right)
+ *right = local_right;
+
+ if ((margin = ippFindAttribute(ippGetCollection(*defattr, 0),
+ "media-top-margin", IPP_TAG_INTEGER))
+ != NULL)
+ local_top = ippGetInteger(margin, 0);
+ else
+ local_top = *custom_top;
+ if (top)
+ *top = local_top;
+
+ if (x_dim && y_dim) {
+ x = ippGetInteger(x_dim, 0);
+ y = ippGetInteger(y_dim, 0);
+ if (x > 0 && y > 0 &&
+ (pwg = pwgMediaForSize(x, y)) != NULL) {
+ psname = (pwg->ppd != NULL ? pwg->ppd : pwg->pwg);
+ if (local_bottom == 0 && local_left == 0 &&
+ local_right == 0 && local_top == 0)
+ snprintf(size_name, IPP_MAX_NAME, "%s.Borderless", psname);
+ else
+ strlcpy(size_name, psname, IPP_MAX_NAME);
+ }
+ }
+ }
+ }
+ if (mode == CF_GEN_SIZES_DEFAULT &&
+ (pwg =
+ pwgMediaForPWG(ippGetString(ippFindAttribute(response,
+ "media-default",
+ IPP_TAG_ZERO), 0,
+ NULL))) != NULL) {
+ psname = (pwg->ppd != NULL ? pwg->ppd : pwg->pwg);
+ strlcpy(size_name, psname, IPP_MAX_NAME);
+ if (x <= 0 || y <= 0) {
+ x = pwg->width;
+ y = pwg->length;
+ }
+ }
+
+ if (mode == CF_GEN_SIZES_DEFAULT)
+ {
+ /* Output the default page size dimensions, 0 if no valid size found */
+ if (!size_name[0])
+ strlcpy(size_name, "Unknown", IPP_MAX_NAME);
+ if (width)
+ {
+ if (x > 0)
+ *width = x;
+ else
+ *width = 0;
+ }
+ if (length)
+ {
+ if (y > 0)
+ *length = y;
+ else
+ *length = 0;
+ }
+ }
+ else
+ {
+ /* Find the dimensions for the page size name we got as search term */
+ char *ptr;
+ int is_transverse = (strcasestr(size_name, ".Transverse") ? 1 : 0);
+ if (strcasestr(size_name, ".Fullbleed") ||
+ strcasestr(size_name, ".Borderless") ||
+ strcasestr(size_name, ".FB"))
+ mode = CF_GEN_SIZES_SEARCH_BORDERLESS_ONLY;
+ if (size_name != size_name_buf)
+ strlcpy(size_name_buf, size_name, IPP_MAX_NAME);
+ if ((ptr = strchr(size_name_buf, '.')) != NULL &&
+ strncasecmp(size_name_buf, "Custom.", 7) != 0)
+ *ptr = '\0';
+ if ((search = pwgMediaForPWG(size_name_buf)) == NULL)
+ if ((search = pwgMediaForPPD(size_name_buf)) == NULL)
+ search = pwgMediaForLegacy(size_name_buf);
+ if (search != NULL) {
+ /* Set the appropriate dimensions */
+ if (is_transverse)
+ {
+ search_width = search->length;
+ search_length = search->width;
+ }
+ else
+ {
+ search_width = search->width;
+ search_length = search->length;
+ }
+ }
+ else
+ {
+ /* Set the dimensions if we search by dimensions */
+ if (width)
+ search_width = *width;
+ if (length)
+ search_length = *length;
+ }
+ if (search_width <= 0 || search_length <= 0)
+ {
+ /* No valid search dimensions, de-activate searching and set 0 as
+ result */
+ mode = CF_GEN_SIZES_DEFAULT;
+ if (width)
+ *width = 0;
+ if (length)
+ *length = 0;
+ }
+ else
+ {
+ /* Check whether we have margin info so that we can search for a
+ size with similar/the same margins, otherwise set the margins
+ -1 to pick the first entry from the list which fits the size
+ dimensions (if there are variants of a size, the first entry
+ is usually the standard size) */
+ if (left && *left >= 0)
+ search_left = *left;
+ else
+ search_left = -1;
+ if (bottom && *bottom >= 0)
+ search_bottom = *bottom;
+ else
+ search_bottom = -1;
+ if (right && *right >= 0)
+ search_right = *right;
+ else
+ search_right = -1;
+ if (top && *top >= 0)
+ search_top = *top;
+ else
+ search_top = -1;
+ }
+ }
+
+ if (mode == CF_GEN_SIZES_DEFAULT &&
+ !sizes && !min_width && !max_width && !min_length && !max_length)
+ return;
+
+ if (sizes)
+ *sizes = cupsArrayNew3((cups_array_func_t)pwg_compare_sizes, NULL, NULL, 0,
+ (cups_acopy_func_t)pwg_copy_size,
+ (cups_afree_func_t)free);
+
+ if ((attr = ippFindAttribute(response, "media-col-database",
+ IPP_TAG_BEGIN_COLLECTION)) != NULL) {
+ for (i = 0, count = ippGetCount(attr); i < count; i ++) {
+ cups_size_t temp, temp_by_name; /* Current size */
+
+ media_col = ippGetCollection(attr, i);
+ media_size =
+ ippGetCollection(ippFindAttribute(media_col, "media-size",
+ IPP_TAG_BEGIN_COLLECTION), 0);
+ /* These are the numeric paper dimensions explicitly mentioned
+ in this media entry. if we were called in a retro-fitting
+ setup via a ppdFilter...() wrapper filter function of libppd,
+ these dimensions can deviate from the paper dimensions which
+ the PWG-style page size name in the same entry suggests. In
+ this case we match both sizes against the size requested for
+ the job and consider the entry as matching if one of the two
+ sizes matches. In this case the entry gets included in all
+ entries which are selected by the closest fit of the margins.
+
+ We do this as some PPD files (especially of HPLIP) contain
+ page size entries which are variants of a standard size with
+ the base name of a standard size (like "A4.Borderless", base
+ name "A4") but different dimensions.
+
+ Especially there are larger dimensions for borderless, for
+ overspraying over the borders of the sheet so that there will
+ be no faint white borders if the sheet is a little
+ mis-aligned.
+
+ So if such overspraying borderless size entry is present and
+ has zero margins while the standard size entry has regular
+ margins, this entry will get automatically selected if
+ borderless printing (standard size name or dimensions plus
+ zero margins) is selected.
+ */
+ x_dim = ippFindAttribute(media_size, "x-dimension", IPP_TAG_ZERO);
+ y_dim = ippFindAttribute(media_size, "y-dimension", IPP_TAG_ZERO);
+ // Move "if" for custom size parameters here
+ //if (ippGetValueTag(x_dim) == IPP_TAG_RANGE ||
+ // ippGetValueTag(y_dim) == IPP_TAG_RANGE) {
+ pwg = pwgMediaForSize(ippGetInteger(x_dim, 0),
+ ippGetInteger(y_dim, 0));
+ name = ippFindAttribute(media_col, "media-size-name",
+ IPP_TAG_ZERO);
+ pwg_by_name = NULL;
+ if (name)
+ {
+ entry_name = ippGetString(name, 0, NULL);
+ if (entry_name)
+ pwg_by_name = pwgMediaForPWG(entry_name);
+ }
+
+ if (pwg || pwg_by_name) {
+ if (!sizes && mode == CF_GEN_SIZES_DEFAULT)
+ continue;
+
+ if (pwg)
+ {
+ temp.width = pwg->width;
+ temp.length = pwg->length;
+ }
+ else
+ temp.width = temp.length = 0;
+
+ if (pwg_by_name)
+ {
+ temp_by_name.width = pwg_by_name->width;
+ temp_by_name.length = pwg_by_name->length;
+ }
+ else
+ temp_by_name.width = temp_by_name.length = 0;
+
+ if ((margin = ippFindAttribute(media_col, "media-bottom-margin",
+ IPP_TAG_INTEGER)) != NULL)
+ temp.bottom = ippGetInteger(margin, 0);
+ else
+ temp.bottom = *custom_bottom;
+
+ if ((margin = ippFindAttribute(media_col, "media-left-margin",
+ IPP_TAG_INTEGER)) != NULL)
+ temp.left = ippGetInteger(margin, 0);
+ else
+ temp.left = *custom_left;
+
+ if ((margin = ippFindAttribute(media_col, "media-right-margin",
+ IPP_TAG_INTEGER)) != NULL)
+ temp.right = ippGetInteger(margin, 0);
+ else
+ temp.right = *custom_right;
+
+ if ((margin = ippFindAttribute(media_col, "media-top-margin",
+ IPP_TAG_INTEGER)) != NULL)
+ temp.top = ippGetInteger(margin, 0);
+ else
+ temp.top = *custom_top;
+
+ psname = (pwg_by_name ?
+ (pwg_by_name->ppd != NULL ?
+ pwg_by_name->ppd : pwg_by_name->pwg) :
+ (pwg->ppd != NULL ? pwg->ppd : pwg->pwg));
+ if (temp.bottom == 0 && temp.left == 0 && temp.right == 0 &&
+ temp.top == 0)
+ {
+ snprintf(temp.media, sizeof(temp.media), "%s.Borderless", psname);
+ borderless = 1;
+ }
+ else
+ {
+ strlcpy(temp.media, psname, sizeof(temp.media));
+ borderless = 0;
+ }
+
+ /* Check whether this size matches our search criteria */
+ if (mode != CF_GEN_SIZES_DEFAULT &&
+ min_border_mismatch > 0 &&
+ search_width > 0 && search_length > 0 &&
+ ((abs(search_width - temp_by_name.width) < 70 /* 2pt */ &&
+ abs(search_length - temp_by_name.length) < 70) /* 2pt */ ||
+ (abs(search_width - temp.width) < 70 /* 2pt */ &&
+ abs(search_length - temp.length) < 70) /* 2pt */))
+ {
+ /* Found size with the correct dimensions */
+ int match = 0;
+ if (mode == CF_GEN_SIZES_SEARCH_BORDERLESS_ONLY &&
+ borderless == 1)
+ {
+ /* We search only for borderless sizes and have found a match */
+ border_mismatch = 0;
+ min_border_mismatch = 0;
+ if (media_col_entry)
+ *media_col_entry = media_col;
+ match = 1;
+ }
+ else if (mode == CF_GEN_SIZES_SEARCH)
+ {
+ /* We search a size in general, borders are accepted. find the
+ best match in terms of border size */
+ border_mismatch =
+ (long long)(search_left < 0 ? 1 :
+ (abs(search_left - temp.left) + 1)) *
+ (long long)(search_bottom < 0 ? 1 :
+ (abs(search_bottom - temp.bottom) + 1)) *
+ (long long)(search_right < 0 ? 1 :
+ (abs(search_right - temp.right) + 1)) *
+ (long long)(search_top < 0 ? 1 :
+ (abs(search_top - temp.top) + 1));
+ if (border_mismatch < min_border_mismatch)
+ {
+ min_border_mismatch = border_mismatch;
+ if (media_col_entry)
+ *media_col_entry = media_col;
+ match = 1;
+ }
+ }
+ if (match)
+ {
+ if (width)
+ *width = temp.width;
+ if (length)
+ *length = temp.length;
+ if (left)
+ *left = temp.left;
+ if (bottom)
+ *bottom = temp.bottom;
+ if (right)
+ *right = temp.right;
+ if (top)
+ *top = temp.top;
+ strlcpy(size_name, temp.media, IPP_MAX_NAME);
+ }
+ }
+
+ /* Add size to list */
+ if (sizes && !cupsArrayFind(*sizes, &temp))
+ cupsArrayAdd(*sizes, &temp);
+
+ } else if (ippGetValueTag(x_dim) == IPP_TAG_RANGE ||
+ ippGetValueTag(y_dim) == IPP_TAG_RANGE) {
+ /*
+ * Custom size - record the min/max values...
+ */
+
+ int lower, upper; /* Range values */
+
+ if (ippGetValueTag(x_dim) == IPP_TAG_RANGE)
+ lower = ippGetRange(x_dim, 0, &upper);
+ else
+ lower = upper = ippGetInteger(x_dim, 0);
+
+ if (min_width && lower < *min_width)
+ *min_width = lower;
+ if (max_width && upper > *max_width)
+ *max_width = upper;
+
+ if (ippGetValueTag(y_dim) == IPP_TAG_RANGE)
+ lower = ippGetRange(y_dim, 0, &upper);
+ else
+ lower = upper = ippGetInteger(y_dim, 0);
+
+ if (min_length && lower < *min_length)
+ *min_length = lower;
+ if (max_length && upper > *max_length)
+ *max_length = upper;
+ }
+ }
+ if (min_border_mismatch < LLONG_MAX)
+ {
+ /* If we have found a matching page size in the media-col-database
+ we stop searching */
+ min_border_mismatch = 0;
+ }
+ }
+ if ((attr = ippFindAttribute(response, "media-size-supported",
+ IPP_TAG_BEGIN_COLLECTION)) != NULL) {
+ for (i = 0, count = ippGetCount(attr); i < count; i ++) {
+ cups_size_t temp; /* Current size */
+
+ media_size = ippGetCollection(attr, i);
+ x_dim = ippFindAttribute(media_size, "x-dimension", IPP_TAG_ZERO);
+ y_dim = ippFindAttribute(media_size, "y-dimension", IPP_TAG_ZERO);
+ pwg = pwgMediaForSize(ippGetInteger(x_dim, 0),
+ ippGetInteger(y_dim, 0));
+
+ if (pwg) {
+ if (!sizes && mode == CF_GEN_SIZES_DEFAULT)
+ continue;
+
+ temp.width = pwg->width;
+ temp.length = pwg->length;
+ temp.left = *custom_left;
+ temp.bottom = *custom_bottom;
+ temp.right = *custom_right;
+ temp.top = *custom_top;
+
+ psname = (pwg->ppd != NULL ? pwg->ppd : pwg->pwg);
+ if (temp.bottom == 0 && temp.left == 0 && temp.right == 0 &&
+ temp.top == 0)
+ {
+ snprintf(temp.media, sizeof(temp.media), "%s.Borderless", psname);
+ borderless = 1;
+ }
+ else
+ {
+ strlcpy(temp.media, psname, sizeof(temp.media));
+ borderless = 0;
+ }
+
+ /* Check whether this size matches our search criteria */
+ if (mode != CF_GEN_SIZES_DEFAULT &&
+ min_border_mismatch > 0 &&
+ search_width > 0 && search_length > 0 &&
+ abs(search_width - temp.width) < 70 /* 2pt */ &&
+ abs(search_length - temp.length) < 70 /* 2pt */)
+ {
+ /* Found size with the correct dimensions */
+ if (mode != CF_GEN_SIZES_SEARCH_BORDERLESS_ONLY ||
+ borderless == 1)
+ {
+ /* We accept the entry just by the size dimensions as
+ "media-size-supported" has no per-size margin info */
+ if (width)
+ *width = temp.width;
+ if (length)
+ *length = temp.length;
+ if (left)
+ *left = temp.left;
+ if (bottom)
+ *bottom = temp.bottom;
+ if (right)
+ *right = temp.right;
+ if (top)
+ *top = temp.top;
+ strlcpy(size_name, temp.media, IPP_MAX_NAME);
+ /* Found it, stop searching */
+ min_border_mismatch = 0;
+ }
+ }
+
+ if (sizes && !cupsArrayFind(*sizes, &temp))
+ cupsArrayAdd(*sizes, &temp);
+ } else if (ippGetValueTag(x_dim) == IPP_TAG_RANGE ||
+ ippGetValueTag(y_dim) == IPP_TAG_RANGE) {
+ /*
+ * Custom size - record the min/max values...
+ */
+
+ int lower, upper; /* Range values */
+
+ if (ippGetValueTag(x_dim) == IPP_TAG_RANGE)
+ lower = ippGetRange(x_dim, 0, &upper);
+ else
+ lower = upper = ippGetInteger(x_dim, 0);
+
+ if (min_width && lower < *min_width)
+ *min_width = lower;
+ if (max_width && upper > *max_width)
+ *max_width = upper;
+
+ if (ippGetValueTag(y_dim) == IPP_TAG_RANGE)
+ lower = ippGetRange(y_dim, 0, &upper);
+ else
+ lower = upper = ippGetInteger(y_dim, 0);
+
+ if (min_length && lower < *min_length)
+ *min_length = lower;
+ if (max_length && upper > *max_length)
+ *max_length = upper;
+ }
+ }
+ }
+ if ((attr = ippFindAttribute(response, "media-supported", IPP_TAG_ZERO))
+ != NULL) {
+ for (i = 0, count = ippGetCount(attr); i < count; i ++) {
+ const char *pwg_size = ippGetString(attr, i, NULL);
+ /* PWG size name */
+ cups_size_t temp, *temp2; /* Current size, found size */
+
+ if ((pwg = pwgMediaForPWG(pwg_size)) != NULL) {
+ if (strstr(pwg_size, "_max_") || strstr(pwg_size, "_max.")) {
+ if (max_width && pwg->width > *max_width)
+ *max_width = pwg->width;
+ if (max_length && pwg->length > *max_length)
+ *max_length = pwg->length;
+ } else if (strstr(pwg_size, "_min_") || strstr(pwg_size, "_min.")) {
+ if (min_width && pwg->width < *min_width)
+ *min_width = pwg->width;
+ if (min_length && pwg->length < *min_length)
+ *min_length = pwg->length;
+ } else {
+ if (!sizes && mode == CF_GEN_SIZES_DEFAULT)
+ continue;
+
+ temp.width = pwg->width;
+ temp.length = pwg->length;
+ temp.left = *custom_left;
+ temp.bottom = *custom_bottom;
+ temp.right = *custom_right;
+ temp.top = *custom_top;
+
+ psname = (pwg->ppd != NULL ? pwg->ppd : pwg->pwg);
+ if (temp.bottom == 0 && temp.left == 0 && temp.right == 0 &&
+ temp.top == 0)
+ snprintf(temp.media, sizeof(temp.media), "%s.Borderless", psname);
+ else
+ strlcpy(temp.media, psname, sizeof(temp.media));
+
+ /* Add the printer's original IPP name to an already found size */
+ if (sizes)
+ {
+ if ((temp2 = cupsArrayFind(*sizes, &temp)) != NULL) {
+ snprintf(temp2->media + strlen(temp2->media),
+ sizeof(temp2->media) - strlen(temp2->media),
+ " %s", pwg_size);
+ /* Check if we have also a borderless version of the size and add
+ the original IPP name also there */
+ snprintf(temp.media, sizeof(temp.media), "%s.Borderless", psname);
+ if ((temp2 = cupsArrayFind(*sizes, &temp)) != NULL)
+ snprintf(temp2->media + strlen(temp2->media),
+ sizeof(temp2->media) - strlen(temp2->media),
+ " %s", pwg_size);
+ } else
+ cupsArrayAdd(*sizes, &temp);
+ }
+ }
+ }
+ }
+ }
+ if (mode != CF_GEN_SIZES_DEFAULT && min_border_mismatch > 0 &&
+ search_width > 0 && search_length > 0 &&
+ *min_width >= 0 && *min_length >= 0 &&
+ *max_width >= *min_width && *max_length >= *min_length &&
+ *custom_left >= 0 && *custom_bottom >= 0 &&
+ *custom_right >= 0 && *custom_top >= 0)
+ {
+ /* Do we have support for a custom page size and have valid size ranges for
+ it? Check whether the size we are searching for can go as custom size */
+ if (search_width >= *min_width - 70 /* 2pt */ &&
+ search_width <= *max_width + 70 /* 2pt */ &&
+ search_length >= *min_length - 70 /* 2pt */ &&
+ search_length <= *max_length + 70 /* 2pt */)
+ {
+ if (width)
+ *width = (search_width < *min_width ? *min_width :
+ (search_width > *max_width ? *max_width : search_width));
+ if (length)
+ *length = (search_length < *min_length ? *min_length :
+ (search_length > *max_length ? *max_length : search_length));
+ if (left) *left = *custom_left;
+ if (bottom) *bottom = *custom_bottom;
+ if (right) *right = *custom_right;
+ if (top) *top = *custom_top;
+ min_border_mismatch = 0;
+ }
+ }
+ if (mode != CF_GEN_SIZES_DEFAULT && min_border_mismatch > 0)
+ {
+ /* Size not found */
+ if (width) *width = 0;
+ if (length) *length = 0;
+ if (left) *left = -1;
+ if (bottom) *bottom = -1;
+ if (right) *right = -1;
+ if (top) *top = -1;
+ }
+}
extern "C" {
# endif /* __cplusplus */
-#ifdef HAVE_CONFIG_H
+/*
+ * Include necessary headers...
+ */
+
#include <config.h>
-#endif
#include <ctype.h>
+#include <stdio.h>
#include <stdlib.h>
+#include <time.h>
+#include <math.h>
+
+#if defined(WIN32) || defined(__EMX__)
+# include <io.h>
+#else
+# include <unistd.h>
+# include <fcntl.h>
+#endif /* WIN32 || __EMX__ */
+
#include <cups/cups.h>
#include <cups/backend.h>
+#include <cups/raster.h>
#define CF_GET_PRINTER_ATTRIBUTES_LOGSIZE 4 * 65536
#define CF_GET_PRINTER_ATTRIBUTES_MAX_OUTPUT_LEN 8192
extern char cf_get_printer_attributes_log[CF_GET_PRINTER_ATTRIBUTES_LOGSIZE];
+
+/*
+ * Types...
+ */
+
/* Enum of possible driverless options */
enum cf_driverless_support_modes_e {
CF_DRVLESS_CHECKERR, /* Unable to get get-printer-attributes response*/
attribute */
};
+/* Data structure for resolution (X x Y dpi) */
+typedef struct cf_res_s {
+ int x, y;
+} cf_res_t;
+
+typedef enum cf_gen_sizes_mode_e {
+ CF_GEN_SIZES_DEFAULT = 0,
+ CF_GEN_SIZES_SEARCH,
+ CF_GEN_SIZES_SEARCH_BORDERLESS_ONLY
+} cf_gen_sizes_mode_t;
+
+
+/*
+ * Prototypes...
+ */
+
char *cfResolveURI(const char *raw_uri);
char *cfippfindBasedURIConverter(const char *uri ,int is_fax);
int cfCheckDriverlessSupport(const char* uri);
ipp_t *job_attrs,
const char *attr_name,
int *value);
+int cfIPPAttrResolutionForPrinter(ipp_t *printer_attrs, ipp_t *job_attrs,
+ const char *attr_name, int *xres, int *yres);
+int cfIPPReverseOutput(ipp_t *printer_attrs, ipp_t *job_attrs);
+
+char *cfStrFormatd(char *buf, char *bufend, double number,
+ struct lconv *loc);
+int cfCompareResolutions(void *resolution_a, void *resolution_b,
+ void *user_data);
+void *cfCopyResolution(void *resolution, void *user_data);
+void cfFreeResolution(void *resolution, void *user_data);
+cf_res_t *cfNewResolution(int x, int y);
+cups_array_t *cfNewResolutionArray();
+cf_res_t *cfIPPResToResolution(ipp_attribute_t *attr, int index);
+cups_array_t *cfIPPAttrToResolutionArray(ipp_attribute_t *attr);
+int cfJoinResolutionArrays(cups_array_t **current,
+ cups_array_t **new_arr,
+ cf_res_t **current_default,
+ cf_res_t **new_default);
+int cfGetPageDimensions(ipp_t *printer_attrs,
+ ipp_t *job_attrs,
+ int num_options,
+ cups_option_t *options,
+ cups_page_header2_t *header,
+ int transverse_fit,
+ float *width,
+ float *height,
+ float *left,
+ float *bottom,
+ float *right,
+ float *top,
+ char *name,
+ ipp_t **media_col_entry);
+void cfGenerateSizes(ipp_t *response,
+ cf_gen_sizes_mode_t mode,
+ cups_array_t **sizes,
+ ipp_attribute_t **defattr,
+ int *width,
+ int *length,
+ int *left,
+ int *bottom,
+ int *right,
+ int *top,
+ int *min_width,
+ int *min_length,
+ int *max_width,
+ int *max_length,
+ int *custom_left,
+ int *custom_bottom,
+ int *custom_right,
+ int *custom_top,
+ char *size_name,
+ ipp_t **media_col_entry);
+
# ifdef __cplusplus
}
* Contents:
*
* cfLutDelete() - Free the memory used by a lookup table.
- * cfLutLoad() - Load a LUT from a PPD file.
* cfLutNew() - Make a lookup table from a list of pixel values.
*/
}
-/*
- * 'cfLutLoad()' - Load a LUT from a PPD file.
- */
-
-cf_lut_t * /* O - New lookup table */
-cfLutLoad(ppd_file_t *ppd, /* I - PPD file */
- const char *colormodel, /* I - Color model */
- const char *media, /* I - Media type */
- const char *resolution, /* I - Resolution */
- const char *ink, /* I - Ink name */
- cf_logfunc_t log, /* I - Log function */
- void *ld) /* I - Log function data */
-{
- char name[PPD_MAX_NAME], /* Attribute name */
- spec[PPD_MAX_NAME]; /* Attribute spec */
- ppd_attr_t *attr; /* Attribute */
- int nvals; /* Number of values */
- float vals[4]; /* Values */
-
-
- /*
- * Range check input...
- */
-
- if (!ppd || !colormodel || !media || !resolution || !ink)
- return (NULL);
-
- /*
- * Try to find the LUT values...
- */
-
- snprintf(name, sizeof(name), "cups%sDither", ink);
-
- if ((attr = cfFindAttr(ppd, name, colormodel, media, resolution, spec,
- sizeof(spec), log, ld)) == NULL)
- attr = cfFindAttr(ppd, "cupsAllDither", colormodel, media,
- resolution, spec, sizeof(spec), log, ld);
-
- if (!attr)
- return (NULL);
-
- vals[0] = 0.0;
- vals[1] = 0.0;
- vals[2] = 0.0;
- vals[3] = 0.0;
- nvals = sscanf(attr->value, "%f%f%f", vals + 1, vals + 2, vals + 3) + 1;
-
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "Loaded LUT %s from PPD with values [%.3f %.3f %.3f %.3f]",
- name, vals[0], vals[1], vals[2], vals[3]);
-
- return (cfLutNew(nvals, vals, log, ld));
-}
-
-
/*
* 'cfLutNew()' - Make a lookup table from a list of pixel values.
*
#include <config.h>
#include <cups/cups.h>
-#if (CUPS_VERSION_MAJOR > 1) || (CUPS_VERSION_MINOR > 6)
-#define HAVE_CUPS_1_7 1
-#endif
#include <stdio.h>
#include <stdlib.h>
}
static void
-add_pdf_header_options(mupdf_page_header *h,
- cf_filter_out_format_t outformat,
- cups_array_t *mupdf_args)
+header_to_gs_args(mupdf_page_header *h,
+ cf_filter_out_format_t outformat,
+ cups_array_t *mupdf_args)
{
char tmpstr[1024];
cfFilterMuPDFToPWG(int inputfd, /* I - File descriptor input stream */
int outputfd, /* I - File descriptor output stream */
int inputseekable, /* I - Is input stream seekable?
- (unused)*/
+ (unused) */
cf_filter_data_t *data, /* I - Job and printer data */
- void *parameters) /* I - Filter-specific parameters */
+ void *parameters) /* I - Filter-specific parameters
+ (unused) */
{
cf_filter_out_format_t outformat;
+ char *val;
char buf[BUFSIZ];
char *icc_profile = NULL;
char tmpstr[1024];
cups_array_t *mupdf_args = NULL;
- cups_option_t *options = NULL;
FILE *fp = NULL;
char infilename[1024];
mupdf_page_header h;
int fd = -1;
- int cm_disabled;
+ int cm_disabled = 0;
int n;
- int num_options;
int empty = 0;
int status = 1;
- ppd_file_t *ppd = NULL;
struct sigaction sa;
cf_cm_calibration_t cm_calibrate;
cf_logfunc_t log = data->logfunc;
void *icd = data->iscanceleddata;
cups_cspace_t cspace = -1;
-#ifdef HAVE_CUPS_1_7
- ppd_attr_t *attr;
-#endif /* HAVE_CUPS_1_7 */
-
(void)inputseekable;
+ (void)parameters;
- if (parameters) {
- outformat = *(cf_filter_out_format_t *)parameters;
- if (outformat != CF_FILTER_OUT_FORMAT_CUPS_RASTER &&
- outformat != CF_FILTER_OUT_FORMAT_PWG_RASTER &&
- outformat != CF_FILTER_OUT_FORMAT_APPLE_RASTER &&
- outformat != CF_FILTER_OUT_FORMAT_PCLM)
+ val = data->final_content_type;
+ if (val)
+ {
+ if (strcasestr(val, "pwg"))
+ outformat = CF_FILTER_OUT_FORMAT_PWG_RASTER;
+ else if (strcasestr(val, "urf"))
+ outformat = CF_FILTER_OUT_FORMAT_APPLE_RASTER;
+ else if (strcasestr(val, "pclm"))
+ outformat = CF_FILTER_OUT_FORMAT_PCLM;
+ else if (strcasestr(val, "cups"))
+ outformat = CF_FILTER_OUT_FORMAT_CUPS_RASTER;
+ else
outformat = CF_FILTER_OUT_FORMAT_PWG_RASTER;
- } else
+ }
+ else
outformat = CF_FILTER_OUT_FORMAT_PWG_RASTER;
if (log) log(ld, CF_LOGLEVEL_DEBUG,
sa.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &sa, NULL);
- num_options = data->num_options;
-
- ppd = data->ppd;
- if (ppd) {
- ppdMarkOptions (ppd, num_options, options);
- }
-
fd = cupsTempFd(infilename, 1024);
if (fd < 0) {
if(log) log(ld, CF_LOGLEVEL_ERROR, "cfFilterMuPDFToPWG: Can't create temporary file");
if (empty == -1)
goto out;
- /* Check status of color management in CUPS */
- cm_calibrate = cfCmGetCupsColorCalibrateMode(data, options, num_options);
-
- if (cm_calibrate == CF_CM_CALIBRATION_ENABLED)
- cm_disabled = 1;
- else
- cm_disabled = cfCmIsPrinterCmDisabled(data);
-
- if (!cm_disabled)
- cfCmGetPrinterIccProfile(data, &icc_profile, ppd);
-
-/* Find print-rendering-intent */
-
- cfGetPrintRenderIntent(data, &h);
- if(log) log(ld, CF_LOGLEVEL_DEBUG,
- "Print rendering intent = %s", h.cupsRenderingIntent);
-
-
/* mutool parameters */
mupdf_args = cupsArrayNew(NULL, NULL);
if (!mupdf_args) {
/* mutool output parameters */
cupsArrayAdd(mupdf_args, strdup("-Fpwg"));
- /* Note that MuPDF only creates PWG Raster and never CUPS Raster,
- so we set the PWG Raster flag in the cfRasterPrepareHeader() call.
- This function takes care of generating a completely consistent PWG
- Raster header then, no extra manipulation needed.
+ /* Note that MuPDF only creates PWG Raster so we select this as header format,
+ We also supply the final output format (to which will be converted with
+ further filters) to determine the correct color space and depth.
From the header h only cupsWidth/cupsHeight (dimensions in pixels),
resolution, and color space are used here. */
cfRasterPrepareHeader(&h, data, outformat,
- CF_FILTER_OUT_FORMAT_PWG_RASTER, 1, &cspace);
-
- if ((h.HWResolution[0] == 100) && (h.HWResolution[1] == 100)) {
- /* No "Resolution" option */
- if (ppd && (attr = ppdFindAttr(ppd, "DefaultResolution", 0)) != NULL) {
- /* "*DefaultResolution" keyword in the PPD */
- const char *p = attr->value;
- h.HWResolution[0] = atoi(p);
- if ((p = strchr(p, 'x')) != NULL)
- h.HWResolution[1] = atoi(p);
- else
- h.HWResolution[1] = h.HWResolution[0];
- if (h.HWResolution[0] <= 0)
- h.HWResolution[0] = 300;
- if (h.HWResolution[1] <= 0)
- h.HWResolution[1] = h.HWResolution[0];
- } else {
- h.HWResolution[0] = 300;
- h.HWResolution[1] = 300;
- }
- h.cupsWidth = h.HWResolution[0] * h.PageSize[0] / 72;
- h.cupsHeight = h.HWResolution[1] * h.PageSize[1] / 72;
- }
+ CF_FILTER_OUT_FORMAT_PWG_RASTER, 1, &cspace);
/* set PDF-specific options */
parse_pdf_header_options(fp, &h);
h.MirrorPrint = CUPS_FALSE;
h.Orientation = CUPS_ORIENT_0;
+ /* Check status of color management in CUPS */
+ cm_calibrate = cfCmGetCupsColorCalibrateMode(data);
+
+ if (cm_calibrate == CF_CM_CALIBRATION_ENABLED)
+ cm_disabled = 1;
+ else
+ cm_disabled = cfCmIsPrinterCmDisabled(data);
+
+ if (!cm_disabled)
+ cfCmGetPrinterIccProfile(data, cfRasterColorSpaceString(h.cupsColorSpace),
+ h.MediaType, h.HWResolution[0], h.HWResolution[1],
+ &icc_profile);
+
+ /* Note: No ICC profile support in mutool! */
+
+ /* Find print-rendering-intent */
+ h.cupsRenderingIntent[0] = '\0';
+ cfGetPrintRenderIntent(data, h.cupsRenderingIntent,
+ sizeof(h.cupsRenderingIntent));
+ if(log) log(ld, CF_LOGLEVEL_DEBUG,
+ "Print rendering intent = %s", h.cupsRenderingIntent);
+
/* get all the data from the header and pass it to mutool */
- add_pdf_header_options (&h, outformat, mupdf_args);
+ header_to_gs_args(&h, outformat, mupdf_args);
snprintf(tmpstr, sizeof(tmpstr), "%s", infilename);
cupsArrayAdd(mupdf_args, strdup(tmpstr));
#include "filter.h"
#include <cups/raster.h>
#include <cups/cups.h>
-#include <ppd/ppd.h>
#include <errno.h>
#include <qpdf/QPDF.hh>
#include <qpdf/QPDFObjectHandle.hh>
#include "image.h"
#include "bitmap.h"
#include "raster.h"
-#include <cupsfilters/filter.h>
+#include "filter.h"
+#include "ipp.h"
+
#if (CUPS_VERSION_MAJOR > 1) || (CUPS_VERSION_MINOR > 6)
int numcolors = 0;
int rowsize = 0;
cups_page_header2_t header;
- ppd_file_t *ppd = 0;
char pageSizeRequested[64];
int bi_level = 0;
/* image swapping */
int num_options = 0;
cups_option_t* options = NULL;
const char* t = NULL;
- ppd_attr_t* attr;
const char *val;
cf_logfunc_t log = data->logfunc;
void *ld = data->logdata;
- ppd_file_t *ppd = pclmtoraster_data->ppd;
cups_page_header2_t *header = &(pclmtoraster_data->header);
- ipp_t *printer_attrs = data->printer_attrs;
cups_cspace_t cspace = (cups_cspace_t)(-1);
num_options = cfJoinJobOptionsAndAttrs(data, num_options, &options);
- if (ppd)
+ t = cupsGetOption("media-class", num_options, options);
+ if (t == NULL)
+ t = cupsGetOption("MediaClass", num_options, options);
+ if (t != NULL)
{
- if ((attr = ppdFindAttr(ppd,"PWGRaster",0)) != 0 &&
- (!strcasecmp(attr->value, "true")
- || !strcasecmp(attr->value, "on") ||
- !strcasecmp(attr->value, "yes")))
+ if (strcasestr(t, "pwg"))
pclmtoraster_data->outformat = CF_FILTER_OUT_FORMAT_PWG_RASTER;
}
- else
- {
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPCLmToRaster: PPD file is not specified.");
-
- t = cupsGetOption("media-class", num_options, options);
- if (t == NULL)
- t = cupsGetOption("MediaClass", num_options, options);
- if (t != NULL)
- {
- if (strcasestr(t, "pwg"))
- pclmtoraster_data->outformat = CF_FILTER_OUT_FORMAT_PWG_RASTER;
- }
- }
cfRasterPrepareHeader(header, data, outformat, outformat, 0, &cspace);
- if (ppd)
+ if (header->Duplex)
{
- if (header->Duplex)
+ int backside;
+ /* analyze options relevant to Duplex */
+ /* APDuplexRequiresFlippedMargin */
+ enum {
+ FM_NO,
+ FM_FALSE,
+ FM_TRUE
+ } flippedMargin = FM_NO;
+
+ backside = cfGetBackSideOrientation(data);
+
+ if (backside >= 0)
{
- /* analyze options relevant to Duplex */
- const char *backside = "";
- /* APDuplexRequiresFlippedMargin */
- enum {
- FM_NO, FM_FALSE, FM_TRUE
- } flippedMargin = FM_NO;
-
- attr = ppdFindAttr(ppd,"cupsBackSide",NULL);
- if (attr != NULL && attr->value != NULL)
- {
- ppd->flip_duplex = 0;
- backside = attr->value;
- }
- else if (ppd->flip_duplex)
- {
- backside = "Rotated"; /* compatible with Max OS and GS 8.71 */
- }
-
- attr = ppdFindAttr(ppd,"APDuplexRequiresFlippedMargin",NULL);
- if (attr != NULL && attr->value != NULL)
- {
- if (strcasecmp(attr->value,"true") == 0)
- {
- flippedMargin = FM_TRUE;
- }
- else
- {
- flippedMargin = FM_FALSE;
- }
- }
- if (strcasecmp(backside,"ManualTumble") == 0 && header->Tumble)
- {
- pclmtoraster_data->swap_image_x = pclmtoraster_data->swap_image_y =
- true;
- pclmtoraster_data->swap_margin_x = pclmtoraster_data->swap_margin_y =
- true;
- if (flippedMargin == FM_TRUE)
- {
- pclmtoraster_data->swap_margin_y = false;
- }
- }
- else if (strcasecmp(backside,"Rotated") == 0 && !header->Tumble)
- {
- pclmtoraster_data->swap_image_x = pclmtoraster_data->swap_image_y =
- true;
- pclmtoraster_data->swap_margin_x = pclmtoraster_data->swap_margin_y =
- true;
- if (flippedMargin == FM_TRUE)
- {
- pclmtoraster_data->swap_margin_y = false;
- }
- }
- else if (strcasecmp(backside,"Flipped") == 0)
- {
- if (header->Tumble)
- {
- pclmtoraster_data->swap_image_x = true;
- pclmtoraster_data->swap_margin_x = pclmtoraster_data->swap_margin_y =
- true;
- }
- else
- {
- pclmtoraster_data->swap_image_y = true;
- }
- if (flippedMargin == FM_FALSE)
- {
- pclmtoraster_data->swap_margin_y =
- !(pclmtoraster_data->swap_margin_y);
- }
- }
- }
- } else {
- int backside = cfGetBackSideAndHeaderDuplex(printer_attrs, header);
- if(header->Duplex){
- /* analyze options relevant to Duplex */
- /* APDuplexRequiresFlippedMargin */
- enum {
- FM_NO, FM_FALSE, FM_TRUE
- } flippedMargin = FM_NO;
+ flippedMargin = (backside & 16 ? FM_TRUE :
+ (backside & 8 ? FM_FALSE :
+ FM_NO));
+ backside &= 7;
if (backside==CF_BACKSIDE_MANUAL_TUMBLE && header->Tumble)
{
- pclmtoraster_data->swap_image_x = pclmtoraster_data->swap_image_y =
+ pclmtoraster_data->swap_image_x = pclmtoraster_data->swap_image_y =
true;
- pclmtoraster_data->swap_margin_x = pclmtoraster_data->swap_margin_y =
+ pclmtoraster_data->swap_margin_x = pclmtoraster_data->swap_margin_y =
true;
- if (flippedMargin == FM_TRUE)
- {
- pclmtoraster_data->swap_margin_y = false;
- }
+ if (flippedMargin == FM_TRUE)
+ pclmtoraster_data->swap_margin_y = false;
}
else if (backside==CF_BACKSIDE_ROTATED && !header->Tumble)
{
- pclmtoraster_data->swap_image_x = pclmtoraster_data->swap_image_y =
+ pclmtoraster_data->swap_image_x = pclmtoraster_data->swap_image_y =
true;
- pclmtoraster_data->swap_margin_x = pclmtoraster_data->swap_margin_y =
+ pclmtoraster_data->swap_margin_x = pclmtoraster_data->swap_margin_y =
true;
- if (flippedMargin == FM_TRUE)
- {
- pclmtoraster_data->swap_margin_y = false;
- }
+ if (flippedMargin == FM_TRUE)
+ pclmtoraster_data->swap_margin_y = false;
}
else if (backside==CF_BACKSIDE_FLIPPED)
{
- if (header->Tumble)
+ if (header->Tumble)
{
- pclmtoraster_data->swap_image_x = true;
- pclmtoraster_data->swap_margin_x = pclmtoraster_data->swap_margin_y =
- true;
- }
+ pclmtoraster_data->swap_image_x = true;
+ pclmtoraster_data->swap_margin_x =
+ pclmtoraster_data->swap_margin_y = true;
+ }
else
- {
- pclmtoraster_data->swap_image_y = true;
- }
- if (flippedMargin == FM_FALSE)
- {
- pclmtoraster_data->swap_margin_y =
+ pclmtoraster_data->swap_image_y = true;
+ if (flippedMargin == FM_FALSE)
+ pclmtoraster_data->swap_margin_y =
!(pclmtoraster_data->swap_margin_y);
- }
}
}
}
+
if ((val = cupsGetOption("print-color-mode", num_options, options)) != NULL
&& !strncasecmp(val, "bi-level", 8))
pclmtoraster_data->bi_level = 1;
long long rotate = 0,
height,
width;
- double paperdimensions[2], margins[4], l, swap;
+ float paperdimensions[2], margins[4], l, swap;
int bufsize = 0, pixel_count = 0,
temp = 0;
float mediaBox[4];
QPDFObjectHandle image;
QPDFObjectHandle imgdict;
QPDFObjectHandle colorspace_obj;
- ppd_file_t *ppd = data->ppd;
// Check if page is rotated.
if (page.getKey("/Rotate").isInteger())
data->header.PageSize[1] = (unsigned)l;
}
- // Adjust header page size and margins according to the ppd file.
- if (ppd)
- {
- ppdRasterMatchPPDSize(&(data->header), ppd, margins, paperdimensions, NULL,
- NULL);
- if (data->outformat != CF_FILTER_OUT_FORMAT_CUPS_RASTER)
- memset(margins, 0, sizeof(margins));
- }
- else if(filter_data!=NULL &&(filter_data->printer_attrs)!=NULL)
+ memset(paperdimensions, 0, sizeof(paperdimensions));
+ memset(margins, 0, sizeof(margins));
+ if (filter_data != NULL && (filter_data->printer_attrs) != NULL)
{
- cfRasterMatchIPPSize(&(data->header), filter_data, margins, paperdimensions, NULL, NULL);
- if (data->outformat != CF_FILTER_OUT_FORMAT_CUPS_RASTER)
+ cfGetPageDimensions(filter_data->printer_attrs, filter_data->job_attrs,
+ filter_data->num_options, filter_data->options,
+ &(data->header), 0,
+ &(paperdimensions[0]), &(paperdimensions[1]),
+ &(margins[0]), &(margins[1]),
+ &(margins[2]), &(margins[3]), NULL, NULL);
+ if (data->outformat == CF_FILTER_OUT_FORMAT_PWG_RASTER)
memset(margins, 0, sizeof(margins));
}
else
+++ /dev/null
-#ifndef _CUPS_FILTERS_PDFTOPDF_PDFTOPDF_JCL_H
-#define _CUPS_FILTERS_PDFTOPDF_PDFTOPDF_JCL_H
-
-struct _cfPDFToPDFProcessingParameters;
-class _cfPDFToPDFProcessor;
-
-void _cfPDFToPDFEmitPreamble(FILE *fp, ppd_file_t *ppd,
- const _cfPDFToPDFProcessingParameters ¶m);
-void _cfPDFToPDFEmitPostamble(FILE *fp, ppd_file_t *ppd,
- const _cfPDFToPDFProcessingParameters ¶m);
-
-void _cfPDFToPDFEmitComment(_cfPDFToPDFProcessor &proc,
- const _cfPDFToPDFProcessingParameters ¶m);
-
-#endif
+++ /dev/null
-#include <ctype.h>
-#include "pdftopdf-processor-private.h"
-#include <ppd/ppd.h>
-
-#include <string.h>
-
-// TODO: -currently changes ppd. (Copies)
-//
-static void emitJCLOptions(FILE *fp, ppd_file_t *ppd, int device_copies) // {{{
-{
- int section;
- ppd_choice_t **choices;
- int i;
- char buf[1024];
- ppd_attr_t *attr;
- bool withJCL=false,
- datawritten=false;
-
- if (!ppd) return;
-
- if ((attr = ppdFindAttr(ppd,"pdftopdfJCLBegin",NULL)) != NULL) {
- withJCL=true;
- const int n=strlen(attr->value);
- for (i = 0;i < n;i++) {
- if (attr->value[i] == '\r' || attr->value[i] == '\n') {
- // skip new line
- continue;
- }
- fputc(attr->value[i],fp);
- datawritten=true;
- }
- }
-
- snprintf(buf,sizeof(buf),"%d",device_copies);
- if (ppdFindOption(ppd,"Copies") != NULL) {
- ppdMarkOption(ppd,"Copies",buf);
- } else {
- if ((attr = ppdFindAttr(ppd,"pdftopdfJCLCopies",buf)) != NULL) {
- fputs(attr->value,fp);
- datawritten=true;
- } else if (withJCL) {
- fprintf(fp,"Copies=%d;",device_copies);
- datawritten=true;
- }
- }
- for (section = (int)PPD_ORDER_ANY;
- section <= (int)PPD_ORDER_PROLOG;section++) {
- int n = ppdCollect(ppd,(ppd_section_t)section,&choices);
- for (i = 0;i < n;i++) {
- snprintf(buf,sizeof(buf),"pdftopdfJCL%s",
- ((ppd_option_t *)(choices[i]->option))->keyword);
- if ((attr = ppdFindAttr(ppd,buf,choices[i]->choice)) != NULL) {
- fputs(attr->value,fp);
- datawritten=true;
- } else if (withJCL) {
- fprintf(fp,"%s=%s;",
- ((ppd_option_t *)(choices[i]->option))->keyword,
- choices[i]->choice);
- datawritten=true;
- }
- }
- }
- if (datawritten) {
- fputc('\n',fp);
- }
-}
-// }}}
-
-/* Copied ppd_decode() from CUPS which is not exported to the API; needed in _cfPDFToPDFEmitPreamble() */
-// {{{ static int ppd_decode(char *string)
-static int /* O - Length of decoded string */
-ppd_decode(char *string) /* I - String to decode */
-{
- char *inptr, /* Input pointer */
- *outptr; /* Output pointer */
-
- inptr = string;
- outptr = string;
-
- while (*inptr != '\0')
- if (*inptr == '<' && isxdigit(inptr[1] & 255)) {
- /*
- * Convert hex to 8-bit values...
- */
-
- inptr ++;
- while (isxdigit(*inptr & 255)) {
- if (isalpha(*inptr))
- *outptr = (tolower(*inptr) - 'a' + 10) << 4;
- else
- *outptr = (*inptr - '0') << 4;
-
- inptr ++;
-
- if (!isxdigit(*inptr & 255))
- break;
-
- if (isalpha(*inptr))
- *outptr |= tolower(*inptr) - 'a' + 10;
- else
- *outptr |= *inptr - '0';
-
- inptr ++;
- outptr ++;
- }
-
- while (*inptr != '>' && *inptr != '\0')
- inptr ++;
- while (*inptr == '>')
- inptr ++;
- } else
- *outptr++ = *inptr++;
-
- *outptr = '\0';
-
- return ((int)(outptr - string));
-}
-// }}}
-
-void _cfPDFToPDFEmitPreamble(FILE *fp, ppd_file_t *ppd,
- const _cfPDFToPDFProcessingParameters ¶m) // {{{
-{
- if (ppd == 0) return;
-
- ppdEmit(ppd, fp, PPD_ORDER_EXIT);
-
- if (param.emit_jcl) {
- /* pdftopdf only adds JCL to the job if the printer is a native PDF
- printer and the PPD is for this mode, having the "*JCLToPDFInterpreter:"
- keyword. We need to read this keyword manually from the PPD and replace
- the content of ppd->jcl_ps by the value of this keyword, so that
- ppdEmitJCL() actually adds JCL based on the presence on
- "*JCLToPDFInterpreter:". */
- ppd_attr_t *attr;
- char buf[1024];
- int devicecopies_done = 0;
- char *old_jcl_ps = ppd->jcl_ps;
- /* If there is a "Copies" option in the PPD file, assure that hardware
- copies are implemented as described by this option */
- if (ppdFindOption(ppd,"Copies") != NULL &&
- param.device_copies > 1) {
- snprintf(buf,sizeof(buf),"%d",param.device_copies);
- ppdMarkOption(ppd,"Copies",buf);
- devicecopies_done = 1;
- }
- if ((attr=ppdFindAttr(ppd,"JCLToPDFInterpreter",NULL)) != NULL) {
- if (param.device_copies > 1 && devicecopies_done == 0 && // HW copies
- strncmp(ppd->jcl_begin, "\033%-12345X@", 10) == 0) { // PJL
- /* Add a PJL command to implement the hardware copies */
- const size_t size=strlen(attr->value)+1+30;
- ppd->jcl_ps=(char *)malloc(size*sizeof(char));
- if (param.device_collate) {
- snprintf(ppd->jcl_ps, size, "@PJL SET QTY=%d\n%s",
- param.device_copies, attr->value);
- } else {
- snprintf(ppd->jcl_ps, size, "@PJL SET COPIES=%d\n%s",
- param.device_copies, attr->value);
- }
- } else
- ppd->jcl_ps=strdup(attr->value);
- ppd_decode(ppd->jcl_ps);
- } else {
- ppd->jcl_ps=NULL;
- }
- ppdEmitJCL(ppd, fp, param.job_id, param.user, param.title);
- emitJCLOptions(fp, ppd, param.device_copies);
- free(ppd->jcl_ps);
- ppd->jcl_ps = old_jcl_ps; // cups uses pool allocator, not free()
- }
-}
-// }}}
-
-void _cfPDFToPDFEmitPostamble(FILE *fp, ppd_file_t *ppd,
- const _cfPDFToPDFProcessingParameters ¶m) // {{{
-{
- if (param.emit_jcl) {
- ppdEmitJCLEnd(ppd, fp);
- }
-}
-// }}}
-
-// pass information to subsequent filters via PDF comments
-void _cfPDFToPDFEmitComment(_cfPDFToPDFProcessor &proc,const _cfPDFToPDFProcessingParameters ¶m) // {{{
-{
- std::vector<std::string> output;
-
- output.push_back("% This file was generated by pdftopdf");
-
- // This is not standard, but like PostScript.
- if (param.device_copies>0) {
- char buf[256];
- snprintf(buf,sizeof(buf),"%d",param.device_copies);
- output.push_back(std::string("%%PDFTOPDFNumCopies : ")+buf);
-
- if (param.device_collate) {
- output.push_back("%%PDFTOPDFCollate : true");
- } else {
- output.push_back("%%PDFTOPDFCollate : false");
- }
- }
-
- proc.set_comments(output);
-}
-// }}}
_cfPDFToPDFProcessingParameters()
: job_id(0),num_copies(1),
user(0),title(0),
+ pagesize_requested(false),
fitplot(false),
fillprint(false), //print-scaling = fill
cropfit(false),
auto_rotate(false),
- emit_jcl(true),device_copies(1),
- device_collate(false),set_duplex(false),
+ device_copies(1),
+ device_collate(false),
+ set_duplex(false),
page_logging(-1)
{
int job_id, num_copies;
const char *user, *title; // will stay around
+ bool pagesize_requested;
bool fitplot;
bool fillprint; //print-scaling = fill
bool cropfit; // -o crop-to-fit
bool auto_rotate;
- // ppd/jcl changes
- bool emit_jcl;
int device_copies;
bool device_collate;
bool set_duplex;
"cfFilterPDFToPDF: auto_rotate: %s",
(auto_rotate)?"true":"false");
- if (doc->logfunc) doc->logfunc(doc->logdata, CF_LOGLEVEL_DEBUG,
- "cfFilterPDFToPDF: emit_jcl: %s",
- (emit_jcl)?"true":"false");
if (doc->logfunc) doc->logfunc(doc->logdata, CF_LOGLEVEL_DEBUG,
"cfFilterPDFToPDF: device_copies: %d",
device_copies);
return false;
}
+ // Certain features require a given page size for the page to be
+ // printed or all pages of the document being the same size. Here we
+ // set param.pagesize_requested so that the default pag size is used
+ // when no size got specified by the user.
+ if (param.fitplot || param.fillprint || param.autoprint || param.autofit ||
+ param.booklet != CF_PDFTOPDF_BOOKLET_OFF ||
+ param.nup.nupX > 1 || param.nup.nupY > 1)
+ param.pagesize_requested = true;
+
const bool dst_lscape =
(param.paper_is_landscape ==
((param.orientation == ROT_0) || (param.orientation == ROT_180)));
if (param.booklet!=CF_PDFTOPDF_BOOKLET_OFF) {
shuffle=_cfPDFToPDFBookletShuffle(numOrigPages,param.book_signature);
if (param.booklet==CF_PDFTOPDF_BOOKLET_ON) { // override options
- // TODO? specifically "sides=two-sided-short-edge" / DuplexTumble
+ // We do not "sides=two-sided-short-edge" / DuplexTumble here.
+ // We assume it done by caller, for example ppdFilterLoadPPD() of libppd
// param.duplex=true;
- // param.set_duplex=true; ? currently done in setFinalPPD()
+ // param.set_duplex=true;
_cfPDFToPDFNupParameters::preset(2,param.nup); // TODO?! better
}
} else { // 0 1 2 3 ...
param.page.top = param.page.height;
}
- if (param.fillprint || param.cropfit)
+ if (param.pagesize_requested && (param.fillprint || param.cropfit))
{
for (int i = 0; i < (int)input_page_range_list.size(); i ++)
{
_cfPDFToPDFPageRect rect;
rect = page->get_rect();
//rect.dump(doc);
+ if (!param.pagesize_requested)
+ {
+ param.page.width = param.page.right = rect.width;
+ param.page.height = param.page.top = rect.height;
+ }
bool newPage = nupstate.mext_page(rect.width, rect.height, pgedit);
if (newPage)
#include <stdio.h>
#include <assert.h>
#include <cups/cups.h>
-#include <ppd/ppd.h>
#if (CUPS_VERSION_MAJOR > 1) || (CUPS_VERSION_MINOR > 6)
#define HAVE_CUPS_1_7 1
#endif
#include <sys/wait.h>
#include "pdftopdf-private.h"
#include "cupsfilters/raster.h"
-#include "cupsfilters/ppdgenerator.h"
+#include "cupsfilters/ipp.h"
+#include "cupsfilters/ipp.h"
#include "pdftopdf-processor-private.h"
-#include "pdftopdf-jcl-private.h"
#include <stdarg.h>
// namespace {}
-void setFinalPPD(ppd_file_t *ppd,const _cfPDFToPDFProcessingParameters ¶m)
-{
- if ((param.booklet==CF_PDFTOPDF_BOOKLET_ON)&&(ppdFindOption(ppd,"Duplex"))) {
- // TODO: elsewhere, better
- ppdMarkOption(ppd,"Duplex","DuplexTumble");
- // TODO? sides=two-sided-short-edge
- }
-
- // for compatibility
- if ((param.set_duplex)&&(ppdFindOption(ppd,"Duplex")!=NULL)) {
- ppdMarkOption(ppd,"Duplex","True");
- ppdMarkOption(ppd,"Duplex","On");
- }
-
- // we do it, printer should not
- ppd_choice_t *choice;
- if ((choice=ppdFindMarkedChoice(ppd,"MirrorPrint")) != NULL) {
- choice->marked=0;
- }
-}
-
-// for choice, only overwrites ret if found in ppd
-static bool ppdGetInt(ppd_file_t *ppd,const char *name,int *ret) // {{{
-{
- assert(ret);
- ppd_choice_t *choice=ppdFindMarkedChoice(ppd,name); // !ppd is ok.
- if (choice) {
- *ret=atoi(choice->choice);
- return true;
- }
- return false;
-}
-// }}}
-
static bool optGetInt(const char *name,int num_options,cups_option_t *options,int *ret) // {{{
{
assert(ret);
}
// }}}
-static bool ppdGetDuplex(ppd_file_t *ppd) // {{{
-{
- const char **option, **choice;
- const char *option_names[] = {
- "Duplex",
- "JCLDuplex",
- "EFDuplex",
- "KD03Duplex",
- NULL
- };
- const char *choice_names[] = {
- "DuplexNoTumble",
- "DuplexTumble",
- "LongEdge",
- "ShortEdge",
- "Top",
- "Bottom",
- NULL
- };
- for (option = option_names; *option; option ++)
- for (choice = choice_names; *choice; choice ++)
- if (ppdIsMarked(ppd, *option, *choice))
- return 1;
- return 0;
-}
-// }}}
-
-// TODO: enum
-static bool ppdDefaultOrder(ppd_file_t *ppd, pdftopdf_doc_t *doc) // {{{ -- is reverse?
-{
- ppd_choice_t *choice;
- ppd_attr_t *attr;
- const char *val=NULL;
-
- // Figure out the right default output order from the PPD file...
- if ((choice=ppdFindMarkedChoice(ppd,"OutputOrder")) != NULL) {
- val=choice->choice;
- } else if (((choice=ppdFindMarkedChoice(ppd,"OutputBin")) != NULL)&&
- ((attr=ppdFindAttr(ppd,"PageStackOrder",choice->choice)) != NULL)) {
- val=attr->value;
- } else if ((attr=ppdFindAttr(ppd,"DefaultOutputOrder",0)) != NULL) {
- val=attr->value;
- }
- if ((!val)||(strcasecmp(val,"Normal")==0)||(strcasecmp(val,"same-order")==0)) {
- return false;
- } else if (strcasecmp(val,"Reverse")==0||(strcasecmp(val,"reverse-order")==0)) {
- return true;
- }
-
- if (doc->logfunc) doc->logfunc(doc->logdata, CF_LOGLEVEL_ERROR,
- "cfFilterPDFToPDF: Unsupported output-order "
- "value %s, using 'normal'!",
- val);
- return false;
-}
-// }}}
-
-static bool optGetCollate(int num_options,cups_option_t *options) // {{{
-{
- if (is_true(cupsGetOption("Collate",num_options,options))) {
- return true;
- }
-
- const char *val=NULL;
- if ((val=cupsGetOption("multiple-document-handling",num_options,options)) != NULL) {
- /* This IPP attribute is unnecessarily complicated:
- * single-document, separate-documents-collated-copies, single-document-new-sheet:
- * -> collate (true)
- * separate-documents-uncollated-copies:
- * -> can be uncollated (false)
- */
- return (strcasecmp(val,"separate-documents-uncollated-copies")!=0);
- }
-
- if ((val=cupsGetOption("sheet-collate",num_options,options)) != NULL) {
- return (strcasecmp(val,"uncollated")!=0);
- }
-
- return false;
-}
-// }}}
static bool parsePosition(const char *value,pdftopdf_position_e &xpos,pdftopdf_position_e &ypos) // {{{
{
}
// }}}
-void getParameters(cf_filter_data_t *data,int num_options,cups_option_t *options,_cfPDFToPDFProcessingParameters ¶m,char *final_content_type,pdftopdf_doc_t *doc) // {{{
+void getParameters(cf_filter_data_t *data,int num_options,cups_option_t *options,_cfPDFToPDFProcessingParameters ¶m,pdftopdf_doc_t *doc) // {{{
{
-
- ppd_file_t *ppd = data->ppd;
+ char *final_content_type = data->final_content_type;
ipp_t *printer_attrs = data->printer_attrs;
- ipp_attribute_t *ipp;
+ ipp_t *job_attrs = data->job_attrs;
+ ipp_attribute_t *attr;
const char *val;
- if ((val = cupsGetOption("copies",num_options,options)) != NULL ||
- (val = cupsGetOption("Copies", num_options, options))!=NULL ||
- (val = cupsGetOption("num-copies", num_options, options))!=NULL ||
- (val = cupsGetOption("NumCopies", num_options, options))!=NULL) {
+ if ((val = cupsGetOption("copies",num_options, options)) != NULL ||
+ (val = cupsGetOption("Copies", num_options, options)) != NULL ||
+ (val = cupsGetOption("num-copies", num_options, options)) != NULL ||
+ (val = cupsGetOption("NumCopies", num_options, options)) != NULL)
+ {
int copies = atoi(val);
if (copies > 0)
param.num_copies = copies;
}
- // param.num_copies initially from commandline
- if (param.num_copies==1) {
- ppdGetInt(ppd,"Copies",¶m.num_copies);
- }
+
if (param.num_copies==0) {
param.num_copies=1;
}
param.autoprint = true;
}
- if (ppd && (ppd->landscape < 0)) { // direction the printer rotates landscape (90 or -90)
+ // direction the printer rotates landscape
+ // (landscape-orientation-requested-preferred: 4: 90 or 5: -90)
+ if (printer_attrs != NULL &&
+ (attr = ippFindAttribute(printer_attrs, "landscape-orientation-requested-preferred", IPP_TAG_ZERO)) != NULL &&
+ ippGetInteger(attr, 0) == 5)
param.normal_landscape=ROT_270;
- } else {
+ else
param.normal_landscape=ROT_90;
- }
int ipprot;
param.orientation=ROT_0;
param.no_orientation = true;
}
- ppd_size_t *pagesize;
- // param.page default is letter, border 36,18
- if ((pagesize=ppdPageSize(ppd,0)) != NULL) { // "already rotated"
- param.page.top=pagesize->top;
- param.page.left=pagesize->left;
- param.page.right=pagesize->right;
- param.page.bottom=pagesize->bottom;
- param.page.width=pagesize->width;
- param.page.height=pagesize->length;
+ if (printer_attrs != NULL)
+ param.pagesize_requested =
+ (cfGetPageDimensions(printer_attrs, job_attrs, num_options, options, NULL,
+ 0,
+ &(param.page.width), &(param.page.height),
+ &(param.page.left), &(param.page.bottom),
+ &(param.page.right), &(param.page.top),
+ NULL, NULL) == 1);
+
+ if (param.page.width <= 0 || param.page.height <= 0)
+ {
+ if (doc->logfunc) doc->logfunc(doc->logdata, CF_LOGLEVEL_WARN,
+ "cfFilterPDFToPDF: Could not determine the output page dimensions, falling back to US Letter format");
+ param.page.width = 612;
+ param.page.height = 792;
}
- else
+ if (param.page.left < 0)
{
- if(printer_attrs!=NULL){
- char defSize[41];
- int min_length = 99999,
- max_length = 0,
- min_width = 99999,
- max_width = 0,
- left, right,
- top, bottom;
- cfGenerateSizes(printer_attrs, &ipp, &min_length, &min_width,
- &max_length, &max_width, &bottom, &left, &right, &top,
- defSize);
- param.page.top = top* 72.0/2540.0;
- param.page.bottom = bottom* 72.0/2540.0;
- param.page.right = right * 72.0/2540.0;
- param.page.left = left* 72.0/2540.0;
- param.page.width = min_width*72.0/2540.0;
- param.page.height = min_length*72.0/2540.0;
- }
-
- #ifdef HAVE_CUPS_1_7
- if ((val = cupsGetOption("media-size", num_options, options)) != NULL ||
- (val = cupsGetOption("MediaSize", num_options, options)) != NULL ||
- (val = cupsGetOption("page-size", num_options, options)) != NULL ||
- (val = cupsGetOption("PageSize", num_options, options)) != NULL) {
- pwg_media_t *size_found = NULL;
- if (doc->logfunc) doc->logfunc(doc->logdata, CF_LOGLEVEL_DEBUG,
- "cfFilterPDFToPDF: Page size from command "
- "line: %s", val);
- if ((size_found = pwgMediaForPWG(val)) == NULL)
- if ((size_found = pwgMediaForPPD(val)) == NULL)
- size_found = pwgMediaForLegacy(val);
- if (size_found != NULL) {
- param.page.width = size_found->width * 72.0 / 2540.0;
- param.page.height = size_found->length * 72.0 / 2540.0;
- param.page.top=param.page.bottom=36.0;
- param.page.right=param.page.left=18.0;
- param.page.right=param.page.width-param.page.right;
- param.page.top=param.page.height-param.page.top;
- if (doc->logfunc) doc->logfunc(doc->logdata, CF_LOGLEVEL_DEBUG,
- "cfFilterPDFToPDF: Width: %f, Length: %f",
- param.page.width, param.page.height);
- }
- else
- if (doc->logfunc) doc->logfunc(doc->logdata, CF_LOGLEVEL_DEBUG,
- "cfFilterPDFToPDF: Unsupported page size %s.",
- val);
- }
- #endif /* HAVE_CUPS_1_7 */
+ if (doc->logfunc) doc->logfunc(doc->logdata, CF_LOGLEVEL_WARN,
+ "cfFilterPDFToPDF: Could not determine the width of the left margin, falling back to 18 pt/6.35 mm");
+ param.page.left = 18.0;
}
+ if (param.page.bottom < 0)
+ {
+ if (doc->logfunc) doc->logfunc(doc->logdata, CF_LOGLEVEL_WARN,
+ "cfFilterPDFToPDF: Could not determine the width of the bottom margin, falling back to 36 pt/12.7 mm");
+ param.page.bottom = 36.0;
+ }
+ if (param.page.right < 0)
+ {
+ if (doc->logfunc) doc->logfunc(doc->logdata, CF_LOGLEVEL_WARN,
+ "cfFilterPDFToPDF: Could not determine the width of the right margin, falling back to 18 pt/6.35 mm");
+ param.page.right = param.page.width - 18.0;
+ }
+ else
+ param.page.right = param.page.width - param.page.right;
+ if (param.page.top < 0)
+ {
+ if (doc->logfunc) doc->logfunc(doc->logdata, CF_LOGLEVEL_WARN,
+ "cfFilterPDFToPDF: Could not determine the width of the top margin, falling back to 36 pt/12.7 mm");
+ param.page.top = param.page.height - 36.0;
+ }
+ else
+ param.page.top = param.page.height - param.page.top;
+
param.paper_is_landscape=(param.page.width>param.page.height);
_cfPDFToPDFPageRect tmp; // borders (before rotation)
param.page.set(tmp); // replace values, where tmp.* != NaN (because tmp needed rotation, param.page not!)
- if (ppdGetDuplex(ppd)) {
+ if ((val = cfIPPAttrEnumValForPrinter(printer_attrs, job_attrs, "sides")) !=
+ NULL &&
+ strncmp(val, "two-sided-", 10) == 0) {
param.duplex=true;
- } else if (is_true(cupsGetOption("Duplex",num_options,options))) {
+ } else if (is_true(cupsGetOption("Duplex", num_options, options))) {
param.duplex=true;
param.set_duplex=true;
} else if ((val=cupsGetOption("sides",num_options,options)) != NULL) {
if ((val=cupsGetOption("OutputOrder",num_options,options)) != NULL ||
(val=cupsGetOption("output-order",num_options,options)) != NULL ||
- (val=cupsGetOption("page-delivery",num_options,options)) != NULL) {
+ (val=cupsGetOption("page-delivery",num_options,options)) != NULL)
+ {
param.reverse = (strcasecmp(val, "Reverse") == 0 ||
strcasecmp(val, "reverse-order") == 0);
- } else if (ppd) {
- param.reverse=ppdDefaultOrder(ppd, doc);
}
+ else
+ param.reverse = cfIPPReverseOutput(printer_attrs, job_attrs);
std::string rawlabel;
char *classification = getenv("CLASSIFICATION");
parseRanges(val,param.input_page_ranges);
}
- ppd_choice_t *choice;
- if ((choice=ppdFindMarkedChoice(ppd,"MirrorPrint")) != NULL) {
- val=choice->choice;
- } else {
- if((val = cupsGetOption("mirror", num_options, options))!=NULL ||
- (val = cupsGetOption("mirror-print", num_options, options))!=NULL ||
- (val = cupsGetOption("MirrorPrint", num_options, options))!=NULL)
+ if((val = cupsGetOption("mirror", num_options, options)) != NULL ||
+ (val = cupsGetOption("mirror-print", num_options, options)) != NULL)
param.mirror=is_true(val);
- }
-
-
- if ((val=cupsGetOption("emit-jcl",num_options,options)) != NULL) {
- param.emit_jcl=!is_false(val)&&(strcmp(val,"0")!=0);
- }
param.booklet=pdftopdf_booklet_mode_e::CF_PDFTOPDF_BOOKLET_OFF;
if ((val=cupsGetOption("booklet",num_options,options)) != NULL) {
}
}
- param.collate=optGetCollate(num_options,options);
- // FIXME? pdftopdf also considers if ppdCollate is set (only when cupsGetOption is /not/ given) [and if is_true overrides param.collate=true] -- pstops does not
+ // Collate
+ if (is_true(cupsGetOption("Collate", num_options, options)))
+ param.collate = true;
+ else if ((val = cupsGetOption("sheet-collate", num_options, options)) != NULL)
+ param.collate = (strcasecmp(val, "uncollated") != 0);
+ else if (((val = cupsGetOption("multiple-document-handling",
+ num_options, options)) != NULL &&
+ (strcasecmp(val, "separate-documents-collated-copies") == 0 ||
+ strcasecmp(val, "separate-documents-uncollated-copies") == 0 ||
+ strcasecmp(val, "single-document") == 0 ||
+ strcasecmp(val, "single-document-new-sheet") == 0)) ||
+ (val = cfIPPAttrEnumValForPrinter(printer_attrs, job_attrs,
+ "multiple-document-handling")) !=
+ NULL)
+ /* This IPP attribute is unnecessarily complicated:
+ * single-document, separate-documents-collated-copies, single-document-new-sheet:
+ * -> collate (true)
+ * separate-documents-uncollated-copies:
+ * -> can be uncollated (false)
+ */
+ param.collate =
+ (strcasecmp(val, "separate-documents-uncollated-copies") != 0);
-/*
+ /*
// TODO: scaling
// TODO: natural-scaling
naturalScaling = atoi(val) * 0.01;
}
-bool checkFeature(const char *feature, int num_options, cups_option_t *options) // {{{
-{
- const char *val;
- ppd_attr_t *attr;
-
- return ((val=cupsGetOption(feature,num_options,options)) != NULL && is_true(val)) ||
- ((attr=ppdFindAttr(ppd,feature,0)) != NULL && is_true(attr->val));
-}
-// }}}
-*/
+ */
// make pages a multiple of two (only considered when duplex is on).
// i.e. printer has hardware-duplex, but needs pre-inserted filler pages
// FIXME? pdftopdf also supports it as cmdline option (via checkFeature())
- ppd_attr_t *attr;
- if ((attr=ppdFindAttr(ppd,"cupsEvenDuplex",0)) != NULL) {
- param.even_duplex=is_true(attr->value);
- }
+ param.even_duplex =
+ (param.duplex &&
+ is_true(cupsGetOption("even-duplex", num_options, options)));
// TODO? pdftopdf* ?
// TODO?! pdftopdfAutoRotate
// printer driver) does page logging in the /var/log/cups/page_log file
// by outputting "PAGE: <# of current page> <# of copies>" to stderr.
- // pdftopdf would have to do this only for PDF printers as in this case
- // pdftopdf is the last filter, but some of the other filters are not
- // able to do the logging because they do not have access to the number
- // of pages of the file to be printed, so pdftopdf overtakes their logging
- // duty.
-
- // The filters currently are:
- // - foomatic-rip (lets Ghostscript convert PDF to printer's format via
- // built-in drivers, no access to the PDF content)
- // - gstopxl (uses Ghostscript, like foomatic-rip)
- // - *toraster on IPP Everywhere printers (then *toraster gets the last
- // filter, the case if FINAL_CONTENT_TYPE env var is "image/pwg-raster")
- // - hpps (bug)
-
- // Check whether page logging is forced or suppressed by the command line
- if ((val=cupsGetOption("page-logging",num_options,options)) != NULL) {
+ // cfFilterPDFToPDF() would have to do this only for PDF printers as
+ // in this case cfFilterPDFToPDF() is the last filter, but some of
+ // the other filters are not able to do the logging because they do
+ // not have access to the number of pages of the file to be printed,
+ // so cfFilterPDFToPDF() overtakes their logging duty.
+
+ // Check whether page logging is forced or suppressed by the options
+ if ((val = cupsGetOption("pdf-filter-page-logging",
+ num_options, options)) != NULL) {
if (strcasecmp(val,"auto") == 0) {
param.page_logging = -1;
if (doc->logfunc) doc->logfunc(doc->logdata, CF_LOGLEVEL_DEBUG,
"cfFilterPDFToPDF: Automatic page logging "
- "selected by command line.");
+ "selected by options.");
} else if (is_true(val)) {
param.page_logging = 1;
if (doc->logfunc) doc->logfunc(doc->logdata, CF_LOGLEVEL_DEBUG,
- "cfFilterPDFToPDF: Forced page logging selected "
- "by command line.");
+ "cfFilterPDFToPDF: Forced page logging "
+ "selected by options.");
} else if (is_false(val)) {
param.page_logging = 0;
if (doc->logfunc) doc->logfunc(doc->logdata, CF_LOGLEVEL_DEBUG,
- "cfFilterPDFToPDF: Suppressed page logging "
- "selected by command line.");
+ "cfFilterPDFToPDF: Suppressed page "
+ "logging selected by options.");
} else {
if (doc->logfunc) doc->logfunc(doc->logdata, CF_LOGLEVEL_ERROR,
- "cfFilterPDFToPDF: Unsupported page-logging "
- "value %s, using page-logging=auto!",val);
+ "cfFilterPDFToPDF: Unsupported page "
+ "logging setting "
+ "\"pdf-filter-page-logging=%s\", "
+ "using \"auto\"!", val);
param.page_logging = -1;
}
}
if (param.page_logging == -1) {
- // Determine the last filter in the chain via cupsFilter(2) lines of the
- // PPD file and FINAL_CONTENT_TYPE
- if (!ppd) {
- // If PPD file is not specified, we determine whether to log pages or not
- // using FINAL_CONTENT_TYPE env variable. log pages only when FINAL_CONTENT_TYPE is
- // either pdf or raster
-
- if (final_content_type && (strcasestr(final_content_type, "/pdf") ||
- strcasestr(final_content_type, "/vnd.cups-pdf") ||
- strcasestr(final_content_type, "/pwg-raster")))
- param.page_logging = 1;
- else
- param.page_logging = 0;
- // If final_content_type is not clearly available we are not sure whether to log pages or not
- if((char*)final_content_type==NULL ||
- sizeof(final_content_type)==0 ||
- final_content_type[0]=='\0'){
- param.page_logging = -1;
- }
- if (doc->logfunc) doc->logfunc(doc->logdata, CF_LOGLEVEL_DEBUG,
- "cfFilterPDFToPDF: No PPD file specified, "
- "determined whether to log pages or "
- "not using final_content_type env variable.");
- doc->logfunc(doc->logdata,CF_LOGLEVEL_DEBUG,"final_content_type = %s page_logging=%d",final_content_type?final_content_type:"NULL",param.page_logging);
- } else {
- char *lastfilter = NULL;
- if (final_content_type == NULL) {
- // No FINAL_CONTENT_TYPE env variable set, we cannot determine
- // whether we have to log pages, so do not log.
- param.page_logging = 0;
- if (doc->logfunc) doc->logfunc(doc->logdata, CF_LOGLEVEL_DEBUG,
- "cfFilterPDFToPDF: No FINAL_CONTENT_TYPE "
- "environment variable, could not "
- "determine whether to log pages or "
- "not, so turned off page logging.");
- // Proceed depending on number of cupsFilter(2) lines in PPD
- } else if (ppd->num_filters == 0) {
- // No filter line, manufacturer-supplied PostScript PPD
- // In this case cfFilterPSToPS, called by cfFilterPDFToPS, does the logging
- param.page_logging = 0;
- } else if (ppd->num_filters == 1) {
- // One filter line, so this one filter is the last filter
- lastfilter = ppd->filters[0];
- } else {
- // More than one filter line, determine the one which got
- // actually used via FINAL_CONTENT_TYPE
- ppd_attr_t *ppd_attr;
- if ((ppd_attr = ppdFindAttr(ppd, "cupsFilter2", NULL)) != NULL) {
- // We have cupsFilter2 lines, use only these
- do {
- // Go to the second work, which is the destination MIME type
- char *p = ppd_attr->value;
- while (!isspace(*p)) p ++;
- while (isspace(*p)) p ++;
- // Compare with FINAL_CONTEN_TYPE
- if (!strncasecmp(final_content_type, p,
- strlen(final_content_type))) {
- lastfilter = ppd_attr->value;
- break;
- }
- } while ((ppd_attr = ppdFindNextAttr(ppd, "cupsFilter2", NULL))
- != NULL);
- } else {
- // We do not have cupsFilter2 lines, use the cupsFilter lines
- int i;
- for (i = 0; i < ppd->num_filters; i ++) {
- // Compare source MIME type (first word) with FINAL_CONTENT_TYPE
- if (!strncasecmp(final_content_type, ppd->filters[i],
- strlen(final_content_type))) {
- lastfilter = ppd->filters[i];
- break;
- }
- }
- }
- }
- if (param.page_logging == -1) {
- if (lastfilter) {
- // Get the name of the last filter, without mime type and cost
- char *p = lastfilter;
- char *q = p + strlen(p) - 1;
- while(!isspace(*q) && *q != '/') q --;
- lastfilter = q + 1;
- // Check whether we have to log
- if (!strcasecmp(lastfilter, "-")) {
- // No filter defined in the PPD
- // If output data (FINAL_CONTENT_TYPE) is PDF, pdftopdf is last
- // filter (PDF printer) and has to log
- // If output data (FINAL_CONTENT_TYPE) is PWG Raster, *toraster is
- // last filter (IPP Everywhere printer) and pdftopdf has to log
- if (strcasestr(final_content_type, "/pdf") ||
- strcasestr(final_content_type, "/vnd.cups-pdf") ||
- strcasestr(final_content_type, "/pwg-raster"))
- param.page_logging = 1;
- else
- param.page_logging = 0;
- } else if (!strcasecmp(lastfilter, "pdftopdf")) {
- // pdftopdf is last filter (PDF printer)
- param.page_logging = 1;
- } else if (!strcasecmp(lastfilter, "gstopxl")) {
- // gstopxl is last filter, this is a Ghostscript-based filter
- // without access to the pages of the file to be printed, so we
- // log the pages
- param.page_logging = 1;
- } else if (!strcasecmp(lastfilter + strlen(lastfilter) - 8,
- "toraster") ||
- !strcasecmp(lastfilter + strlen(lastfilter) - 5,
- "topwg")) {
- // On IPP Everywhere printers which accept PWG Raster data one
- // of gstoraster, cfFilterPDFToRaster, or mupdftopwg is the last
- // filter. These filters do not log pages so pdftopdf has to
- // do it
- param.page_logging = 1;
- } else if (!strcasecmp(lastfilter, "foomatic-rip")) {
- // foomatic-rip is last filter, foomatic-rip is mainly used as
- // Ghostscript wrapper to use Ghostscript's built-in printer
- // drivers. Here there is also no access to the pages so that we
- // delegate the logging to pdftopdf
- param.page_logging = 1;
- } else if (!strcasecmp(lastfilter, "hpps")) {
- // hpps is last filter, hpps is part of HPLIP and it is a bug that
- // it does not do the page logging.
- param.page_logging = 1;
- } else {
- // All the other filters log pages as expected.
- param.page_logging = 0;
- }
- } else {
- if (doc->logfunc) doc->logfunc(doc->logdata, CF_LOGLEVEL_ERROR,
- "cfFilterPDFToPDF: Last filter could not "
- "get determined, page logging turned "
- "off.");
- param.page_logging = 0;
- }
- }
- if (doc->logfunc) doc->logfunc(doc->logdata, CF_LOGLEVEL_DEBUG,
- "cfFilterPDFToPDF: Last filter determined by the "
- "PPD: %s; FINAL_CONTENT_TYPE: "
- "%s => pdftopdf will %slog pages in "
- "page_log.",
- (lastfilter ? lastfilter : "None"),
- (final_content_type ? final_content_type :
- "(not supplied)"),
- (param.page_logging == 0 ? "not " : ""));
+ // We determine whether to log pages or not
+ // using the output data MIME type. log pages only when the output is
+ // either pdf or PWG Raster
+ if (final_content_type &&
+ (strcasestr(final_content_type, "/pdf") ||
+ strcasestr(final_content_type, "/vnd.cups-pdf") ||
+ strcasestr(final_content_type, "/pwg-raster")))
+ param.page_logging = 1;
+ else
+ param.page_logging = 0;
+
+ // If final_content_type is not clearly available we are not sure whether
+ // to log pages or not
+ if((char*)final_content_type==NULL ||
+ sizeof(final_content_type)==0 ||
+ final_content_type[0]=='\0'){
+ param.page_logging = -1;
+ }
+ if (doc->logfunc)
+ {
+ doc->logfunc(doc->logdata, CF_LOGLEVEL_DEBUG,
+ "cfFilterPDFToPDF: Determined whether to "
+ "log pages or not using output data type.");
+ doc->logfunc(doc->logdata, CF_LOGLEVEL_DEBUG,
+ "final_content_type = %s => page_logging = %d",
+ final_content_type ? final_content_type : "NULL",
+ param.page_logging);
}
+ if (param.page_logging == -1)
+ param.page_logging = 0;
}
}
// }}}
-static bool printerWillCollate(ppd_file_t *ppd) // {{{
+void calculate(int num_options,
+ cups_option_t *options,
+ _cfPDFToPDFProcessingParameters ¶m,
+ char *final_content_type) // {{{
{
- ppd_choice_t *choice;
-
- if (((choice=ppdFindMarkedChoice(ppd,"Collate")) != NULL)&&
- (is_true(choice->choice))) {
-
- // printer can collate, but also for the currently marked ppd features?
- ppd_option_t *opt=ppdFindOption(ppd,"Collate");
- return (opt)&&(!opt->conflicted);
+ const char *val;
+ bool hw_copies = false,
+ hw_collate = false;
+
+
+ // Check options for caller's instructions about hardware copies/collate
+ if ((val = cupsGetOption("hardware-copies",
+ num_options, options)) != NULL)
+ // Use hardware copies according to the caller's instructions
+ hw_copies = is_true(val);
+ else
+ // Caller did not tell us whether the printer does Hardware copies
+ // or not, so we assume hardware copies on PDF printers, and software
+ // copies on other (usually raster) printers or if we do not know the
+ // final output format.
+ hw_copies = (final_content_type &&
+ (strcasestr(final_content_type, "/pdf") ||
+ strcasestr(final_content_type, "/vnd.cups-pdf")));
+ if (hw_copies)
+ {
+ if ((val = cupsGetOption("hardware-collate",
+ num_options, options)) != NULL)
+ // Use hardware collate according to the caller's instructions
+ hw_collate = is_true(val);
+ else
+ // Check output format MIME type whether it is
+ // of a driverless IPP printer (PDF, Apple Raster, PWG Raster, PCLm).
+ // These printers do always hardware collate if they do hardware copies.
+ // https://github.com/apple/cups/issues/5433
+ hw_collate = (final_content_type &&
+ (strcasestr(final_content_type, "/pdf") ||
+ strcasestr(final_content_type, "/vnd.cups-pdf") ||
+ strcasestr(final_content_type, "/pwg-raster") ||
+ strcasestr(final_content_type, "/urf") ||
+ strcasestr(final_content_type, "/PCLm")));
}
- return false;
-}
-// }}}
-
-void calculate(cf_filter_data_t *data,_cfPDFToPDFProcessingParameters ¶m,char *final_content_type) // {{{
-{
- ppd_file_t *ppd = data->ppd;
- int num_options = 0;
- cups_option_t *options = NULL;
- num_options = cfJoinJobOptionsAndAttrs(data, num_options, &options);
- if (param.reverse)
+
+ if (param.reverse && param.duplex)
// Enable even_duplex or the first page may be empty.
param.even_duplex=true; // disabled later, if non-duplex
- setFinalPPD(ppd,param);
-
if (param.num_copies==1) {
param.device_copies=1;
// collate is never needed for a single copy
param.collate=false; // (does not make a big difference for us)
- } else if ((ppd)&&(!ppd->manual_copies)) { // hw copy generation available
+ } else if (hw_copies) { // hw copy generation available
param.device_copies=param.num_copies;
if (param.collate) { // collate requested by user
- // Check output format (FINAL_CONTENT_TYPE env variable) whether it is
- // of a driverless IPP printer (PDF, Apple Raster, PWG Raster, PCLm).
- // These printers do always hardware collate if they do hardware copies.
- // https://github.com/apple/cups/issues/5433
- if (final_content_type &&
- (strcasestr(final_content_type, "/pdf") ||
- strcasestr(final_content_type, "/vnd.cups-pdf") ||
- strcasestr(final_content_type, "/pwg-raster") ||
- strcasestr(final_content_type, "/urf") ||
- strcasestr(final_content_type, "/PCLm"))) {
- param.device_collate = true;
- } else {
- // check collate device, with current/final(!) ppd settings
- param.device_collate=printerWillCollate(ppd);
- if (!param.device_collate) {
- // printer can't hw collate -> we must copy collated in sw
- param.device_copies=1;
- }
+ param.device_collate = hw_collate;
+ if (!param.device_collate) {
+ // printer can't hw collate -> we must copy collated in sw
+ param.device_copies=1;
}
} // else: printer copies w/o collate and takes care of duplex/even_duplex
}
- else if(final_content_type &&
- ((strcasestr(final_content_type, "/pdf")) ||
- (strcasestr(final_content_type, "/vnd.cups-pdf")))){
- param.device_copies = param.num_copies;
- if(param.collate){
- param.device_collate = true;
- }
- }
- else { // sw copies
+ else { // sw copies
param.device_copies=1;
if (param.duplex) { // &&(num_copies>1)
// sw collate + even_duplex must be forced to prevent copies on the backsides
}
}
- // TODO? FIXME: unify code with emitJCLOptions, which does this "by-hand" now (and makes this code superfluous)
- if (param.device_copies==1) {
- // make sure any hardware copying is disabled
- ppdMarkOption(ppd,"Copies","1");
- ppdMarkOption(ppd,"JCLCopies","1");
- } else { // hw copy
+ if (param.device_copies != 1) //hw copy
param.num_copies=1; // disable sw copy
- }
- if ((param.collate)&&(!param.device_collate)) { // software collate
- ppdMarkOption(ppd,"Collate","False"); // disable any hardware-collate (in JCL)
+ if (param.duplex &&
+ param.collate && !param.device_collate) // software collate
param.even_duplex=true; // fillers always needed
- }
- if (!param.duplex) {
+ if (!param.duplex)
param.even_duplex=false;
- }
}
// }}}
int outputfd, /* I - File descriptor output stream */
int inputseekable, /* I - Is input stream seekable? */
cf_filter_data_t *data, /* I - Job and printer data */
- void *parameters) /* I - Filter-specific parameters */
+ void *parameters) /* I - Filter-specific parameters (unused) */
{
pdftopdf_doc_t doc; /* Document information */
- char *final_content_type = NULL;
+ char *final_content_type = data->final_content_type;
FILE *inputfp,
*outputfp;
const char *t;
void *icd = data->iscanceleddata;
int num_options = 0;
cups_option_t *options = NULL;
- num_options = cfJoinJobOptionsAndAttrs(data, num_options, &options);
- if (parameters)
- final_content_type = (char *)parameters;
try {
_cfPDFToPDFProcessingParameters param;
doc.iscanceledfunc = iscanceled;
doc.iscanceleddata = icd;
- getParameters(data, num_options, options, param, final_content_type, &doc);
+ num_options = cfJoinJobOptionsAndAttrs(data, num_options, &options);
- calculate(data, param, final_content_type);
+ getParameters(data, num_options, options, param, &doc);
+
+ calculate(num_options, options, param, final_content_type);
#ifdef DEBUG
param.dump(&doc);
"cfFilterPDFToPDF: Streaming mode: No PDF processing, only adding of JCL");
}
+ cupsFreeOptions(num_options, options);
+
std::unique_ptr<_cfPDFToPDFProcessor> proc(_cfPDFToPDFFactory::processor());
if ((inputseekable && inputfd > 0) || streaming) {
return 2;
// Pass information to subsequent filters via PDF comments
- _cfPDFToPDFEmitComment(*proc, param);
- }
+ std::vector<std::string> output;
+
+ output.push_back("% This file was generated by pdftopdf");
+
+ // This is not standard, but like PostScript.
+ if (param.device_copies > 0)
+ {
+ char buf[256];
+ snprintf(buf, sizeof(buf), "%d", param.device_copies);
+ output.push_back(std::string("%%PDFTOPDFNumCopies : ")+buf);
+
+ if (param.device_collate)
+ output.push_back("%%PDFTOPDFCollate : true");
+ else
+ output.push_back("%%PDFTOPDFCollate : false");
+ }
- /* TODO
- // color management
- --- PPD:
- copyPPDLine_(fp_dest, fp_src, "*PPD-Adobe: ");
- copyPPDLine_(fp_dest, fp_src, "*cupsICCProfile ");
- copyPPDLine_(fp_dest, fp_src, "*Manufacturer:");
- copyPPDLine_(fp_dest, fp_src, "*ColorDevice:");
- copyPPDLine_(fp_dest, fp_src, "*DefaultColorSpace:");
- if (cupsICCProfile) {
- proc.add_cm(...,...);
+ proc->set_comments(output);
}
- */
outputfp = fdopen(outputfd, "w");
if (outputfp == NULL)
return 1;
- _cfPDFToPDFEmitPreamble(outputfp, data->ppd, param); // ppdEmit, JCL stuff
-
if (!streaming) {
// Pass on the processed input data
proc->emit_file(outputfp, &doc, CF_PDFTOPDF_WILL_STAY_ALIVE);
fclose(inputfp);
}
- _cfPDFToPDFEmitPostamble(outputfp, data->ppd,param);
fclose(outputfp);
} catch (std::exception &e) {
// TODO? exception type
#include "colormanager.h"
#include "image.h"
#include "filter.h"
+#include "ipp.h"
#include <config.h>
#include <cups/cups.h>
#if (CUPS_VERSION_MAJOR > 1) || (CUPS_VERSION_MINOR > 6)
#ifdef HAVE_CPP_POPPLER_VERSION_H
#include <poppler/cpp/poppler-version.h>
#endif
-#include <ppd/ppd.h>
#include <stdarg.h>
#include <cups/raster.h>
#include <cupsfilters/image.h>
unsigned int bitspercolor;
unsigned int popplerNumColors;
unsigned int bitmapoffset[2];
- ppd_file_t *ppd = 0;
poppler::document *poppler_doc;
cups_page_header2_t header;
cf_logfunc_t logfunc; /* Logging function, NULL for no
}
#endif
-static void handle_requires_page_region(pdftoraster_doc_t*doc) {
- ppd_choice_t *mf;
- ppd_choice_t *is;
- ppd_attr_t *rregions = NULL;
- ppd_size_t *size;
-
- if ((size = ppdPageSize(doc->ppd,NULL)) == NULL) return;
- mf = ppdFindMarkedChoice(doc->ppd,"ManualFeed");
- if ((is = ppdFindMarkedChoice(doc->ppd,"InputSlot")) != NULL) {
- rregions = ppdFindAttr(doc->ppd,"RequiresPageRegion",is->choice);
- }
- if (rregions == NULL) {
- rregions = ppdFindAttr(doc->ppd,"RequiresPageRegion","All");
- }
- if (!strcasecmp(size->name,"Custom") || (!mf && !is) ||
- (mf && !strcasecmp(mf->choice,"False") &&
- (!is || (is->code && !is->code[0]))) ||
- (!rregions && doc->ppd->num_filters > 0)) {
- ppdMarkOption(doc->ppd,"PageSize",size->name);
- } else if (rregions && rregions->value
- && !strcasecmp(rregions->value,"True")) {
- ppdMarkOption(doc->ppd,"PageRegion",size->name);
- } else {
- ppd_choice_t *page;
-
- if ((page = ppdFindMarkedChoice(doc->ppd,"PageSize")) != NULL) {
- page->marked = 0;
- cupsArrayRemove(doc->ppd->marked,page);
- }
- if ((page = ppdFindMarkedChoice(doc->ppd,"PageRegion")) != NULL) {
- page->marked = 0;
- cupsArrayRemove(doc->ppd->marked, page);
- }
- }
-}
-
static int parse_opts(cf_filter_data_t *data,
- cf_filter_out_format_t outformat,
- pdftoraster_doc_t *doc)
+ cf_filter_out_format_t outformat,
+ pdftoraster_doc_t *doc)
{
int num_options = 0;
cups_option_t *options = NULL;
char *profile = NULL;
const char *t = NULL;
- ppd_attr_t *attr;
const char *val;
cf_logfunc_t log = data->logfunc;
void *ld = data ->logdata;
- ipp_t *printer_attrs = data->printer_attrs;
cups_cspace_t cspace = (cups_cspace_t)(-1);
if (outformat == CF_FILTER_OUT_FORMAT_PWG_RASTER ||
num_options = cfJoinJobOptionsAndAttrs(data, num_options, &options);
- doc->ppd = data->ppd;
-
- if (doc->ppd)
- handle_requires_page_region(doc);
- else
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPDFToRaster: PPD file is not specified.");
-
+ memset(&(doc->header), 0, sizeof(doc->header));
cfRasterPrepareHeader(&(doc->header), data, outformat,
(outformat == CF_FILTER_OUT_FORMAT_PWG_RASTER ||
outformat == CF_FILTER_OUT_FORMAT_APPLE_RASTER ?
outformat : CF_FILTER_OUT_FORMAT_CUPS_RASTER), 0,
&cspace);
- if (doc->ppd) {
- attr = ppdFindAttr(doc->ppd,"pdftorasterRenderingIntent",NULL);
- if (attr != NULL && attr->value != NULL) {
- if (strcasecmp(attr->value,"PERCEPTUAL") == 0) {
- doc->colour_profile.renderingIntent = INTENT_PERCEPTUAL;
- } else if (strcasecmp(attr->value,"RELATIVE_COLORIMETRIC") == 0) {
- doc->colour_profile.renderingIntent = INTENT_RELATIVE_COLORIMETRIC;
- } else if (strcasecmp(attr->value,"SATURATION") == 0) {
- doc->colour_profile.renderingIntent = INTENT_SATURATION;
- } else if (strcasecmp(attr->value,"ABSOLUTE_COLORIMETRIC") == 0) {
- doc->colour_profile.renderingIntent = INTENT_ABSOLUTE_COLORIMETRIC;
- }
- }
- if (doc->header.Duplex) {
- /* analyze options relevant to Duplex */
- const char *backside = "";
- /* APDuplexRequiresFlippedMargin */
- enum {
- FM_NO, FM_FALSE, FM_TRUE
- } flippedMargin = FM_NO;
-
- attr = ppdFindAttr(doc->ppd,"cupsBackSide",NULL);
- if (attr != NULL && attr->value != NULL) {
- doc->ppd->flip_duplex = 0;
- backside = attr->value;
- } else if (doc->ppd->flip_duplex) {
- backside = "Rotated"; /* compatible with Max OS and GS 8.71 */
- }
-
- attr = ppdFindAttr(doc->ppd,"APDuplexRequiresFlippedMargin",NULL);
- if (attr != NULL && attr->value != NULL) {
- if (strcasecmp(attr->value,"true") == 0) {
- flippedMargin = FM_TRUE;
- } else {
- flippedMargin = FM_FALSE;
- }
- }
- if (strcasecmp(backside,"ManualTumble") == 0 && doc->header.Tumble) {
- doc->swap_image_x = doc->swap_image_y = true;
- doc->swap_margin_x = doc->swap_margin_y = true;
- if (flippedMargin == FM_TRUE) {
- doc->swap_margin_y = false;
- }
- } else if (strcasecmp(backside,"Rotated") == 0 && !doc->header.Tumble) {
- doc->swap_image_x = doc->swap_image_y = true;
- doc->swap_margin_x = doc->swap_margin_y = true;
- if (flippedMargin == FM_TRUE) {
- doc->swap_margin_y = false;
- }
- } else if (strcasecmp(backside,"Flipped") == 0) {
- if (doc->header.Tumble) {
- doc->swap_image_x = true;
- doc->swap_margin_x = doc->swap_margin_y = true;
- } else {
- doc->swap_image_y = true;
- }
- if (flippedMargin == FM_FALSE) {
- doc->swap_margin_y = !doc->swap_margin_y;
- }
- }
- }
-
- /* support the CUPS "cm-calibration" option */
- doc->colour_profile.cm_calibrate = cfCmGetCupsColorCalibrateMode(data, options, num_options);
-
- if (doc->colour_profile.cm_calibrate == CF_CM_CALIBRATION_ENABLED)
- doc->colour_profile.cm_disabled = 1;
- else
- doc->colour_profile.cm_disabled = cfCmIsPrinterCmDisabled(data);
-
- if (!doc->colour_profile.cm_disabled)
- cfCmGetPrinterIccProfile(data, &profile, doc->ppd);
-
- if (profile != NULL) {
- doc->colour_profile.colorProfile = cmsOpenProfileFromFile(profile,"r");
- free(profile);
- }
-
- if ((attr = ppdFindAttr(doc->ppd,"PWGRaster",0)) != 0 &&
- (!strcasecmp(attr->value, "true")
- || !strcasecmp(attr->value, "on") ||
- !strcasecmp(attr->value, "yes")))
- doc->pwgraster = 1;
- } else {
+ t = cupsGetOption("media-class", num_options, options);
+ if (t == NULL)
+ t = cupsGetOption("MediaClass", num_options, options);
+ if (t != NULL && strcasestr(t, "pwg"))
doc->pwgraster = 1;
- t = cupsGetOption("media-class", num_options, options);
- if (t == NULL)
- t = cupsGetOption("MediaClass", num_options, options);
- if (t != NULL)
+ else
+ doc->pwgraster = 0;
+
+ doc->header.cupsRenderingIntent[0] = '\0';
+ cfGetPrintRenderIntent(data, doc->header.cupsRenderingIntent,
+ sizeof(doc->header.cupsRenderingIntent));
+ if (strcasecmp(doc->header.cupsRenderingIntent, "PERCEPTUAL") == 0)
+ doc->colour_profile.renderingIntent = INTENT_PERCEPTUAL;
+ else if (strcasecmp(doc->header.cupsRenderingIntent, "RELATIVE") == 0)
+ doc->colour_profile.renderingIntent = INTENT_RELATIVE_COLORIMETRIC;
+ else if (strcasecmp(doc->header.cupsRenderingIntent, "SATURATION") == 0)
+ doc->colour_profile.renderingIntent = INTENT_SATURATION;
+ else if (strcasecmp(doc->header.cupsRenderingIntent, "ABSOLUTE") == 0)
+ doc->colour_profile.renderingIntent = INTENT_ABSOLUTE_COLORIMETRIC;
+ // XXX relative-bpc ???
+
+ if(log) log(ld, CF_LOGLEVEL_DEBUG,
+ "Print rendering intent = %s", doc->header.cupsRenderingIntent);
+
+ if (doc->header.Duplex)
+ {
+ int backside;
+ /* analyze options relevant to Duplex */
+ /* APDuplexRequiresFlippedMargin */
+ enum {
+ FM_NO,
+ FM_FALSE,
+ FM_TRUE
+ } flippedMargin;
+
+ backside = cfGetBackSideOrientation(data);
+
+ if (backside >= 0)
{
- if (strcasestr(t, "pwg"))
- doc->pwgraster = 1;
- else
- doc->pwgraster = 0;
- }
- cfGetPrintRenderIntent(data, &(doc->header));
- if(strcasecmp(doc->header.cupsRenderingIntent, "PERCEPTUAL")==0){
- doc->colour_profile.renderingIntent = INTENT_PERCEPTUAL;
- } else if (strcasecmp(doc->header.cupsRenderingIntent,"RELATIVE") == 0) {
- doc->colour_profile.renderingIntent = INTENT_RELATIVE_COLORIMETRIC;
- } else if (strcasecmp(doc->header.cupsRenderingIntent,"SATURATION") == 0) {
- doc->colour_profile.renderingIntent = INTENT_SATURATION;
- } else if (strcasecmp(doc->header.cupsRenderingIntent,"ABSOLUTE") == 0) {
- doc->colour_profile.renderingIntent = INTENT_ABSOLUTE_COLORIMETRIC;
- }
- if(log) log(ld, CF_LOGLEVEL_DEBUG,
- "Print rendering intent = %s", doc->header.cupsRenderingIntent);
-
- int backside = cfGetBackSideAndHeaderDuplex(printer_attrs, &(doc->header));
- if (doc->header.Duplex) {
- /* analyze options relevant to Duplex */
- /* APDuplexRequiresFlippedMargin */
- enum {
- FM_NO, FM_FALSE, FM_TRUE
- } flippedMargin = FM_NO;
-
- if (backside == CF_BACKSIDE_MANUAL_TUMBLE && doc->header.Tumble) {
+ flippedMargin = (backside & 16 ? FM_TRUE :
+ (backside & 8 ? FM_FALSE :
+ FM_NO));
+ backside &= 7;
+
+ if (backside == CF_BACKSIDE_MANUAL_TUMBLE && doc->header.Tumble)
+ {
doc->swap_image_x = doc->swap_image_y = true;
doc->swap_margin_x = doc->swap_margin_y = true;
- if (flippedMargin == FM_TRUE) {
+ if (flippedMargin == FM_TRUE)
doc->swap_margin_y = false;
- }
- } else if (backside==CF_BACKSIDE_ROTATED && !doc->header.Tumble) {
+ }
+ else if (backside==CF_BACKSIDE_ROTATED && !doc->header.Tumble)
+ {
doc->swap_image_x = doc->swap_image_y = true;
doc->swap_margin_x = doc->swap_margin_y = true;
- if (flippedMargin == FM_TRUE) {
+ if (flippedMargin == FM_TRUE)
doc->swap_margin_y = false;
- }
- } else if (backside==CF_BACKSIDE_FLIPPED) {
- if (doc->header.Tumble) {
+ }
+ else if (backside==CF_BACKSIDE_FLIPPED)
+ {
+ if (doc->header.Tumble)
+ {
doc->swap_image_x = true;
doc->swap_margin_x = doc->swap_margin_y = true;
- } else {
- doc->swap_image_y = true;
}
- if (flippedMargin == FM_FALSE) {
+ else
+ doc->swap_image_y = true;
+ if (flippedMargin == FM_FALSE)
doc->swap_margin_y = !doc->swap_margin_y;
- }
}
}
+ }
- /* support the CUPS "cm-calibration" option */
- doc->colour_profile.cm_calibrate = cfCmGetCupsColorCalibrateMode(data, options, num_options);
+ /* support the CUPS "cm-calibration" option */
+ doc->colour_profile.cm_calibrate = cfCmGetCupsColorCalibrateMode(data);
- if (doc->colour_profile.cm_calibrate == CF_CM_CALIBRATION_ENABLED)
- doc->colour_profile.cm_disabled = 1;
- else
- doc->colour_profile.cm_disabled = cfCmIsPrinterCmDisabled(data);
+ if (doc->colour_profile.cm_calibrate == CF_CM_CALIBRATION_ENABLED)
+ doc->colour_profile.cm_disabled = 1;
+ else
+ doc->colour_profile.cm_disabled = cfCmIsPrinterCmDisabled(data);
- if (!doc->colour_profile.cm_disabled)
- cfCmGetPrinterIccProfile(data, &profile, doc->ppd);
+ if (!doc->colour_profile.cm_disabled)
+ cfCmGetPrinterIccProfile
+ (data,
+ cfRasterColorSpaceString(doc->header.cupsColorSpace),
+ doc->header.MediaType,
+ doc->header.HWResolution[0], doc->header.HWResolution[1],
+ &profile);
- if (profile != NULL) {
- doc->colour_profile.colorProfile = cmsOpenProfileFromFile(profile,"r");
- free(profile);
- }
+ if (profile != NULL)
+ {
+ doc->colour_profile.colorProfile = cmsOpenProfileFromFile(profile,"r");
+ free(profile);
}
+
if ((val = cupsGetOption("print-color-mode", num_options, options)) != NULL
&& !strncasecmp(val, "bi-level", 8))
doc->bi_level = 1;
if (log) log(ld, CF_LOGLEVEL_DEBUG,
"cfFilterPDFToRaster: Page size requested: %s", doc->header.cupsPageSizeName);
- if (num_options)
- cupsFreeOptions(num_options, options);
+ cupsFreeOptions(num_options, options);
return (0);
}
return dst;
}
-/* Handle special cases which appear in Gutenprint's PPDs */
+/* Handle special cases which appear in the Gutenprint driver */
static bool select_special_case(pdftoraster_doc_t* doc, conversion_function_t* convert)
{
int i;
}
static void write_page_image(cups_raster_t *raster, pdftoraster_doc_t *doc,
- int pageNo, conversion_function_t* convert, cf_filter_iscanceledfunc_t iscanceled, void *icd)
+ int pageNo, conversion_function_t* convert, float overspray_factor, cf_filter_iscanceledfunc_t iscanceled, void *icd)
{
+ int i;
convert_line_func convertLine;
unsigned char *lineBuf = NULL;
unsigned char *dp;
unsigned int rowsize;
+ int fakeres[2];
if (iscanceled && iscanceled(icd))
return;
pr.set_render_hint(poppler::page_renderer::antialiasing, true);
pr.set_render_hint(poppler::page_renderer::text_antialiasing, true);
+ // Overspray borderless page size: If the dimensions of the page
+ // size are up to 10% larger than the ones of the input page, zoom
+ // the image by rendering with an appropriately larger fake
+ // resolution.
+ poppler::page_box_enum box = poppler::page_box_enum::crop_box;
+ poppler::rectf inputPageBox = current_page->page_rect(box);
+ for (i = 0; i < 2; i ++)
+ fakeres[i] = doc->header.HWResolution[i];
+ if (overspray_factor != 1.0)
+ for (i = 0; i < 2; i ++)
+ fakeres[i] = (int)(fakeres[i] * overspray_factor);
+
unsigned char *colordata,*newdata,*graydata,*onebitdata;
unsigned int pixel_count;
poppler::image im;
case CUPS_CSPACE_K: // Black
case CUPS_CSPACE_SW: // sGray
if(doc->header.cupsBitsPerColor==1){ // Special case for 1-bit colorspaces
- im = pr.render_page(current_page,doc->header.HWResolution[0],doc->header.HWResolution[1],doc->bitmapoffset[0],doc->bitmapoffset[1],(doc->bytesPerLine)*8,doc->header.cupsHeight);
+ im = pr.render_page(current_page,fakeres[0],fakeres[1],doc->bitmapoffset[0],doc->bitmapoffset[1],(doc->bytesPerLine)*8,doc->header.cupsHeight);
newdata = (unsigned char *)malloc(sizeof(char)*3*im.width()*im.height());
newdata = remove_alpha((unsigned char *)im.const_data(),newdata,im.width(),im.height());
graydata=(unsigned char *)malloc(sizeof(char)*im.width()*im.height());
rowsize=doc->bytesPerLine;
}
else{
- im = pr.render_page(current_page,doc->header.HWResolution[0],doc->header.HWResolution[1],doc->bitmapoffset[0],doc->bitmapoffset[1],doc->header.cupsWidth,doc->header.cupsHeight);
+
+ im = pr.render_page(current_page,fakeres[0],fakeres[1],doc->bitmapoffset[0],doc->bitmapoffset[1],doc->header.cupsWidth,doc->header.cupsHeight);
newdata = (unsigned char *)malloc(sizeof(char)*3*im.width()*im.height());
newdata = remove_alpha((unsigned char *)im.const_data(),newdata,im.width(),im.height());
pixel_count=im.width()*im.height();
case CUPS_CSPACE_CMY:
case CUPS_CSPACE_RGBW:
default:
- im = pr.render_page(current_page,doc->header.HWResolution[0],doc->header.HWResolution[1],doc->bitmapoffset[0],doc->bitmapoffset[1],doc->header.cupsWidth,doc->header.cupsHeight);
+ im = pr.render_page(current_page,fakeres[0],fakeres[1],doc->bitmapoffset[0],doc->bitmapoffset[1],doc->header.cupsWidth,doc->header.cupsHeight);
newdata = (unsigned char *)malloc(sizeof(char)*3*im.width()*im.height());
newdata = remove_alpha((unsigned char *)im.const_data(),newdata,im.width(),im.height());
pixel_count=im.width()*im.height();
cups_raster_t *raster, conversion_function_t *convert, cf_logfunc_t log, void* ld, cf_filter_iscanceledfunc_t iscanceled, void *icd)
{
int rotate = 0;
- double paperdimensions[2], /* Physical size of the paper */
+ float paperdimensions[2], /* Physical size of the paper */
margins[4]; /* Physical margins of print */
double l, swap;
int imageable_area_fit = 0;
+ float overspray_factor = 1.0;
int i;
if (iscanceled && iscanceled(icd))
return (0);
poppler::page *current_page =doc->poppler_doc->create_page(pageNo-1);
- poppler::page_box_enum box = poppler::page_box_enum::media_box;
- poppler::rectf mediaBox = current_page->page_rect(box);
+ poppler::page_box_enum box = poppler::page_box_enum::crop_box;
+ poppler::rectf inputPageBox = current_page->page_rect(box);
poppler::page::orientation_enum orient = current_page->orientation();
switch (orient) {
case poppler::page::landscape: rotate=90;
default:rotate=0;
}
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPDFToRaster: mediabox = [ %f %f %f %f ]; rotate = %d",
- mediaBox.left(), mediaBox.top(), mediaBox.right(),
- mediaBox.bottom(), rotate);
- l = mediaBox.width();
+ "cfFilterPDFToRaster: cropbox = [ %f %f %f %f ]; rotate = %d",
+ inputPageBox.left(), inputPageBox.top(), inputPageBox.right(),
+ inputPageBox.bottom(), rotate);
+ // Enter input page dimensions in header, so that if no page size got
+ // specified for the job, the input size gets used via the header
+ l = inputPageBox.width();
if (l < 0) l = -l;
if (rotate == 90 || rotate == 270)
- doc->header.PageSize[1] = (unsigned)l;
+ doc->header.cupsPageSize[1] = l;
else
- doc->header.PageSize[0] = (unsigned)l;
- l = mediaBox.height();
+ doc->header.cupsPageSize[0] = l;
+ l = inputPageBox.height();
if (l < 0) l = -l;
if (rotate == 90 || rotate == 270)
- doc->header.PageSize[0] = (unsigned)l;
+ doc->header.cupsPageSize[0] = l;
+ else
+ doc->header.cupsPageSize[1] = l;
+ if (rotate == 90 || rotate == 270)
+ {
+ doc->header.cupsImagingBBox[0] =
+ doc->header.cupsPageSize[0] - inputPageBox.bottom();
+ doc->header.cupsImagingBBox[1] = inputPageBox.right();
+ doc->header.cupsImagingBBox[2] =
+ doc->header.cupsPageSize[0] - inputPageBox.top();
+ doc->header.cupsImagingBBox[3] = inputPageBox.left();
+ }
else
- doc->header.PageSize[1] = (unsigned)l;
+ {
+ doc->header.cupsImagingBBox[0] = inputPageBox.left();
+ doc->header.cupsImagingBBox[1] =
+ doc->header.cupsPageSize[1] - inputPageBox.bottom();
+ doc->header.cupsImagingBBox[2] = inputPageBox.right();
+ doc->header.cupsImagingBBox[3] =
+ doc->header.cupsPageSize[1] - inputPageBox.top();
+ }
+ for (i = 0; i < 2; i ++)
+ doc->header.PageSize[i] = (unsigned)(doc->header.cupsPageSize[i]);
+ for (i = 0; i < 4; i ++)
+ doc->header.ImagingBoundingBox[i] =
+ (unsigned)(doc->header.cupsImagingBBox[i]);
memset(paperdimensions, 0, sizeof(paperdimensions));
memset(margins, 0, sizeof(margins));
- if (doc->ppd) {
- ppdRasterMatchPPDSize(&(doc->header), doc->ppd, margins, paperdimensions, &imageable_area_fit, NULL);
+ if (data != NULL && (data->printer_attrs) != NULL)
+ {
+ i = cfGetPageDimensions(data->printer_attrs, data->job_attrs,
+ data->num_options, data->options,
+ &(doc->header), 0,
+ &(paperdimensions[0]), &(paperdimensions[1]),
+ &(margins[0]), &(margins[1]),
+ &(margins[2]), &(margins[3]), NULL, NULL);
+ // Overspray borderless page size: If the dimensions of the page
+ // size are up to 10% larger than the ones of the input page, zoom
+ // the image by rendering with an appropriately larger fake
+ // resolution.
+ if (i == 1 && // User-requested page size or size of the input
+ // page (if user did not request a page size) was
+ // fitting one of the printer
+ margins[0] == 0 && margins[1] == 0 &&
+ margins[2] == 0 && margins[3] == 0 && // Borderless only
+ paperdimensions[0] > (int)(doc->header.cupsPageSize[0]) &&
+ paperdimensions[0] <= (int)(doc->header.cupsPageSize[0] * 1.10) &&
+ paperdimensions[1] > (int)(doc->header.cupsPageSize[1]) &&
+ paperdimensions[1] <= (int)(doc->header.cupsPageSize[1] * 1.10))
+ {
+ float factor0, factor1;
+ factor0 = paperdimensions[0] / doc->header.cupsPageSize[0];
+ factor1 = paperdimensions[1] / doc->header.cupsPageSize[1];
+ overspray_factor = (factor0 > factor1 ? factor0 : factor1);
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "cfFilterPDFToRaster: Zoom factor for borderless printing with overspray: %f",
+ overspray_factor);
+ }
if (doc->pwgraster == 1)
memset(margins, 0, sizeof(margins));
- } else if(data!=NULL && (data->printer_attrs)!=NULL) {
- cfRasterMatchIPPSize(&(doc->header), data, margins, paperdimensions, &imageable_area_fit, NULL);
- if(doc->pwgraster==1){
- memset(margins, 0, sizeof(margins));
- }
}
- else {
+ else
+ {
for (i = 0; i < 2; i ++)
paperdimensions[i] = doc->header.PageSize[i];
if (doc->header.cupsImagingBBox[3] > 0.0) {
if (doc->header.cupsColorOrder == CUPS_ORDER_BANDED) {
doc->header.cupsBytesPerLine *= doc->header.cupsNumColors;
}
+
+ if (log) log(ld,CF_LOGLEVEL_DEBUG,
+ "cfFilterPDFToRaster: Page %d: Dimensions: %fx%f; Bounding box: %f %f %f %f",
+ pageNo,
+ doc->header.cupsPageSize[0], doc->header.cupsPageSize[1],
+ doc->header.cupsImagingBBox[0],
+ doc->header.cupsImagingBBox[1],
+ doc->header.cupsImagingBBox[2],
+ doc->header.cupsImagingBBox[3]);
+ if (log) log(ld,CF_LOGLEVEL_DEBUG,
+ "cfFilterPDFToRaster: Page %d: Pixel dimensions: %dx%d; Bitmap offsets: %d %d",
+ pageNo, doc->header.cupsWidth, doc->header.cupsHeight,
+ doc->bitmapoffset[0], doc->bitmapoffset[1]);
+
if (!cupsRasterWriteHeader2(raster,&(doc->header))) {
if (log) log(ld,CF_LOGLEVEL_ERROR,
"cfFilterPDFToRaster: Cannot write page %d header", pageNo);
}
/* write page image */
- write_page_image(raster,doc,pageNo, convert, iscanceled, icd);
+ write_page_image(raster,doc,pageNo, convert, overspray_factor, iscanceled, icd);
return (0);
}
int outputfd, /* I - File descriptor output stream */
int inputseekable, /* I - Is input stream seekable? (unused)*/
cf_filter_data_t *data, /* I - Job and printer data */
- void *parameters) /* I - Filter-specific parameters */
+ void *parameters) /* I - Filter-specific parameters(unused)*/
{
+ const char *val;
cf_filter_out_format_t outformat;
pdftoraster_doc_t doc;
int i;
int ret = 0;
(void)inputseekable;
+ (void)parameters;
+
cmsSetLogErrorHandler(lcms_error_handler);
+ val = data->final_content_type;
+ if (val)
+ {
+ if (strcasestr(val, "pwg"))
+ outformat = CF_FILTER_OUT_FORMAT_PWG_RASTER;
+ else if (strcasestr(val, "urf"))
+ outformat = CF_FILTER_OUT_FORMAT_APPLE_RASTER;
+ else if (strcasestr(val, "pclm"))
+ outformat = CF_FILTER_OUT_FORMAT_PCLM;
+ else
+ outformat = CF_FILTER_OUT_FORMAT_CUPS_RASTER;
+ }
+ else
+ outformat = CF_FILTER_OUT_FORMAT_CUPS_RASTER;
+
/* Note: With the CF_FILTER_OUT_FORMAT_PCLM selection the output is
actually CUPS Raster but color spaces and depth are always
assumed to be 8-bit sRGB or sGray, the only color spaces in
PCLm. This mode is for further processing with rastertopclm. */
- if (parameters) {
- outformat = *(cf_filter_out_format_t *)parameters;
- if (outformat != CF_FILTER_OUT_FORMAT_CUPS_RASTER &&
- outformat != CF_FILTER_OUT_FORMAT_PWG_RASTER &&
- outformat != CF_FILTER_OUT_FORMAT_APPLE_RASTER &&
- outformat != CF_FILTER_OUT_FORMAT_PCLM)
- outformat = CF_FILTER_OUT_FORMAT_CUPS_RASTER;
- } else
- outformat = CF_FILTER_OUT_FORMAT_CUPS_RASTER;
-
if (log) log(ld, CF_LOGLEVEL_DEBUG,
"cfFilterPDFToRaster: Final output format: %s",
(outformat == CF_FILTER_OUT_FORMAT_CUPS_RASTER ? "CUPS Raster" :
}
} else
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPDFToRaster: Input is empty outputting empty file.");
+ "cfFilterPDFToRaster: Input is empty, outputting empty file.");
out:
if (raster)
+++ /dev/null
-/*
- * IPP Everywhere/Apple Raster/IPP legacy PPD generator header file
- *
- * Copyright 2016 by Till Kamppeter.
- *
- * The PPD generator is based on the PPD generator for the CUPS
- * "lpadmin -m everywhere" functionality in the cups/ppd-cache.c
- * file. The copyright of this file is:
- *
- * Copyright 2010-2016 by Apple Inc.
- *
- * These coded instructions, statements, and computer programs are the
- * property of Apple Inc. and are protected by Federal copyright
- * law. Distribution and use rights are outlined in the file "COPYING"
- * which should have been included with this file.
- */
-
-#ifndef _CUPS_FILTERS_PPDGENERATOR_H_
-# define _CUPS_FILTERS_PPDGENERATOR_H_
-
-# ifdef __cplusplus
-extern "C" {
-# endif /* __cplusplus */
-
-/*
- * Include necessary headers...
- */
-
-# include <stdio.h>
-# include <stdlib.h>
-# include <time.h>
-# include <math.h>
-
-# if defined(WIN32) || defined(__EMX__)
-# include <io.h>
-# else
-# include <unistd.h>
-# include <fcntl.h>
-# endif /* WIN32 || __EMX__ */
-
-# include <cups/cups.h>
-# include <cups/raster.h>
-
-#include <config.h>
-#include <cups/cups.h>
-#if (CUPS_VERSION_MAJOR > 1) || (CUPS_VERSION_MINOR > 5)
-#define HAVE_CUPS_1_6 1
-#endif
-
-/*
- * Prototypes...
- */
-
-#ifdef HAVE_CUPS_1_6
-
-/* Data structure for resolution (X x Y dpi) */
-typedef struct cf_res_s {
- int x, y;
-} cf_res_t;
-
-char *cfCreatePPDFromIPP(char *buffer, size_t bufsize,
- ipp_t *response, const char *make_model,
- const char *pdl, int color, int duplex,
- char *status_msg, size_t status_msg_size);
-char *cfCreatePPDFromIPP2(char *buffer, size_t bufsize,
- ipp_t *response, const char *make_model,
- const char *pdl, int color, int duplex,
- cups_array_t* conflicts,
- cups_array_t *sizes,char* default_pagesize,
- const char *default_cluster_color,
- char *status_msg, size_t status_msg_size);
-char *cfStrFormatd(char *buf, char *bufend, double number,
- struct lconv *loc);
-int cfCompareResolutions(void *resolution_a, void *resolution_b,
- void *user_data);
-void *cfCopyResolution(void *resolution, void *user_data);
-void cfFreeResolution(void *resolution, void *user_data);
-cf_res_t *cfNewResolution(int x, int y);
-cups_array_t *cfNewResolutionArray();
-cf_res_t *cfIPPResToResolution(ipp_attribute_t *attr, int index);
-cups_array_t *cfIPPAttrToResolutionArray(ipp_attribute_t *attr);
-int cfJoinResolutionArrays(cups_array_t **current,
- cups_array_t **new_arr,
- cf_res_t **current_default,
- cf_res_t **new_default);
-cups_array_t *cfGenerateSizes(ipp_t *response,
- ipp_attribute_t **defattr,
- int *min_length,
- int* min_width,
- int* max_length,
- int* max_width,
- int* bottom,
- int* left,
- int* right,
- int* top,
- char* ppdname);
-#endif /* HAVE_CUPS_1_6 */
-
-# ifdef __cplusplus
-}
-# endif /* __cplusplus */
-
-#endif /* !_CUPS_FILTERS_PPDGENERATOR_H_ */
#include "image.h"
#include "bitmap.h"
#include "filter.h"
+#include "ipp.h"
#include <config.h>
#include <cups/cups.h>
#if (CUPS_VERSION_MAJOR > 1) || (CUPS_VERSION_MINOR > 6)
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
-#include <ppd/ppd.h>
#include <stdarg.h>
#include <cups/raster.h>
#include <cupsfilters/image.h>
typedef struct pwgtoraster_doc_s
{ /**** Document information ****/
+ cf_filter_data_t *data;
bool page_size_requested;
int bi_level;
bool allocLineBuf;
unsigned int bitspercolor;
unsigned int outputNumColors;
unsigned int bitmapoffset[2];
- ppd_file_t *ppd;
cups_page_header2_t inheader;
cups_page_header2_t outheader;
- cf_logfunc_t logfunc; /* Logging function, NULL for no
- logging */
- void *logdata; /* User data for logging function, can
- be NULL */
cups_file_t *inputfp; /* Temporary file, if any */
FILE *outputfp; /* Temporary file, if any */
/* margin swapping */
}
#endif
-static void handle_requires_page_region(pwgtoraster_doc_t*doc) {
- ppd_choice_t *mf;
- ppd_choice_t *is;
- ppd_attr_t *rregions = NULL;
- ppd_size_t *size;
-
- if ((size = ppdPageSize(doc->ppd,NULL)) == NULL) return;
- mf = ppdFindMarkedChoice(doc->ppd,"ManualFeed");
- if ((is = ppdFindMarkedChoice(doc->ppd,"InputSlot")) != NULL) {
- rregions = ppdFindAttr(doc->ppd,"RequiresPageRegion",is->choice);
- }
- if (rregions == NULL) {
- rregions = ppdFindAttr(doc->ppd,"RequiresPageRegion","All");
- }
- if (!strcasecmp(size->name,"Custom") || (!mf && !is) ||
- (mf && !strcasecmp(mf->choice,"False") &&
- (!is || (is->code && !is->code[0]))) ||
- (!rregions && doc->ppd->num_filters > 0)) {
- ppdMarkOption(doc->ppd,"PageSize",size->name);
- } else if (rregions && rregions->value
- && !strcasecmp(rregions->value,"True")) {
- ppdMarkOption(doc->ppd,"PageRegion",size->name);
- } else {
- ppd_choice_t *page;
-
- if ((page = ppdFindMarkedChoice(doc->ppd,"PageSize")) != NULL) {
- page->marked = 0;
- cupsArrayRemove(doc->ppd->marked,page);
- }
- if ((page = ppdFindMarkedChoice(doc->ppd,"PageRegion")) != NULL) {
- page->marked = 0;
- cupsArrayRemove(doc->ppd->marked, page);
- }
- }
-}
-
-static int parse_opts(cf_filter_data_t *data,
- cf_filter_out_format_t outformat,
- pwgtoraster_doc_t *doc)
+static int parse_opts(cf_filter_out_format_t outformat,
+ pwgtoraster_doc_t *doc)
{
int num_options = 0;
cups_option_t *options = NULL;
char *profile = NULL;
- ppd_attr_t *attr;
const char *val;
+ cf_filter_data_t *data = doc->data;
cf_logfunc_t log = data->logfunc;
void *ld = data ->logdata;
cups_cspace_t cspace = (cups_cspace_t)(-1);
num_options = cfJoinJobOptionsAndAttrs(data, num_options, &options);
- doc->ppd = data->ppd;
-
// Did the user explicitly request a certain page size? If not, overtake
// the page size(s) from the input pages
doc->page_size_requested =
outformat == CF_FILTER_OUT_FORMAT_PCLM ?
CF_FILTER_OUT_FORMAT_CUPS_RASTER : outformat, 0, &cspace);
- if (doc->ppd) {
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPWGToRaster: Using PPD file: %s", doc->ppd->nickname);
- ppdMarkOptions(doc->ppd,num_options,options);
- handle_requires_page_region(doc);
- attr = ppdFindAttr(doc->ppd,"pwgtorasterRenderingIntent",NULL);
- if (attr != NULL && attr->value != NULL) {
- if (strcasecmp(attr->value,"PERCEPTUAL") == 0) {
- doc->color_profile.renderingIntent = INTENT_PERCEPTUAL;
- } else if (strcasecmp(attr->value,"RELATIVE_COLORIMETRIC") == 0) {
- doc->color_profile.renderingIntent = INTENT_RELATIVE_COLORIMETRIC;
- } else if (strcasecmp(attr->value,"SATURATION") == 0) {
- doc->color_profile.renderingIntent = INTENT_SATURATION;
- } else if (strcasecmp(attr->value,"ABSOLUTE_COLORIMETRIC") == 0) {
- doc->color_profile.renderingIntent = INTENT_ABSOLUTE_COLORIMETRIC;
- }
- }
- if (doc->outheader.Duplex) {
- /* analyze options relevant to Duplex */
- const char *backside = "";
- /* APDuplexRequiresFlippedMargin */
- enum {
- FM_NO, FM_FALSE, FM_TRUE
- } flippedMargin = FM_NO;
-
- attr = ppdFindAttr(doc->ppd,"cupsBackSide",NULL);
- if (attr != NULL && attr->value != NULL) {
- doc->ppd->flip_duplex = 0;
- backside = attr->value;
- } else if (doc->ppd->flip_duplex) {
- backside = "Rotated"; /* compatible with Max OS and GS 8.71 */
- }
+ if (doc->outheader.Duplex)
+ {
+ int backside;
+ /* analyze options relevant to Duplex */
+ /* APDuplexRequiresFlippedMargin */
+ enum {
+ FM_NO,
+ FM_FALSE,
+ FM_TRUE
+ } flippedMargin;
+
+ backside = cfGetBackSideOrientation(data);
+
+ if (backside >= 0)
+ {
+ flippedMargin = (backside & 16 ? FM_TRUE :
+ (backside & 8 ? FM_FALSE :
+ FM_NO));
+ backside &= 7;
- attr = ppdFindAttr(doc->ppd,"APDuplexRequiresFlippedMargin",NULL);
- if (attr != NULL && attr->value != NULL) {
- if (strcasecmp(attr->value,"true") == 0) {
- flippedMargin = FM_TRUE;
- } else {
- flippedMargin = FM_FALSE;
- }
- }
- if (strcasecmp(backside,"ManualTumble") == 0 && doc->outheader.Tumble) {
+ if (backside == CF_BACKSIDE_MANUAL_TUMBLE && doc->outheader.Tumble)
+ {
doc->swap_margin_x = doc->swap_margin_y = true;
- if (flippedMargin == FM_TRUE) {
+ if (flippedMargin == FM_TRUE)
doc->swap_margin_y = false;
- }
- } else if (strcasecmp(backside,"Rotated") == 0 && !doc->outheader.Tumble) {
+ }
+ else if (backside==CF_BACKSIDE_ROTATED && !doc->outheader.Tumble)
+ {
doc->swap_margin_x = doc->swap_margin_y = true;
- if (flippedMargin == FM_TRUE) {
+ if (flippedMargin == FM_TRUE)
doc->swap_margin_y = false;
- }
- } else if (strcasecmp(backside,"Flipped") == 0) {
- if (doc->outheader.Tumble) {
+ }
+ else if (backside==CF_BACKSIDE_FLIPPED)
+ {
+ if (doc->outheader.Tumble)
doc->swap_margin_x = doc->swap_margin_y = true;
- }
- if (flippedMargin == FM_FALSE) {
+ if (flippedMargin == FM_FALSE)
doc->swap_margin_y = !doc->swap_margin_y;
- }
}
}
+ }
- /* support the CUPS "cm-calibration" option */
- doc->color_profile.cm_calibrate = cfCmGetCupsColorCalibrateMode(data, options, num_options);
+ /* support the CUPS "cm-calibration" option */
+ doc->color_profile.cm_calibrate = cfCmGetCupsColorCalibrateMode(data);
- if (doc->color_profile.cm_calibrate == CF_CM_CALIBRATION_ENABLED)
- doc->color_profile.cm_disabled = 1;
- else
- doc->color_profile.cm_disabled = cfCmIsPrinterCmDisabled(data);
+ if (doc->color_profile.cm_calibrate == CF_CM_CALIBRATION_ENABLED)
+ doc->color_profile.cm_disabled = 1;
+ else
+ doc->color_profile.cm_disabled = cfCmIsPrinterCmDisabled(data);
- if (!doc->color_profile.cm_disabled)
- cfCmGetPrinterIccProfile(data, &profile, doc->ppd);
+ if (!doc->color_profile.cm_disabled)
+ cfCmGetPrinterIccProfile
+ (data,
+ cfRasterColorSpaceString(doc->outheader.cupsColorSpace),
+ doc->outheader.MediaType,
+ doc->outheader.HWResolution[0], doc->outheader.HWResolution[1],
+ &profile);
- if (profile != NULL) {
- doc->color_profile.colorProfile = cmsOpenProfileFromFile(profile,"r");
- free(profile);
- }
- } else {
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPWGToRaster: No PPD file is specified.");
- if (strcasecmp(doc->outheader.cupsRenderingIntent, "Perceptual") == 0) {
- doc->color_profile.renderingIntent = INTENT_PERCEPTUAL;
- } else if (strcasecmp(doc->outheader.cupsRenderingIntent, "Relative") == 0) {
- doc->color_profile.renderingIntent = INTENT_RELATIVE_COLORIMETRIC;
- } else if (strcasecmp(doc->outheader.cupsRenderingIntent, "Saturation") == 0) {
- doc->color_profile.renderingIntent = INTENT_SATURATION;
- } else if (strcasecmp(doc->outheader.cupsRenderingIntent, "Absolute") == 0) {
- doc->color_profile.renderingIntent = INTENT_ABSOLUTE_COLORIMETRIC;
- }
+ if (profile != NULL)
+ {
+ doc->color_profile.colorProfile = cmsOpenProfileFromFile(profile,"r");
+ free(profile);
+ }
+
+ doc->outheader.cupsRenderingIntent[0] = '\0';
+ cfGetPrintRenderIntent(data, doc->outheader.cupsRenderingIntent,
+ sizeof(doc->outheader.cupsRenderingIntent));
+ if (strcasecmp(doc->outheader.cupsRenderingIntent, "Perceptual") == 0) {
+ doc->color_profile.renderingIntent = INTENT_PERCEPTUAL;
+ } else if (strcasecmp(doc->outheader.cupsRenderingIntent, "Relative") == 0) {
+ doc->color_profile.renderingIntent = INTENT_RELATIVE_COLORIMETRIC;
+ } else if (strcasecmp(doc->outheader.cupsRenderingIntent, "Saturation") == 0) {
+ doc->color_profile.renderingIntent = INTENT_SATURATION;
+ } else if (strcasecmp(doc->outheader.cupsRenderingIntent, "Absolute") == 0) {
+ doc->color_profile.renderingIntent = INTENT_ABSOLUTE_COLORIMETRIC;
}
+
if ((val = cupsGetOption("print-color-mode", num_options, options)) != NULL
&& !strncasecmp(val, "bi-level", 8))
doc->bi_level = 1;
return dst;
}
-/* Handle special cases which appear in Gutenprint's PPDs */
+/* Handle special cases which appear in the Gutenprint driver */
static bool select_special_case(pwgtoraster_doc_t* doc, conversion_function_t* convert)
{
int i;
/* select convertLine function */
static int select_convert_func(cups_raster_t *raster,
- pwgtoraster_doc_t* doc,
- conversion_function_t *convert,
- cf_logfunc_t log,
- void* ld)
+ pwgtoraster_doc_t* doc,
+ conversion_function_t *convert)
{
+ cf_logfunc_t log = doc->data->logfunc;
+ void* ld = doc->data->logdata;
+
doc->bitspercolor = doc->outheader.cupsBitsPerColor;
if ((doc->color_profile.colorProfile == NULL || doc->color_profile.outputColorProfile == doc->color_profile.colorProfile)
}
static bool out_page(pwgtoraster_doc_t *doc,
- int pageNo,
- cups_raster_t *inras,
- cups_raster_t *outras,
- conversion_function_t *convert,
- cf_logfunc_t log,
- void *ld,
- cf_filter_iscanceledfunc_t iscanceled,
- void *icd)
+ int pageNo,
+ cups_raster_t *inras,
+ cups_raster_t *outras,
+ conversion_function_t *convert)
{
int i, j;
- double paperdimensions[2], /* Physical size of the paper */
+ cf_filter_data_t *data = doc->data;
+ float paperdimensions[2], /* Physical size of the paper */
margins[4]; /* Physical margins of print */
- double swap;
+ float swap;
int imageable_area_fit = 0;
- int landscape_fit = 0;
int overspray_duplicate_after_pixels = INT_MAX;
int next_overspray_duplicate = 0;
int next_line_read = 0;
unsigned char *pagebuf = NULL;
unsigned int res_down_factor[2];
unsigned int res_up_factor[2];
-
+ cf_logfunc_t log = data->logfunc;
+ void *ld = data->logdata;
+ cf_filter_iscanceledfunc_t iscanceled = data->iscanceledfunc;
+ void *icd = data->iscanceleddata;
if (iscanceled && iscanceled(icd))
{
return (false);
}
- if (doc->inheader.ImagingBoundingBox[0] ||
- doc->inheader.ImagingBoundingBox[1] ||
- doc->inheader.ImagingBoundingBox[2] ||
- doc->inheader.ImagingBoundingBox[3])
- {
- // Only CUPS Raster (not supported as input format by this filter
- // function) defines margins and so an ImagingBoundingBox, for PWG
- // Raster and Apple Raster (the input formats supported by this
- // filter function) these values are all zero. With at least one not
- // zero we consider the input not supported.
- log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterPWGToRaster: Input page %d is not PWG or Apple Raster", pageNo);
- return (false);
- }
-
if (log) {
log(ld, CF_LOGLEVEL_DEBUG,
"cfFilterPWGToRaster: Input page %d", pageNo);
memset(paperdimensions, 0, sizeof(paperdimensions));
memset(margins, 0, sizeof(margins));
- if (doc->ppd)
+ if (data->printer_attrs)
{
- ppdRasterMatchPPDSize(&(doc->outheader), doc->ppd, margins,
- paperdimensions, &imageable_area_fit, &landscape_fit);
+ /* Find dimensions/margins of requested page size */
+ if (cfGetPageDimensions(data->printer_attrs, data->job_attrs,
+ data->num_options, data->options,
+ &(doc->outheader), 0,
+ &(paperdimensions[0]), &(paperdimensions[1]),
+ &(margins[0]), &(margins[1]),
+ &(margins[2]), &(margins[3]), NULL, NULL) == 0)
+ {
+ /* Find dimensions/margins for input page size */
+ cfGetPageDimensions(data->printer_attrs, NULL, 0, NULL,
+ &(doc->inheader), 0,
+ &(paperdimensions[0]), &(paperdimensions[1]),
+ &(margins[0]), &(margins[1]),
+ &(margins[2]), &(margins[3]), NULL, NULL);
+ }
if (doc->outheader.ImagingBoundingBox[3] == 0)
for (i = 0; i < 4; i ++)
margins[i] = 0.0;
// Pre-conversion of resolution and color space
//
+ // This is needed if we work with a driver (especially Gutenprint)
+ // handling very high resolutions due to the high resolution (high
+ // ink nozzle density of printer) used for dithering but do not want
+ // to overload clients be requiring them sending high-resolution job
+ // data. So we can tell the client to send a lower resolution while
+ // we let the driver use a higher resolution. Also color spaces
+ // clients can produce are usually more limited than what drivers
+ // work with.
+ //
+ // We also need this feature for retro-fitting CUPS Raster drivers
+ // which have the driver's/the printers's capabilities defined in
+ // PPD files (handled by ppdFilterCUPSWrapper() in libppd):
+ //
// The resolution and color space/depth/order for the CUPS Raster
// data to be fed into the filter is not simply defined by options
// and choices with intuitive names, but by the PostScript code
// Input line buffer (with space for raising horizontal resolution
// and overspray stretch if needed)
//
- // Note that the input lines can get stretched when the PPD defines
+ // Note that the input lines can get stretched when the driver defines
// paper dimensions larger than the physical paper size for
// overspraying on borderless printouts. Therefore we allocate the
// maximum of the input line size (multiplied by a resolution
// Overspray stretch of the input image If the output page
// dimensions are larger than the input page dimensions we have most
- // probably a page size from the PPD where the page dimensions are
+ // probably a page size from the driver where the page dimensions are
// defined larger than the physical paper to do an overspray when
// printing borderless, to avoid narrow white margins on one side if
// the paper is not exactly aligned in the printer. The HPLIP driver
int outputfd, /* I - File descriptor output stream */
int inputseekable, /* I - Is input stream seekable? (unused) */
cf_filter_data_t *data,/* I - Job and printer data */
- void *parameters) /* I - Filter-specific parameters */
+ void *parameters) /* I - Filter-specific parameters (unused)*/
{
cf_filter_out_format_t outformat;
pwgtoraster_doc_t doc;
int i;
+ const char *val;
cups_raster_t *inras = NULL,
*outras = NULL;
cf_logfunc_t log = data->logfunc;
(void)inputseekable;
+ (void)parameters;
- if (parameters) {
- outformat = *(cf_filter_out_format_t *)parameters;
- if (outformat != CF_FILTER_OUT_FORMAT_CUPS_RASTER &&
- outformat != CF_FILTER_OUT_FORMAT_PWG_RASTER &&
- outformat != CF_FILTER_OUT_FORMAT_APPLE_RASTER &&
- outformat != CF_FILTER_OUT_FORMAT_PCLM)
+ val = data->final_content_type;
+ if (val)
+ {
+ if (strcasestr(val, "pwg"))
+ outformat = CF_FILTER_OUT_FORMAT_PWG_RASTER;
+ else if (strcasestr(val, "urf"))
+ outformat = CF_FILTER_OUT_FORMAT_APPLE_RASTER;
+ else if (strcasestr(val, "pclm"))
+ outformat = CF_FILTER_OUT_FORMAT_PCLM;
+ else
outformat = CF_FILTER_OUT_FORMAT_CUPS_RASTER;
- } else
+ }
+ else
outformat = CF_FILTER_OUT_FORMAT_CUPS_RASTER;
if (log) log(ld, CF_LOGLEVEL_DEBUG,
// Initialize data structure
memset(&doc, 0, sizeof(doc));
+ doc.data = data;
doc.color_profile.renderingIntent = INTENT_PERCEPTUAL;
// Parse the options
- if (parse_opts(data, outformat, &doc) == 1)
+ if (parse_opts(outformat, &doc) == 1)
return (1);
doc.outheader.NumCopies = data->copies;
*/
memset(&convert, 0, sizeof(conversion_function_t));
- if (select_convert_func(outras, &doc, &convert, log, ld) == 1)
+ if (select_convert_func(outras, &doc, &convert) == 1)
{
if (log) log(ld, CF_LOGLEVEL_ERROR,
"cfFilterPWGToRaster: Unable to select color conversion function.");
*/
i = 0;
- while (out_page(&doc, i + 1, inras, outras, &convert, log, ld, iscanceled,
- icd))
+ while (out_page(&doc, i + 1, inras, outras, &convert))
i ++;
if (i == 0)
if (log) log(ld, CF_LOGLEVEL_DEBUG,
/*
* Function to apply IPP options to a CUPS/PWG Raster header.
*
- * Copyright 2013 by Till Kamppeter.
+ * Copyright 2013-2022 by Till Kamppeter.
*
* Distribution and use rights are outlined in the file "COPYING"
* which should have been included with this file.
*
* Contents:
*
- * cfRasterParseIPPOptions() - Parse IPP options from the command line
- * and apply them to the CUPS Raster header.
*/
-#include <config.h>
-#include <cups/cups.h>
-#if (CUPS_VERSION_MAJOR > 1) || (CUPS_VERSION_MINOR > 6)
-#define HAVE_CUPS_1_7 1
-#endif
/*
* Include necessary headers.
*/
+#include <config.h>
+#include <cups/cups.h>
#include "raster.h"
#include "filter.h"
#include "driver.h"
#include "ipp.h"
#include <string.h>
#include <ctype.h>
-#include <cupsfilters/ppdgenerator.h>
-#ifdef HAVE_CUPS_1_7
+#include <cupsfilters/ipp.h>
#include <cups/pwg.h>
-#endif /* HAVE_CUPS_1_7 */
+
+/*
+ * Local functions
+ */
+
+int raster_base_header(cups_page_header2_t *h, cf_filter_data_t *data,
+ int pwg_raster);
/*
* '_strlcpy()' - Safely copy two strings.
}
+/*
+ * 'cfRasterColorSpaceString()' - Return the color space name for a
+ * cupsColorSpace value.
+ */
+
+const char *
+cfRasterColorSpaceString(cups_cspace_t cspace) /* I - cupsColorSpace value */
+{
+ static const char * const cups_color_spaces[] =
+ { /* Color spaces */
+ "W",
+ "RGB",
+ "RGBA",
+ "K",
+ "CMY",
+ "YMC",
+ "CMYK",
+ "YMCK",
+ "KCMY",
+ "KCMYcm",
+ "GMCK",
+ "GMCS",
+ "WHITE",
+ "GOLD",
+ "SILVER",
+ "CIEXYZ",
+ "CIELab",
+ "RGBW",
+ "SW",
+ "SRGB",
+ "ADOBERGB",
+ "21",
+ "22",
+ "23",
+ "24",
+ "25",
+ "26",
+ "27",
+ "28",
+ "29",
+ "30",
+ "31",
+ "ICC1",
+ "ICC2",
+ "ICC3",
+ "ICC4",
+ "ICC5",
+ "ICC6",
+ "ICC7",
+ "ICC8",
+ "ICC9",
+ "ICCA",
+ "ICCB",
+ "ICCC",
+ "ICCD",
+ "ICCE",
+ "ICCF",
+ "47",
+ "DEVICE1",
+ "DEVICE2",
+ "DEVICE3",
+ "DEVICE4",
+ "DEVICE5",
+ "DEVICE6",
+ "DEVICE7",
+ "DEVICE8",
+ "DEVICE9",
+ "DEVICEA",
+ "DEVICEB",
+ "DEVICEC",
+ "DEVICED",
+ "DEVICEE",
+ "DEVICEF"
+ };
+
+ if (cspace < CUPS_CSPACE_W || cspace > CUPS_CSPACE_DEVICEF)
+ return ("Unknown");
+ else
+ return (cups_color_spaces[cspace]);
+}
+
+
/*
* 'cfRasterMatchIPPSize()' - Match IPP page size to header page size.
*/
int
cfRasterMatchIPPSize(
cups_page_header2_t *header, /* I - Page header to match */
- cf_filter_data_t *data, /* I - printer-data file */
+ cf_filter_data_t *data, /* I - Filter data */
double margins[4], /* O - Margins of media in points */
double dimensions[2], /* O - Width and Length of media in points */
int *image_fit, /* O - Imageable Area Fit */
/* Requested PageSize */
printer_attrs = data->printer_attrs;
- printer_sizes = cfGenerateSizes(printer_attrs, &defattr, &min_length, &min_width,
- &max_length, &max_width,
- &bottom, &left, &right, &top, defsize);
if (!header)
{
- if(log) log(ld, CF_LOGLEVEL_ERROR, "Page header cannot be NULL!\n");
+ if(log) log(ld, CF_LOGLEVEL_ERROR, "Page header cannot be NULL!");
return (-1);
}
+
if (!printer_attrs)
{
- if(log) log(ld, CF_LOGLEVEL_ERROR, "Printer-attributes info not supplied!\n");
+ if(log) log(ld, CF_LOGLEVEL_ERROR, "Printer-attributes info not supplied!");
return (-1);
}
- strncpy(pageSizeRequested, header->cupsPageSizeName, 64); /* Prefer user-selected page size. */
+ cfGenerateSizes(printer_attrs, CF_GEN_SIZES_DEFAULT, &printer_sizes, &defattr,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ &min_width, &min_length,
+ &max_width, &max_length,
+ &left, &bottom, &right, &top, defsize, NULL);
+
+ strncpy(pageSizeRequested, header->cupsPageSizeName, 64);
+ /* Prefer user-selected page size. */
memset(dimensions, 0, sizeof(double)*2);
memset(margins, 0, sizeof(double)*4);
size_matched = NULL;
+ /* XXX FullBleed? FB? */
/* Find a page size without ".Borderless" suffix */
/* (if all are ".Borderless" we drop the suffix in the size's names) */
for (size = (cups_size_t *)cupsArrayFirst(printer_sizes); size;
if(fabs(header->PageSize[1] - temptop + tempbottom) / templength < 0.01 &&
fabs(header->PageSize[0] - tempright + templeft) / tempwidth < 0.01 &&
(size_matched==NULL || !strcasecmp(pageSizeRequested, ippsizename))){
- if(log)log(ld,CF_LOGLEVEL_DEBUG,"Imageable area fit\n");
+ if(log)log(ld,CF_LOGLEVEL_DEBUG,"Imageable area fit");
size_matched = size;
if (landscape) *landscape = 0;
if (image_fit) *image_fit = 1;
/*
* Standard size...
*/
- if(log)log(ld,CF_LOGLEVEL_DEBUG,"IPP matched size = %s\n", size_matched->media);
+ if(log)log(ld,CF_LOGLEVEL_DEBUG,"IPP matched size = %s", size_matched->media);
size = size_matched;
dimensions[0] = size->width * 72.0 / 2540.0;
dimensions[1] = size->length * 72.0 / 2540.0;
margins[0] = size->left * 72.0 / 2540.0;
margins[1] = size->bottom * 72.0 / 2540.0;
- margins[2] = (size->width - size->right) * 72.0 / 2540.0;
- margins[3] = (size->length - size->top) * 72.0 / 2540.0;
+ margins[2] = size->right * 72.0 / 2540.0;
+ margins[3] = size->top * 72.0 / 2540.0;
snprintf(header->cupsPageSizeName, sizeof(header->cupsPageSizeName),
"%.63s", size->media);
}
if(fabs(header->PageSize[0] - temptop + tempbottom) / templength < 0.01 &&
fabs(header->PageSize[1] - tempright + templeft) / tempwidth < 0.01 &&
(size_matched==NULL || !strcasecmp(pageSizeRequested, ippsizename))){
- if(log) log(ld, CF_LOGLEVEL_DEBUG, "Imageable area fit\n");
+ if(log) log(ld, CF_LOGLEVEL_DEBUG, "Imageable area fit");
size_matched = size;
if (landscape) *landscape = 1;
if (image_fit) *image_fit = 1;
}
}
- }
- if (size_matched)
- {
- /*
- * Standard size in landscape orientation...
- */
- size = size_matched;
- if(log) log(ld, CF_LOGLEVEL_DEBUG, "landscape size = %s\n", size->media);
- dimensions[0] = size->width * 72.0 / 2540.0;
- dimensions[1] = size->length * 72.0 / 2540.0;
- margins[0] = size->left * 72.0 / 2540.0;
- margins[1] = size->bottom * 72.0 / 2540.0;
- margins[2] = (size->width - size->right) * 72.0 / 2540.0;
- margins[3] = (size->length - size->top) * 72.0 / 2540.0;
- snprintf(header->cupsPageSizeName, sizeof(header->cupsPageSizeName),
- "%.63s", size->media);
- }
- else
- {
- /*
- * Custom size...
- */
- if(log) log(ld, CF_LOGLEVEL_DEBUG, "size = custom\n");
- for (i = 0; i < 2; i ++)
- dimensions[i] = header->PageSize[i];
- margins[0] = left * 72.0 / 2540.0;
- margins[1] = bottom * 72.0 / 2540.0;
- margins[2] = right * 72.0 / 2540.0;
- margins[3] = bottom * 72.0 / 2540.0;
- snprintf(header->cupsPageSizeName, 64, "Custom.%dx%d", header->PageSize[0], header->PageSize[1]);
+ if (size_matched)
+ {
+ /*
+ * Standard size in landscape orientation...
+ */
+ size = size_matched;
+ if(log) log(ld, CF_LOGLEVEL_DEBUG, "landscape size = %s", size->media);
+ dimensions[0] = size->width * 72.0 / 2540.0;
+ dimensions[1] = size->length * 72.0 / 2540.0;
+ margins[0] = size->left * 72.0 / 2540.0;
+ margins[1] = size->bottom * 72.0 / 2540.0;
+ margins[2] = size->right * 72.0 / 2540.0;
+ margins[3] = size->top * 72.0 / 2540.0;
+ snprintf(header->cupsPageSizeName, sizeof(header->cupsPageSizeName),
+ "%.63s", size->media);
+ }
+ else
+ {
+ /*
+ * Custom size...
+ */
+ if(log) log(ld, CF_LOGLEVEL_DEBUG, "size = custom");
+ for (i = 0; i < 2; i ++)
+ dimensions[i] = header->PageSize[i];
+ margins[0] = left * 72.0 / 2540.0;
+ margins[1] = bottom * 72.0 / 2540.0;
+ margins[2] = right * 72.0 / 2540.0;
+ margins[3] = top * 72.0 / 2540.0;
+ snprintf(header->cupsPageSizeName, 64, "Custom.%dx%d", header->PageSize[0], header->PageSize[1]);
+ }
}
return 0;
}
/*
- * 'cfGetBackSideAndHeaderDuplex()' -
- * This functions returns the cupsBackSide using
- * printer attributes.
- * meaning and reason for backside orientation:-
- * It only makes sense if printer supports duplex,
- * so, if printer reports that it supports duplex
- * printing via sides-supported IPP attribute, then
- * it also reports back-side orientation for each
- * PDL in PDL specific IPP attributes. Backside
- * orientation is specially needed for raster
- * PDLs as raster PDLs are specially made for
- * raster printers which do not have sufficient memory
- * to hold a full page bitmap(raster page).
- * So they cannot build the whole page in memory
- * before starting to print it. For one sided printing
- * it is easy to manage. The printer's mechanism pulls
- * the page in on its upper edge and starts to print,
- * from top to bottom, after that it ejects the page.
- * For double-sided printing it does the same for the
- * front side, but for the back side the mechanics of
- * the printer has to turn over the sheet, and now,
- * depending on how the sheet is turned over it happens
- * that the edge arriving in the printing mechanism is
- * the lower edge of the back side. And if the printer
- * simply prints then, the back side is the wrong way
- * around. The printer reports its need via back side
- * orientation in such a case, so that the client knows
- * to send the back side upside down for example.
- * In vector PDL, PDF and PostScript, always the full
- * page's raster image is completely generated in the
- * printer before the page is started, and therefore the
- * printer can start to take the pixels from the lower
- * edge of the raster image if needed, so back side
- * orientation is always "normal" for these PDLs.
- * And if a printer does not support duplex, back side
- * orientation is not needed.
+ * 'cfGetBackSideOrientation()' - This functions returns the back
+ * side orientation using printer
+ * attributes. Meaning and reason for
+ * backside orientation: It only
+ * makes sense if printer supports
+ * duplex, so, if printer reports that
+ * it supports duplex printing via
+ * sides-supported IPP attribute, then
+ * it also reports back-side
+ * orientation for each PDL in PDL
+ * specific IPP attributes. Backside
+ * orientation is specially needed for
+ * raster PDLs as raster PDLs are
+ * specially made for raster printers
+ * which do not have sufficient memory
+ * to hold a full page bitmap(raster
+ * page). So they cannot build the
+ * whole page in memory before
+ * starting to print it. For one sided
+ * printing it is easy to manage. The
+ * printer's mechanism pulls the page
+ * in on its upper edge and starts to
+ * print, from top to bottom, after
+ * that it ejects the page. For
+ * double-sided printing it does the
+ * same for the front side, but for
+ * the back side the mechanics of the
+ * printer has to turn over the sheet,
+ * and now, depending on how the sheet
+ * is turned over it happens that the
+ * edge arriving in the printing
+ * mechanism is the lower edge of the
+ * back side. And if the printer
+ * simply prints then, the back side
+ * is the wrong way around. The
+ * printer reports its need via back
+ * side orientation in such a case, so
+ * that the client knows to send the
+ * back side upside down for example.
+ * In vector PDL, PDF and PostScript,
+ * always the full page's raster image
+ * is completely generated in the
+ * printer before the page is started,
+ * and therefore the printer can start
+ * to take the pixels from the lower
+ * edge of the raster image if needed,
+ * so back side orientation is always
+ * "normal" for these PDLs. And if a
+ * printer does not support duplex,
+ * back side orientation is not
+ * needed.
*/
-int /* O - Backside obtained using printer attributes */
-cfGetBackSideAndHeaderDuplex(ipp_t *printer_attrs, /* I - printer attributes using filter data */
- cups_page_header2_t *header) /* O - header */
+int /* O - Backside orientation (bit 0-2)
+ Requires flipped margin?
+ Yes: bit 4 set; No: bit 3 set */
+cfGetBackSideOrientation(cf_filter_data_t *data) /* I - Filter data */
{
- ipp_attribute_t *ipp_attr; /* IPP attribute */
- int i, /* Looping variable */
- count;
- int backside = -1; /* backside obtained using printer attributes */
- if((ipp_attr = ippFindAttribute(printer_attrs, "sides-supported", IPP_TAG_ZERO))!=NULL){
- if(ippContainsString(ipp_attr, "two-sided-long-edge")){
- if(header) header->Duplex = CUPS_TRUE;
- if((ipp_attr = ippFindAttribute(printer_attrs, "urf-supported",
- IPP_TAG_ZERO))!=NULL){
- for(i = 0, count = ippGetCount(ipp_attr); i<count;i++){
- const char *dm = ippGetString(ipp_attr, i, NULL); /* DM value */
- if(!strcasecmp(dm, "DM1")){
- backside = CF_BACKSIDE_NORMAL;
- break;
- }
- if(!strcasecmp(dm, "DM2")){
- backside = CF_BACKSIDE_FLIPPED;
- break;
- }
- if(!strcasecmp(dm, "DM3")){
- backside = CF_BACKSIDE_ROTATED;
- break;
- }
- if(!strcasecmp(dm, "DM4")){
- backside = CF_BACKSIDE_MANUAL_TUMBLE;
- break;
- }
- }
- }
- if((ipp_attr = ippFindAttribute(printer_attrs, "pwg-raster-document-sheet-back",
- IPP_TAG_ZERO))!=NULL){
- const char *keyword;
- keyword = ippGetString(ipp_attr, 0, NULL);
- if (!strcmp(keyword, "flipped"))
- backside = CF_BACKSIDE_FLIPPED;
- else if (!strcmp(keyword, "manual-tumble"))
- backside = CF_BACKSIDE_MANUAL_TUMBLE;
- else if (!strcmp(keyword, "normal"))
- backside = CF_BACKSIDE_NORMAL;
- else
- backside = CF_BACKSIDE_ROTATED;
- }
+ ipp_t *printer_attrs = data->printer_attrs;
+ int num_options = data->num_options;
+ cups_option_t *options = data->options;
+ char *final_content_type = data->final_content_type;
+ ipp_attribute_t *ipp_attr = NULL; /* IPP attribute */
+ int i, /* Looping variable */
+ count;
+ const char *keyword;
+ int backside = -1; /* backside obtained using printer attributes */
+ // also check options
+ if ((ipp_attr = ippFindAttribute(printer_attrs, "sides-supported",
+ IPP_TAG_ZERO)) != NULL)
+ {
+ if (ippContainsString(ipp_attr, "two-sided-long-edge"))
+ {
+ if (final_content_type &&
+ strcasestr(final_content_type, "/urf") &&
+ (ipp_attr = ippFindAttribute(printer_attrs, "urf-supported",
+ IPP_TAG_ZERO)) != NULL)
+ {
+ for (i = 0, count = ippGetCount(ipp_attr); i < count; i ++)
+ {
+ const char *dm = ippGetString(ipp_attr, i, NULL); /* DM value */
+ if(!strcasecmp(dm, "DM1")){
+ backside = CF_BACKSIDE_NORMAL;
+ break;
+ }
+ if(!strcasecmp(dm, "DM2")){
+ backside = CF_BACKSIDE_FLIPPED;
+ break;
+ }
+ if(!strcasecmp(dm, "DM3")){
+ backside = CF_BACKSIDE_ROTATED;
+ break;
+ }
+ if(!strcasecmp(dm, "DM4")){
+ backside = CF_BACKSIDE_MANUAL_TUMBLE;
+ break;
+ }
}
+ }
+ else if ((final_content_type &&
+ strcasestr(final_content_type, "/vnd.pwg-raster") &&
+ (ipp_attr = ippFindAttribute(printer_attrs,
+ "pwg-raster-document-sheet-back",
+ IPP_TAG_ZERO)) != NULL) ||
+ (final_content_type &&
+ strcasestr(final_content_type, "/pclm") &&
+ (ipp_attr = ippFindAttribute(printer_attrs,
+ "pclm-raster-back-side",
+ IPP_TAG_ZERO)) != NULL) ||
+ ((ipp_attr = NULL) ||
+ (keyword = cupsGetOption("back-side-orientation",
+ num_options, options)) != NULL))
+ {
+ if (ipp_attr)
+ keyword = ippGetString(ipp_attr, 0, NULL);
+ if (!strcasecmp(keyword, "flipped"))
+ backside = CF_BACKSIDE_FLIPPED;
+ else if (!strncasecmp(keyword, "manual", 6))
+ backside = CF_BACKSIDE_MANUAL_TUMBLE;
+ else if (!strcasecmp(keyword, "normal"))
+ backside = CF_BACKSIDE_NORMAL;
+ else if (!strcasecmp(keyword, "rotated"))
+ backside = CF_BACKSIDE_ROTATED;
+ }
+
+ if (backside == -1)
+ backside = CF_BACKSIDE_NORMAL;
+ else if ((keyword = cupsGetOption("duplex-requires-flipped-margin",
+ num_options, options)) != NULL)
+ {
+ if (strcasecmp(keyword, "true") == 0)
+ backside |= 16;
+ else
+ backside |= 8;
+ }
}
-
- if(header && header->Duplex==1 && backside==-1) backside = CF_BACKSIDE_NORMAL;
- return backside;
-
+ }
+
+ return backside;
}
-int
-cfGetPrintRenderIntent(cf_filter_data_t *data,
- cups_page_header2_t *header)
+const char *
+cfGetPrintRenderIntent(cf_filter_data_t *data, char *ri, int ri_len)
{
const char *val;
int num_options = 0;
cups_option_t *options = NULL;
ipp_t *printer_attrs = data->printer_attrs;
ipp_attribute_t *ipp_attr;
- cf_logfunc_t log = data->logfunc;
+ cf_logfunc_t log = data->logfunc;
void *ld = data->logdata;
int i;
+
+
num_options = cfJoinJobOptionsAndAttrs(data, num_options, &options);
if ((val = cupsGetOption("print-rendering-intent", num_options,
(val = cupsGetOption("RenderingIntent", num_options,
options)) != NULL)
{
- if (!strcmp(val, "absolute"))
- snprintf(header->cupsRenderingIntent, sizeof(header->cupsRenderingIntent),
- "%s","Absolute");
- else if (!strcmp(val, "automatic"))
- snprintf(header->cupsRenderingIntent,sizeof(header->cupsRenderingIntent),
- "%s", "Automatic");
- else if (!strcmp(val, "perceptual"))
- snprintf(header->cupsRenderingIntent, sizeof(header->cupsRenderingIntent),
- "%s", "Perceptual");
- else if (!strcmp(val, "relative"))
- snprintf(header->cupsRenderingIntent, sizeof(header->cupsRenderingIntent),
- "%s", "Relative");
- else if (!strcmp(val, "relative-bpc"))
- snprintf(header->cupsRenderingIntent, sizeof(header->cupsRenderingIntent),
- "%s", "RelativeBpc");
- else if (!strcmp(val, "saturation"))
- snprintf(header->cupsRenderingIntent, sizeof(header->cupsRenderingIntent),
- "%s", "Saturation");
+ if (!strcasecmp(val, "absolute"))
+ snprintf(ri, ri_len, "%s", "Absolute");
+ else if (!strcasecmp(val, "auto") || !strcasecmp(val, "automatic"))
+ snprintf(ri, ri_len, "%s", "Automatic");
+ else if (!strcasecmp(val, "perceptual"))
+ snprintf(ri, ri_len, "%s", "Perceptual");
+ else if (!strcasecmp(val, "relative"))
+ snprintf(ri, ri_len, "%s", "Relative");
+ else if (!strcasecmp(val, "relative-bpc") ||
+ !strcasecmp(val, "relativebpc"))
+ snprintf(ri, ri_len, "%s", "RelativeBpc");
+ else if (!strcasecmp(val, "saturation"))
+ snprintf(ri, ri_len, "%s", "Saturation");
}
- else
+
+ if ((ipp_attr = ippFindAttribute(printer_attrs,
+ "print-rendering-intent-supported",
+ IPP_TAG_ZERO)) != NULL)
{
- header->cupsRenderingIntent[0] = '\0';
- }
- if((ipp_attr = ippFindAttribute(printer_attrs, "print-rendering-intent-supported",
- IPP_TAG_ZERO))!=NULL){
- int autoRender = 0;int count;
- if((count = ippGetCount(ipp_attr))>0){
- char temp[41] = "auto";
- if(header->cupsRenderingIntent[0]!='\0'){ /* User is willing to supply some option */
- for(i=0; i<count; i++){
- const char *temp2 = ippGetString(ipp_attr, i, NULL);
- if(!strcasecmp(temp2, "auto")) autoRender = 1;
- if(!strcasecmp(header->cupsRenderingIntent, temp2)){
- break;
- }
- }
- if(i==count){
- if(log) log(ld, CF_LOGLEVEL_DEBUG,
- "User specified print-rendering-intent not supported by printer,"
- "using default print rendering intent.");
- header->cupsRenderingIntent[0] = '\0';
- }
- }
- if(header->cupsRenderingIntent[0]=='\0'){ /* Either user has not supplied any option
- or user supplied value is not supported by printer */
- if((ipp_attr = ippFindAttribute(printer_attrs, "print-rendering-intent-default",
- IPP_TAG_ZERO))!=NULL){
- snprintf(temp,sizeof(temp),"%s",ippGetString(ipp_attr, 0, NULL));
- snprintf(header->cupsRenderingIntent, sizeof(header->cupsRenderingIntent),
- "%s",ippGetString(ipp_attr, 0, NULL));
- }
- else if(autoRender==1){
- snprintf(temp,sizeof(temp),"%s","auto");
- snprintf(header->cupsRenderingIntent, sizeof(header->cupsRenderingIntent),
- "%s","auto");
+ int autoRender = 0;
+ int count;
- }
- }
- }
+ if ((count = ippGetCount(ipp_attr)) > 0)
+ {
+ for (i = 0; i < count; i ++)
+ {
+ const char *temp = ippGetString(ipp_attr, i, NULL);
+ if (!strcasecmp(temp, "auto")) autoRender = 1;
+ if (ri[0] != '\0')
+ /* User has supplied a setting */
+ if (!strcasecmp(ri, temp))
+ break;
+ }
+ if (ri[0] != '\0' && i == count)
+ {
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "User specified print-rendering-intent not supported "
+ "by printer, using default print rendering intent.");
+ ri[0] = '\0';
+ }
+ if (ri[0] == '\0')
+ { /* Either user has not supplied any setting
+ or user supplied value is not supported by printer */
+ if ((ipp_attr = ippFindAttribute(printer_attrs,
+ "print-rendering-intent-default",
+ IPP_TAG_ZERO)) != NULL)
+ snprintf(ri, ri_len, "%s", ippGetString(ipp_attr, 0, NULL));
+ else if (autoRender == 1)
+ snprintf(ri, ri_len, "%s", "auto");
+ }
}
- return 0;
+ }
+
+ cupsFreeOptions(num_options, options);
+ return (ri);
}
/*
- * 'cfRasterPrepareHeader() - This function creates a CUPS/PWG
- * Raster header for Raster output based
- * on the printer and job properties
- * supplied to the calling filter
- * functions, printer properties via PPD
- * file or printer IPP attributes and job
- * properties via CUPS option list and
- * job IPP attributes. For PWG and Apple
- * Raster output the color space and
- * depth is auto-selected based on
- * available options listed in the
- * urf-supported and
- * pwg-raster-document-type-supported
- * printer IPP attributes (PPD generator
- * adds those also to the PPD) and the
- * settings of print-color-mode
- * ("ColorModel") and print-quality
- * ("cupsPrintQuality") job
- * attributes/options.
+ * 'cfRasterPrepareHeader() - This function creates a CUPS/PWG Raster
+ * header for Raster output based on the
+ * printer and job properties supplied to
+ * the calling filter functions, printer
+ * properties via printer IPP attributes
+ * and job properties via CUPS option list
+ * and job IPP attributesor optionally a
+ * sample header. For PWG and Apple Raster
+ * output the color space and depth is
+ * auto-selected based on available options
+ * listed in the urf-supported and
+ * pwg-raster-document-type-supported
+ * printer IPP attributes and the settings
+ * of print-color-mode ("ColorModel") and
+ * print-quality ("cupsPrintQuality") job
+ * attributes/options.
*/
int /* O - 0 on success,
found. */
{
int i;
- ppd_file_t *ppd;
ipp_t *printer_attrs, *job_attrs;
int num_options = 0;
cups_option_t *options = NULL;
pclm = 0;
int cupsrasterheader = 1;
const char *p;
- ppd_attr_t *ppd_attr;
ipp_attribute_t *attr;
- const char *cspaces_available, *color_mode, *quality;
+ const char *cspaces_available = NULL, *color_mode = NULL, *quality = NULL;
int hi_depth;
- ppd_choice_t *choice;
char valuebuffer[2048];
int res = 1;
int xres = -1; int yres = -1;
- double margins[4];
- double dimensions[2];
+ float margins[4];
+ float dimensions[2];
+ char size_name_buf[IPP_MAX_NAME + 1];
+
if (final_outformat == CF_FILTER_OUT_FORMAT_PWG_RASTER)
pwgraster = 1;
else
cupsraster = 1;
+ if (cupsraster)
+ {
+ pwgraster = 0;
+ p = cupsGetOption("media-class", num_options, options);
+ if (p == NULL)
+ p = cupsGetOption("MediaClass", num_options, options);
+ if (p != NULL)
+ {
+ if (strcasestr(p, "pwg")) {
+ pwgraster = 1;
+ cupsraster = 0;
+ if (log)
+ log(ld, CF_LOGLEVEL_DEBUG,
+ "PWG Raster output requested (via \"MediaClass\"/\"media-class\" option)");
+ } else
+ pwgraster = 0;
+ }
+ }
+
if (header_outformat == CF_FILTER_OUT_FORMAT_PWG_RASTER ||
header_outformat == CF_FILTER_OUT_FORMAT_APPLE_RASTER)
cupsrasterheader = 0;
job_attrs = data->job_attrs;
num_options = cfJoinJobOptionsAndAttrs(data, num_options, &options);
- ppd = data->ppd;
printer_attrs = data->printer_attrs;
job_attrs = data->job_attrs;
"pwg-raster-document-resolution-supported",
IPP_TAG_RESOLUTION)) != NULL)
{
- strncpy(valuebuffer, ippGetString(attr, 0, NULL),
- sizeof(valuebuffer) - 1);
+ ippAttributeString(attr, valuebuffer, sizeof(valuebuffer));
const char *p = valuebuffer;
xres = atoi(p);
if ((p = strchr(p, 'x')) != NULL)
"pclm-source-resolution-default",
IPP_TAG_RESOLUTION)) != NULL)
{
- strncpy(valuebuffer, ippGetString(attr, 0, NULL),
- sizeof(valuebuffer) - 1);
+ ippAttributeString(attr, valuebuffer, sizeof(valuebuffer));
const char *p = valuebuffer;
xres = atoi(p);
if ((p = strchr(p, 'x')) != NULL)
(pclm ? "PCLm" : "CUPS Raster")));
}
- if (ppd)
- {
- if (log)
- log(ld, CF_LOGLEVEL_DEBUG, "PPD file present");
- ppdRasterInterpretPPD(h, ppd, num_options, options, NULL);
- if ((ppd_attr = ppdFindAttr(ppd,"PWGRaster",0)) != 0 &&
- (!strcasecmp(ppd_attr->value, "true") ||
- !strcasecmp(ppd_attr->value, "on") ||
- !strcasecmp(ppd_attr->value, "yes"))) {
- pwgraster = 1;
- cupsraster = 0;
- appleraster = 0;
- pclm = 0;
- if (log)
- log(ld, CF_LOGLEVEL_DEBUG,
- "PWG Raster output requested (via \"PWGRaster\" PPD attribute)");
- }
-
- if (pwgraster || appleraster || pclm) {
- if ((pwgraster &&
- (ppd_attr = ppdFindAttr(ppd, "cupsPwgRasterDocumentTypeSupported",
- NULL)) != NULL) ||
- (appleraster &&
- (ppd_attr = ppdFindAttr(ppd, "cupsUrfSupported", NULL)) != NULL)) {
- cspaces_available = ppd_attr->value;
- if (cspaces_available && cspaces_available[0]) {
- /* PPD is from the PPD generator (cfCreatePPDFromIPP()) of
- cups-filters, so we auto-select color space and depth */
- if ((color_mode = cupsGetOption("print-color-mode", num_options,
- options)) == NULL) {
- choice = ppdFindMarkedChoice(ppd, "ColorModel");
- if (choice)
- color_mode = choice->choice;
- else
- color_mode = "auto";
- }
- if ((quality = cupsGetOption("print-quality", num_options,
- options)) == NULL) {
- choice = ppdFindMarkedChoice(ppd, "cupsPrintQuality");
- if (choice)
- quality = choice->choice;
- else
- quality = "Normal";
- }
- hi_depth = (!no_high_depth &&
- (!strcasecmp(quality, "High") || !strcmp(quality, "5"))) ?
- 1 : 0;
- if (log) {
- log(ld, CF_LOGLEVEL_DEBUG,
- "Color mode requested: %s; color depth requested: %s",
- color_mode, hi_depth ? "High" : "Standard");
- log(ld, CF_LOGLEVEL_DEBUG,
- "Determining best color space/depth ...");
- }
- res = cfRasterSetColorSpace(h, cspaces_available, color_mode,
- cspace, &hi_depth);
- }
- }
- else if (pclm)
- {
- /* Available color spaces are always SRGB 8 and SGray 8 */
- cspaces_available = "srgb_8,sgray_8";
- if ((color_mode = cupsGetOption("print-color-mode", num_options,
- options)) == NULL) {
- choice = ppdFindMarkedChoice(ppd, "ColorModel");
- if (choice)
- color_mode = choice->choice;
- else
- color_mode = "auto";
- }
- hi_depth = 0;
- if (log)
- log(ld, CF_LOGLEVEL_DEBUG,
- "For PCLm color mode is always SRGB/SGray 8-bit.");
- res = cfRasterSetColorSpace(h, cspaces_available, color_mode,
- cspace, &hi_depth);
- }
- }
-
- for (i = 0; i < 2; i ++)
- dimensions[i] = h->PageSize[i];
- if (cupsrasterheader) {
- margins[0] = h->cupsImagingBBox[0];
- margins[1] = h->cupsImagingBBox[1];
- margins[2] = dimensions[0] - h->cupsImagingBBox[2];
- margins[3] = dimensions[1] - h->cupsImagingBBox[3];
- } else
- memset(margins, 0, sizeof(margins));
- }
+ if (data->header)
+ *h = *(data->header); /* Copy sample header */
else
+ raster_base_header(h, data, 1 - cupsrasterheader);
+ if (cfGetPageDimensions(data->printer_attrs, data->job_attrs,
+ data->num_options, data->options, h, 0,
+ &(dimensions[0]), &(dimensions[1]),
+ &(margins[0]), &(margins[1]),
+ &(margins[2]), &(margins[3]), size_name_buf,
+ NULL) < 0)
{
- if (log)
- log(ld, CF_LOGLEVEL_DEBUG, "No PPD file present");
- if (cupsraster)
+ pwg_media_t *pwg_media;
+
+ for (i = 0; i < 2; i ++)
+ dimensions[i] = h->cupsPageSize[i];
+ margins[0] = h->cupsImagingBBox[0];
+ margins[1] = h->cupsImagingBBox[1];
+ margins[2] = dimensions[0] - h->cupsImagingBBox[2];
+ margins[3] = dimensions[1] - h->cupsImagingBBox[3];
+ pwg_media = pwgMediaForSize(dimensions[0] / 72 * 2540,
+ dimensions[1] / 72 * 2540);
+ if (pwg_media)
{
- pwgraster = 0;
- p = cupsGetOption("media-class", num_options, options);
- if (p == NULL)
- p = cupsGetOption("MediaClass", num_options, options);
- if (p != NULL)
- {
- if (strcasestr(p, "pwg")) {
- pwgraster = 1;
- cupsraster = 0;
- if (log)
- log(ld, CF_LOGLEVEL_DEBUG,
- "PWG Raster output requested (via \"MediaClass\"/\"media-class\" option)");
- } else
- pwgraster = 0;
- }
- }
- cfRasterParseIPPOptions(h, data, 1 - cupsrasterheader, 1);
- if (cfRasterMatchIPPSize(h, data, margins, dimensions, NULL, NULL) < 0) {
- for (i = 0; i < 2; i ++)
- dimensions[i] = h->PageSize[i];
- memset(margins, 0, sizeof(margins));
+ p = (pwg_media->ppd ? pwg_media->ppd :
+ (pwg_media->legacy ? pwg_media->legacy : pwg_media->pwg));
+ if (p)
+ _strlcpy(h->cupsPageSizeName, p, sizeof(h->cupsPageSizeName));
}
- if (!cupsrasterheader)
- memset(margins, 0, sizeof(margins));
-
- if (printer_attrs &&
- ((pwgraster &&
- (attr = ippFindAttribute(printer_attrs,
- "pwg-raster-document-type-supported",
- IPP_TAG_ZERO)) != NULL) ||
- (appleraster &&
- (attr = ippFindAttribute(printer_attrs,
- "urf-supported",
- IPP_TAG_ZERO)) != NULL))) {
- ippAttributeString(attr, valuebuffer, sizeof(valuebuffer));
- cspaces_available = valuebuffer;
- if ((color_mode = cupsGetOption("print-color-mode", num_options,
- options)) == NULL)
- color_mode = cfIPPAttrEnumValForPrinter(printer_attrs, job_attrs,
+ }
+ else if (size_name_buf[0])
+ _strlcpy(h->cupsPageSizeName, size_name_buf, sizeof(h->cupsPageSizeName));
+
+ if (!cupsrasterheader)
+ memset(margins, 0, sizeof(margins));
+
+ if (printer_attrs &&
+ ((pwgraster &&
+ (attr = ippFindAttribute(printer_attrs,
+ "pwg-raster-document-type-supported",
+ IPP_TAG_ZERO)) != NULL) ||
+ (appleraster &&
+ (attr = ippFindAttribute(printer_attrs,
+ "urf-supported",
+ IPP_TAG_ZERO)) != NULL))) {
+ ippAttributeString(attr, valuebuffer, sizeof(valuebuffer));
+ cspaces_available = valuebuffer;
+ if ((color_mode = cupsGetOption("print-color-mode", num_options,
+ options)) == NULL)
+ color_mode = cfIPPAttrEnumValForPrinter(printer_attrs, job_attrs,
"print-color-mode");
- if ((quality = cupsGetOption("print-quality", num_options,
- options)) == NULL)
- quality = cfIPPAttrEnumValForPrinter(printer_attrs, job_attrs,
+ if ((quality = cupsGetOption("print-quality", num_options,
+ options)) == NULL)
+ quality = cfIPPAttrEnumValForPrinter(printer_attrs, job_attrs,
"print-quality");
- hi_depth = (!no_high_depth &&
- (!strcasecmp(quality, "high") || !strcmp(quality, "5"))) ?
- 1 : 0;
- if (log) {
- log(ld, CF_LOGLEVEL_DEBUG,
- "Color mode requested: %s; color depth requested: %s",
- color_mode, hi_depth ? "High" : "Standard");
- log(ld, CF_LOGLEVEL_DEBUG,
- "Determining best color space/depth ...");
- }
- res = cfRasterSetColorSpace(h, cspaces_available, color_mode,
- cspace, &hi_depth);
+ hi_depth = (!no_high_depth && quality &&
+ (!strcasecmp(quality, "high") || !strcmp(quality, "5"))) ?
+ 1 : 0;
+ if (log) {
+ log(ld, CF_LOGLEVEL_DEBUG,
+ "Color mode requested: %s; color depth requested: %s",
+ color_mode, hi_depth ? "High" : "Standard");
+ log(ld, CF_LOGLEVEL_DEBUG,
+ "Determining best color space/depth ...");
}
- else if (pclm)
- {
- /* Available color spaces are always SRGB 8 and SGray 8 */
- cspaces_available = "srgb_8,sgray_8";
- if ((color_mode = cupsGetOption("print-color-mode", num_options,
- options)) == NULL)
- color_mode = cfIPPAttrEnumValForPrinter(printer_attrs, job_attrs,
+ res = cfRasterSetColorSpace(h, cspaces_available, color_mode,
+ cspace, &hi_depth);
+ }
+ else if (pclm)
+ {
+ /* Available color spaces are always SRGB 8 and SGray 8 */
+ cspaces_available = "srgb_8,sgray_8";
+ if ((color_mode = cupsGetOption("print-color-mode", num_options,
+ options)) == NULL)
+ color_mode = cfIPPAttrEnumValForPrinter(printer_attrs, job_attrs,
"print-color-mode");
- hi_depth = 0;
- if (log)
- log(ld, CF_LOGLEVEL_DEBUG,
- "For PCLm color mode is always SRGB/SGray 8-bit.");
- res = cfRasterSetColorSpace(h, cspaces_available, color_mode,
- cspace, &hi_depth);
- }
+ hi_depth = 0;
+ if (log)
+ log(ld, CF_LOGLEVEL_DEBUG,
+ "For PCLm color mode is always SRGB/SGray 8-bit.");
+ res = cfRasterSetColorSpace(h, cspaces_available, color_mode,
+ cspace, &hi_depth);
}
if (res != 1) {
}
if ((h->HWResolution[0] == 100) && (h->HWResolution[1] == 100)) {
- /* No "Resolution" option */
- if (ppd && (ppd_attr = ppdFindAttr(ppd, "DefaultResolution", 0)) != NULL) {
- /* "*DefaultResolution" keyword in the PPD */
- const char *p = ppd_attr->value;
- h->HWResolution[0] = atoi(p);
- if ((p = strchr(p, 'x')) != NULL)
- h->HWResolution[1] = atoi(p+1); /* Since p now points to a pointer such that *p = 'x',
- therefore using p+1, cause p+1 points to a numeric value */
- else
- h->HWResolution[1] = h->HWResolution[0];
- if (h->HWResolution[0] <= 0)
- h->HWResolution[0] = 300;
- if (h->HWResolution[1] <= 0)
- h->HWResolution[1] = h->HWResolution[0];
- } else {
- if(xres!=-1){
+ /* No resolution set in header */
+ if (xres != -1)
+ {
h->HWResolution[0] = xres;
h->HWResolution[1] = yres;
}
- else{
+ else
+ {
h->HWResolution[0] = 300;
h->HWResolution[1] = 300;
}
- }
h->cupsWidth = h->HWResolution[0] * h->PageSize[0] / 72;
h->cupsHeight = h->HWResolution[1] * h->PageSize[1] / 72;
}
only */
if (islower(available[0]) &&
(p = strstr(available, "black_1")) != NULL &&
- !isdigit(p + 7) &&
+ !isdigit(*(p + 7)) &&
(!strcmp(color_mode, "bi-level") ||
!strcmp(color_mode, "process-bi-level"))) {
/* Set parameters for bi-level, there is only one color space and color
}
-/*
- * 'cfRasterParseIPPOptions()' - Parse IPP options from the command line
- * and apply them to the CUPS Raster header.
- */
-
-int /* O - -1 on error, 0 on success */
-cfRasterParseIPPOptions(cups_page_header2_t *h, /* I - Raster header */
- cf_filter_data_t *data,
- int pwg_raster, /* I - 1 if PWG Raster */
- int set_defaults) /* I - If 1, set default
- values for all fields for
- which we did not get an
- option */
+int /* O - -1 on error, 0 on success */
+raster_base_header(cups_page_header2_t *h, /* O - Raster header */
+ cf_filter_data_t *data, /* I - Filter data */
+ int pwg_raster) /* I - 1 if PWG/Apple Raster */
{
-#ifdef HAVE_CUPS_1_7
int i; /* Looping var */
char *ptr, /* Pointer into string */
s[255]; /* Temporary string */
const char *val, /* Pointer into value */
*media; /* media option */
- char *page_size, /* PageSize option */
- *media_source, /* Media source */
+ char *media_source, /* Media source */
*media_type; /* Media type */
pwg_media_t *size_found; /* page size found for given name */
- float size; /* page size dimension */
- int num_options = 0; /* number of options */
- cups_option_t *options = NULL; /* Options */
- ppd_option_t *option;
+ int num_options = 0; /* Number of options */
+ cups_option_t *options = NULL; /* Options */
+ ipp_attribute_t *attr;
/*
/*
* Join the IPP attributes and the CUPS options in a single list
*/
- num_options = cfJoinJobOptionsAndAttrs(data, num_options, &options);
-
- /*
- * If we have a PPD file in the filter data, take it into account, by
- * not parsing options which are in the PPD file here.
- *
- * They should get parsed and applied separately via the
- * ppdRasterInterpretPPD() as that function parses the embedded
- * PostScript code. This way weird things like Gutenprint's
- * "Resolution" option (choice name is something odd, like
- * 301x300dpi, and actual resolution can be completely different)
- * will get treated correctly.
- *
- * We mark the option settings in the PPD and call ppdRasterInterpretPPD()
- * only when we are called with set_defaults = 1. In any case we remove
- * the options of the PPD from our option list before we start parsing.
- */
- if (data->ppd)
- {
- if (set_defaults)
- {
- ppdMarkOptions(data->ppd, num_options, options);
- ppdRasterInterpretPPD(h, data->ppd, num_options, options, NULL);
- }
- for (option = ppdFirstOption(data->ppd); option;
- option = ppdNextOption(data->ppd))
- num_options = cupsRemoveOption(option->keyword, num_options, &options);
- } else if (set_defaults)
- memset(h, 0, sizeof(cups_page_header2_t));
+ num_options = cfJoinJobOptionsAndAttrs(data, num_options, &options);
/*
* Check if the supplied "media" option is a comma-separated list of any
* combination of page size ("media"), media source ("media-position"),
- * and media type ("media-type") and if so, put these list elements into
- * their dedicated options.
+ * and media type ("media-type") and if so, extract media type and source.
+ * Media size will be handled separately.
*/
- page_size = NULL;
media_source = NULL;
media_type = NULL;
if ((media = cupsGetOption("media", num_options, options)) != NULL)
{
/*
- * Loop through the option string, separating it at commas and marking each
- * individual option as long as the corresponding PPD option (PageSize,
- * InputSlot, etc.) is not also set.
+ * Loop through the option string, separating it at commas and setting each
+ * individual option.
*
* For PageSize, we also check for an empty option value since some versions
* of MacOS X use it to specify auto-selection of the media based solely on
size_found = NULL;
if ((size_found = pwgMediaForPWG(s)) == NULL)
if ((size_found = pwgMediaForPPD(s)) == NULL)
- if ((size_found = pwgMediaForPPD(s)) == NULL)
+ if ((size_found = pwgMediaForLegacy(s)) == NULL)
{
if (strcasestr(s, "tray") ||
strcasestr(s, "feed") ||
strcasestr(s, "left") ||
strcasestr(s, "right") ||
strcasestr(s, "side") ||
+ strcasestr(s, "roll") ||
strcasestr(s, "main"))
{
if (media_source == NULL)
else
media_type = strdup(s);
}
- if (page_size == NULL && size_found)
- page_size = strdup(size_found->pwg);
}
}
+ /*
+ * Initialize header
+ */
+
+ memset(h, 0, sizeof(cups_page_header2_t));
+
+ /*
+ * Fill in the items using printer and job IPP attributes and options
+ */
+
if (pwg_raster)
strcpy(h->MediaClass, "PwgRaster");
else if ((val = cupsGetOption("media-class", num_options, options)) != NULL ||
(val = cupsGetOption("MediaClass", num_options, options)) != NULL)
_strlcpy(h->MediaClass, val, sizeof(h->MediaClass));
- else if (set_defaults)
+ else
strcpy(h->MediaClass, "");
+ if (strcasecmp(h->MediaClass, "PwgRaster") == 0)
+ pwg_raster = 1;
if ((val = cupsGetOption("media-color", num_options, options)) != NULL ||
(val = cupsGetOption("MediaColor", num_options, options)) != NULL)
_strlcpy(h->MediaColor, val, sizeof(h->MediaColor));
- else if (set_defaults)
+ else
h->MediaColor[0] = '\0';
if ((val = cupsGetOption("media-type", num_options, options)) != NULL ||
(val = cupsGetOption("MediaType", num_options, options)) != NULL ||
- (val = media_type) != NULL)
+ (val = media_type) != NULL ||
+ (val = cfIPPAttrEnumValForPrinter(data->printer_attrs,
+ data->job_attrs,
+ "media-type")) != NULL)
_strlcpy(h->MediaType, val, sizeof(h->MediaType));
- else if (set_defaults)
+ else
h->MediaType[0] = '\0';
if ((val = cupsGetOption("print-content-optimize", num_options,
options)) != NULL ||
(val = cupsGetOption("output-type", num_options, options)) != NULL ||
- (val = cupsGetOption("OutputType", num_options, options)) != NULL)
+ (val = cupsGetOption("OutputType", num_options, options)) != NULL ||
+ (val = cfIPPAttrEnumValForPrinter(data->printer_attrs,
+ data->job_attrs,
+ "print-content-optimize")) != NULL)
{
- if (!strcasecmp(val, "automatic"))
- _strlcpy(h->OutputType, "Automatic",
+ if (!strncasecmp(val, "auto", 4))
+ _strlcpy(h->OutputType, "automatic",
sizeof(h->OutputType));
else if (!strcasecmp(val, "graphics") ||
!strcasecmp(val, "graphic"))
- _strlcpy(h->OutputType, "Graphics", sizeof(h->OutputType));
+ _strlcpy(h->OutputType, "graphics", sizeof(h->OutputType));
else if (!strcasecmp(val, "photo"))
- _strlcpy(h->OutputType, "Photo", sizeof(h->OutputType));
+ _strlcpy(h->OutputType, "photo", sizeof(h->OutputType));
else if (!strcasecmp(val, "text"))
- _strlcpy(h->OutputType, "Text", sizeof(h->OutputType));
+ _strlcpy(h->OutputType, "text", sizeof(h->OutputType));
else if (!strcasecmp(val, "text-and-graphics") ||
!strcasecmp(val, "text-and-graphic") ||
!strcasecmp(val, "TextAndGraphics") ||
!strcasecmp(val, "TextAndGraphic"))
- _strlcpy(h->OutputType, "TextAndGraphics",
+ _strlcpy(h->OutputType, "text-and-graphics",
sizeof(h->OutputType));
else if (!pwg_raster)
_strlcpy(h->OutputType, val, sizeof(h->OutputType));
}
- else if (set_defaults)
- _strlcpy(h->OutputType, "Automatic", sizeof(h->OutputType));
+ else
+ _strlcpy(h->OutputType, "automatic", sizeof(h->OutputType));
if (pwg_raster)
{
else
{
/* TODO - Support for advance distance and advance media */
- if (set_defaults)
+ h->AdvanceDistance = 0;
+ h->AdvanceMedia = CUPS_ADVANCE_NONE;
+ if ((val = cupsGetOption("Collate", num_options, options)) != NULL ||
+ (val = cupsGetOption("multiple-document-handling",
+ num_options, options)) != NULL ||
+ (val = cfIPPAttrEnumValForPrinter(data->printer_attrs,
+ data->job_attrs,
+ "multiple-document-handling")) !=
+ NULL)
{
- h->AdvanceDistance = 0;
- h->AdvanceMedia = CUPS_ADVANCE_NONE;
+ if (!strcasecmp(val, "true") || !strcasecmp(val, "on") ||
+ !strcasecmp(val, "yes") ||
+ !strcasecmp(val, "separate-documents-collated-copies"))
+ h->Collate = CUPS_TRUE;
+ else
+ h->Collate = CUPS_FALSE;
}
- if ((val = cupsGetOption("Collate", num_options, options)) != NULL &&
- (!strcasecmp(val, "true") || !strcasecmp(val, "on") ||
- !strcasecmp(val, "yes")))
- h->Collate = CUPS_TRUE;
- else if ((val = cupsGetOption("Collate", num_options, options)) != NULL &&
- (!strcasecmp(val, "false") || !strcasecmp(val, "off") ||
- !strcasecmp(val, "no")))
- h->Collate = CUPS_FALSE;
- else if (set_defaults)
+ else
h->Collate = CUPS_FALSE;
}
- if (set_defaults)
- h->CutMedia = CUPS_CUT_NONE;
+ h->CutMedia = CUPS_CUT_NONE;
- if (set_defaults)
- h->Tumble = CUPS_FALSE;
+ h->Tumble = CUPS_FALSE;
if ((val = cupsGetOption("sides", num_options, options)) != NULL ||
- (val = cupsGetOption("Duplex", num_options, options)) != NULL)
+ (val = cupsGetOption("Duplex", num_options, options)) != NULL ||
+ (val = cfIPPAttrEnumValForPrinter(data->printer_attrs,
+ data->job_attrs,
+ "sides")) != NULL)
{
if (!strcasecmp(val, "None") || !strcasecmp(val, "Off") ||
!strcasecmp(val, "False") || !strcasecmp(val, "No") ||
!strncasecmp(val, "Duplex", 6))
{
h->Duplex = CUPS_TRUE;
- if (!strncasecmp(val, "DuplexTumble", 12))
+ if (!strncasecmp(val, "DuplexTumble", 12) ||
+ strcasestr(val, "short-edge"))
h->Tumble = CUPS_TRUE;
- if (!strncasecmp(val, "DuplexNoTumble", 12))
+ if (!strncasecmp(val, "DuplexNoTumble", 14) ||
+ strcasestr(val, "long-edge"))
h->Tumble = CUPS_FALSE;
}
- else if (set_defaults)
+ else
h->Duplex = CUPS_FALSE;
}
- else if (set_defaults)
+ else
h->Duplex = CUPS_FALSE;
if ((val = cupsGetOption("printer-resolution", num_options,
yres = strtol(ptr + 1, (char **)&ptr, 10);
}
- if (ptr <= val || xres <= 0 || yres <= 0 || !ptr ||
- (*ptr != '\0' &&
- strcasecmp(ptr, "dpi") &&
- strcasecmp(ptr, "dpc") &&
- strcasecmp(ptr, "dpcm")))
- {
- if (set_defaults)
- {
- h->HWResolution[0] = 600;
- h->HWResolution[1] = 600;
- }
- }
- else
+ if (ptr > val && xres > 0 && yres > 0 && ptr &&
+ (*ptr == '\0' ||
+ !strcasecmp(ptr, "dpi") ||
+ !strcasecmp(ptr, "dpc") ||
+ !strcasecmp(ptr, "dpcm")))
{
if (!strcasecmp(ptr, "dpc") ||
!strcasecmp(ptr, "dpcm"))
h->HWResolution[0] = xres;
h->HWResolution[1] = yres;
}
+ else
+ {
+ h->HWResolution[0] = 100; /* Resolution invalid */
+ h->HWResolution[1] = 100;
+ }
}
- else if (set_defaults)
- {
- h->HWResolution[0] = 600;
- h->HWResolution[1] = 600;
- }
-
- if (set_defaults)
+ else
{
- /* TODO - Support for insert sheets */
- h->InsertSheet = CUPS_FALSE;
+ h->HWResolution[0] = 100; /* Resolution invalid */
+ h->HWResolution[1] = 100;
}
- if (set_defaults)
+ // Resolution from IPP attrs
+ if (h->HWResolution[0] == 100 && h->HWResolution[1] == 100)
{
- /* TODO - Support for jog */
- h->Jog = CUPS_JOG_NONE;
+ int x = 0, y = 0;
+ cfIPPAttrResolutionForPrinter(data->printer_attrs, data->job_attrs,
+ NULL, &x, &y);
+ if (x && y)
+ {
+ h->HWResolution[0] = x;
+ h->HWResolution[1] = y;
+ }
}
+
+ /* TODO - Support for insert sheets */
+ h->InsertSheet = CUPS_FALSE;
+
+ /* TODO - Support for jog */
+ h->Jog = CUPS_JOG_NONE;
if ((val = cupsGetOption("feed-orientation", num_options,
options)) != NULL ||
else if (!strcasecmp(val, "LongEdgeFirst"))
h->LeadingEdge = CUPS_EDGE_RIGHT;
}
- else if (set_defaults)
+ else
h->LeadingEdge = CUPS_EDGE_TOP;
- if (pwg_raster || set_defaults)
- {
- /* TODO - Support for manual feed */
- h->ManualFeed = CUPS_FALSE;
- }
+ /* TODO - Support for manual feed */
+ h->ManualFeed = CUPS_FALSE;
if ((val = cupsGetOption("media-position", num_options, options)) != NULL ||
(val = cupsGetOption("MediaPosition", num_options, options)) != NULL ||
(val = cupsGetOption("media-source", num_options, options)) != NULL ||
(val = cupsGetOption("MediaSource", num_options, options)) != NULL ||
(val = cupsGetOption("InputSlot", num_options, options)) != NULL ||
- (val = media_source) != NULL)
+ (val = media_source) != NULL ||
+ (val = cfIPPAttrEnumValForPrinter(data->printer_attrs,
+ data->job_attrs,
+ "media-source")) != NULL)
{
if (!strncasecmp(val, "Auto", 4) ||
!strncasecmp(val, "Default", 7))
h->MediaPosition = 1;
else if (!strcasecmp(val, "Alternate"))
h->MediaPosition = 2;
- else if (!strcasecmp(val, "LargeCapacity"))
+ else if (!strcasecmp(val, "LargeCapacity") ||
+ !strcasecmp(val, "large-capacity"))
h->MediaPosition = 3;
else if (!strcasecmp(val, "Manual"))
h->MediaPosition = 4;
h->MediaPosition = 7;
else if (!strcasecmp(val, "Hagaki"))
h->MediaPosition = 8;
- else if (!strcasecmp(val, "MainRoll"))
+ else if (!strcasecmp(val, "MainRoll") ||
+ !strcasecmp(val, "main-roll"))
h->MediaPosition = 9;
- else if (!strcasecmp(val, "AlternateRoll"))
+ else if (!strcasecmp(val, "AlternateRoll") ||
+ !strcasecmp(val, "alternate-roll"))
h->MediaPosition = 10;
else if (!strcasecmp(val, "Top"))
h->MediaPosition = 11;
h->MediaPosition = 17;
else if (!strcasecmp(val, "Rear"))
h->MediaPosition = 18;
- else if (!strcasecmp(val, "ByPassTray"))
+ else if (!strcasecmp(val, "ByPassTray") ||
+ !strcasecmp(val, "bypass-tray"))
h->MediaPosition = 19;
- else if (!strcasecmp(val, "Tray1"))
+ else if (!strcasecmp(val, "Tray1") ||
+ !strcasecmp(val, "tray-1"))
h->MediaPosition = 20;
- else if (!strcasecmp(val, "Tray2"))
+ else if (!strcasecmp(val, "Tray2") ||
+ !strcasecmp(val, "tray-2"))
h->MediaPosition = 21;
- else if (!strcasecmp(val, "Tray3"))
+ else if (!strcasecmp(val, "Tray3") ||
+ !strcasecmp(val, "tray-3"))
h->MediaPosition = 22;
- else if (!strcasecmp(val, "Tray4"))
+ else if (!strcasecmp(val, "Tray4") ||
+ !strcasecmp(val, "tray-4"))
h->MediaPosition = 23;
- else if (!strcasecmp(val, "Tray5"))
+ else if (!strcasecmp(val, "Tray5") ||
+ !strcasecmp(val, "tray-5"))
h->MediaPosition = 24;
- else if (!strcasecmp(val, "Tray6"))
+ else if (!strcasecmp(val, "Tray6") ||
+ !strcasecmp(val, "tray-6"))
h->MediaPosition = 25;
- else if (!strcasecmp(val, "Tray7"))
+ else if (!strcasecmp(val, "Tray7") ||
+ !strcasecmp(val, "tray-7"))
h->MediaPosition = 26;
- else if (!strcasecmp(val, "Tray8"))
+ else if (!strcasecmp(val, "Tray8") ||
+ !strcasecmp(val, "tray-8"))
h->MediaPosition = 27;
- else if (!strcasecmp(val, "Tray9"))
+ else if (!strcasecmp(val, "Tray9") ||
+ !strcasecmp(val, "tray-9"))
h->MediaPosition = 28;
- else if (!strcasecmp(val, "Tray10"))
+ else if (!strcasecmp(val, "Tray10") ||
+ !strcasecmp(val, "tray-10"))
h->MediaPosition = 29;
- else if (!strcasecmp(val, "Tray11"))
+ else if (!strcasecmp(val, "Tray11") ||
+ !strcasecmp(val, "tray-11"))
h->MediaPosition = 30;
- else if (!strcasecmp(val, "Tray12"))
+ else if (!strcasecmp(val, "Tray12") ||
+ !strcasecmp(val, "tray-12"))
h->MediaPosition = 31;
- else if (!strcasecmp(val, "Tray13"))
+ else if (!strcasecmp(val, "Tray13") ||
+ !strcasecmp(val, "tray-13"))
h->MediaPosition = 32;
- else if (!strcasecmp(val, "Tray14"))
+ else if (!strcasecmp(val, "Tray14") ||
+ !strcasecmp(val, "tray-14"))
h->MediaPosition = 33;
- else if (!strcasecmp(val, "Tray15"))
+ else if (!strcasecmp(val, "Tray15") ||
+ !strcasecmp(val, "tray-15"))
h->MediaPosition = 34;
- else if (!strcasecmp(val, "Tray16"))
+ else if (!strcasecmp(val, "Tray16") ||
+ !strcasecmp(val, "tray-16"))
h->MediaPosition = 35;
- else if (!strcasecmp(val, "Tray17"))
+ else if (!strcasecmp(val, "Tray17") ||
+ !strcasecmp(val, "tray-17"))
h->MediaPosition = 36;
- else if (!strcasecmp(val, "Tray18"))
+ else if (!strcasecmp(val, "Tray18") ||
+ !strcasecmp(val, "tray-18"))
h->MediaPosition = 37;
- else if (!strcasecmp(val, "Tray19"))
+ else if (!strcasecmp(val, "Tray19") ||
+ !strcasecmp(val, "tray-19"))
h->MediaPosition = 38;
- else if (!strcasecmp(val, "Tray20"))
+ else if (!strcasecmp(val, "Tray20") ||
+ !strcasecmp(val, "tray-20"))
h->MediaPosition = 39;
- else if (!strcasecmp(val, "Roll1"))
+ else if (!strcasecmp(val, "Roll1") ||
+ !strcasecmp(val, "roll-1"))
h->MediaPosition = 40;
- else if (!strcasecmp(val, "Roll2"))
+ else if (!strcasecmp(val, "Roll2") ||
+ !strcasecmp(val, "roll-2"))
h->MediaPosition = 41;
- else if (!strcasecmp(val, "Roll3"))
+ else if (!strcasecmp(val, "Roll3") ||
+ !strcasecmp(val, "roll-3"))
h->MediaPosition = 42;
- else if (!strcasecmp(val, "Roll4"))
+ else if (!strcasecmp(val, "Roll4") ||
+ !strcasecmp(val, "roll-4"))
h->MediaPosition = 43;
- else if (!strcasecmp(val, "Roll5"))
+ else if (!strcasecmp(val, "Roll5") ||
+ !strcasecmp(val, "roll-5"))
h->MediaPosition = 44;
- else if (!strcasecmp(val, "Roll6"))
+ else if (!strcasecmp(val, "Roll6") ||
+ !strcasecmp(val, "roll-6"))
h->MediaPosition = 45;
- else if (!strcasecmp(val, "Roll7"))
+ else if (!strcasecmp(val, "Roll7") ||
+ !strcasecmp(val, "roll-7"))
h->MediaPosition = 46;
- else if (!strcasecmp(val, "Roll8"))
+ else if (!strcasecmp(val, "Roll8") ||
+ !strcasecmp(val, "roll-8"))
h->MediaPosition = 47;
- else if (!strcasecmp(val, "Roll9"))
+ else if (!strcasecmp(val, "Roll9") ||
+ !strcasecmp(val, "roll-9"))
h->MediaPosition = 48;
- else if (!strcasecmp(val, "Roll10"))
+ else if (!strcasecmp(val, "Roll10") ||
+ !strcasecmp(val, "roll-10"))
h->MediaPosition = 49;
}
- else if (set_defaults)
+ else
h->MediaPosition = 0; /* Auto */
if ((val = cupsGetOption("media-weight", num_options, options)) != NULL ||
options)) != NULL ||
(val = cupsGetOption("MediaWeightMetric", num_options, options)) != NULL)
h->MediaWeight = atol(val);
- else if (set_defaults)
+ else
h->MediaWeight = 0;
if (pwg_raster)
!strcasecmp(val, "off") ||
!strcasecmp(val, "no"))
h->MirrorPrint = CUPS_FALSE;
- else if (set_defaults)
+ else
h->MirrorPrint = CUPS_FALSE;
}
if ((val = cupsGetOption("negative-print", num_options, options)) != NULL ||
!strcasecmp(val, "off") ||
!strcasecmp(val, "no"))
h->NegativePrint = CUPS_FALSE;
- else if (set_defaults)
+ else
h->NegativePrint = CUPS_FALSE;
}
}
+ i = 0;
if ((val = cupsGetOption("copies", num_options, options)) != NULL ||
(val = cupsGetOption("Copies", num_options, options)) != NULL ||
(val = cupsGetOption("num-copies", num_options, options)) != NULL ||
- (val = cupsGetOption("NumCopies", num_options, options)) != NULL)
- h->NumCopies = atol(val);
- else if (set_defaults)
+ (val = cupsGetOption("NumCopies", num_options, options)) != NULL ||
+ cfIPPAttrIntValForPrinter(data->printer_attrs, data->job_attrs,
+ "copies", &i) == 1)
+ {
+ if (val)
+ h->NumCopies = atol(val);
+ else if (i)
+ h->NumCopies = i;
+ }
+ else
h->NumCopies = 1; /* 0 = Printer default */
if ((val = cupsGetOption("orientation-requested", num_options,
options)) != NULL ||
(val = cupsGetOption("OrientationRequested", num_options,
options)) != NULL ||
- (val = cupsGetOption("Orientation", num_options, options)) != NULL)
+ (val = cupsGetOption("Orientation", num_options, options)) != NULL ||
+ (val = cfIPPAttrEnumValForPrinter(data->printer_attrs,
+ data->job_attrs,
+ "orientation-requested")) != NULL)
{
if (!strcasecmp(val, "Portrait") ||
!strcasecmp(val, "3") ||
!strcasecmp(val, "ReverseLandscape") ||
!strcasecmp(val, "6"))
h->Orientation = CUPS_ORIENT_270;
- else if (set_defaults)
+ else
h->Orientation = CUPS_ORIENT_0;
}
- else if (set_defaults)
+ else
h->Orientation = CUPS_ORIENT_0;
if (pwg_raster)
else
{
if ((val = cupsGetOption("OutputFaceUp", num_options, options)) != NULL ||
- (val = cupsGetOption("output-face-up", num_options, options)) != NULL)
+ (val = cupsGetOption("output-face-up", num_options, options)) != NULL ||
+ (val = cupsGetOption("OutputBin", num_options, options)) != NULL ||
+ (val = cupsGetOption("output-bin", num_options, options)) != NULL ||
+ (val = cfIPPAttrEnumValForPrinter(data->printer_attrs,
+ data->job_attrs,
+ "output-bin")) != NULL)
{
if (!strcasecmp(val, "true") || !strcasecmp(val, "on") ||
- !strcasecmp(val, "yes"))
+ !strcasecmp(val, "yes") || !strcasecmp(val, "face-up") ||
+ !strcasecmp(val, "FaceUp"))
h->OutputFaceUp = CUPS_TRUE;
- else if (!strcasecmp(val, "false") ||
- !strcasecmp(val, "off") ||
- !strcasecmp(val, "no"))
+ else if (!strcasecmp(val, "false") || !strcasecmp(val, "off") ||
+ !strcasecmp(val, "no") || !strcasecmp(val, "face-down") ||
+ !strcasecmp(val, "FaceDown"))
h->OutputFaceUp = CUPS_FALSE;
- else if (set_defaults)
- h->OutputFaceUp = CUPS_FALSE;
- }
- }
-
- if ((val = cupsGetOption("media-size", num_options, options)) != NULL ||
- (val = cupsGetOption("MediaSize", num_options, options)) != NULL ||
- (val = cupsGetOption("page-size", num_options, options)) != NULL ||
- (val = cupsGetOption("PageSize", num_options, options)) != NULL ||
- (val = page_size) != NULL)
- {
- size_found = NULL;
- if ((size_found = pwgMediaForPWG(val)) == NULL)
- if ((size_found = pwgMediaForPPD(val)) == NULL)
- size_found = pwgMediaForLegacy(val);
- if (size_found != NULL)
- {
- h->PageSize[0] = size_found->width * 72 / 2540;
- h->PageSize[1] = size_found->length * 72 / 2540;
- _strlcpy(h->cupsPageSizeName, size_found->pwg,
- sizeof(h->cupsPageSizeName));
- if (pwg_raster)
- {
- h->cupsPageSize[0] = 0.0;
- h->cupsPageSize[1] = 0.0;
- }
else
- {
- h->cupsPageSize[0] = size_found->width * 72.0 / 2540.0;
- h->cupsPageSize[1] = size_found->length * 72.0 / 2540.0;
- }
- }
- }
- else if (set_defaults)
- {
- /* TODO: Automatic A4/Letter, like in scheduler/conf.c in CUPS. */
- h->cupsPageSize[0] = 612.0f;
- h->cupsPageSize[1] = 792.0f;
-
- h->PageSize[0] = 612;
- h->PageSize[1] = 792;
- _strlcpy(h->cupsPageSizeName, "na_letter_8.5x11in",
- sizeof(h->cupsPageSizeName));
- if (pwg_raster)
- {
- h->cupsPageSize[0] = 0.0;
- h->cupsPageSize[1] = 0.0;
- }
- }
- else if (pwg_raster)
- {
- h->cupsPageSize[0] = 0.0;
- h->cupsPageSize[1] = 0.0;
- }
-
- if (pwg_raster)
- {
- /* Set "reserved" fields to 0 */
- h->Margins[0] = 0;
- h->Margins[1] = 0;
- h->ImagingBoundingBox[0] = 0;
- h->ImagingBoundingBox[1] = 0;
- h->ImagingBoundingBox[2] = 0;
- h->ImagingBoundingBox[3] = 0;
- h->cupsImagingBBox[0] = 0.0;
- h->cupsImagingBBox[1] = 0.0;
- h->cupsImagingBBox[2] = 0.0;
- h->cupsImagingBBox[3] = 0.0;
- }
- else
- {
- if ((val = cupsGetOption("media-left-margin", num_options, options))
- != NULL)
- {
- size = atol(val) * 72.0 / 2540.0;
- h->Margins[0] = (int)size;
- h->ImagingBoundingBox[0] = (int)size;
- h->cupsImagingBBox[0] = size;
- }
- else if (set_defaults)
- {
- h->Margins[0] = 0;
- h->ImagingBoundingBox[0] = 0;
- h->cupsImagingBBox[0] = 18.0f;
- }
- if ((val = cupsGetOption("media-bottom-margin", num_options, options))
- != NULL)
- {
- size = atol(val) * 72.0 / 2540.0;
- h->Margins[1] = (int)size;
- h->ImagingBoundingBox[1] = (int)size;
- h->cupsImagingBBox[1] = size;
- }
- else if (set_defaults)
- {
- h->Margins[1] = 0;
- h->ImagingBoundingBox[1] = 0;
- h->cupsImagingBBox[1] = 36.0f;
- }
- if ((val = cupsGetOption("media-right-margin", num_options, options))
- != NULL)
- {
- size = atol(val) * 72.0 / 2540.0;
- h->ImagingBoundingBox[2] = h->PageSize[0] - (int)size;
- h->cupsImagingBBox[2] = h->cupsPageSize[0] - size;
- }
- else if (set_defaults)
- {
- h->ImagingBoundingBox[2] = h->PageSize[0];
- h->cupsImagingBBox[2] = 594.0f;
- }
- if ((val = cupsGetOption("media-top-margin", num_options, options))
- != NULL)
- {
- size = atol(val) * 72.0 / 2540.0;
- h->ImagingBoundingBox[3] = h->PageSize[1] - (int)size;
- h->cupsImagingBBox[3] = h->cupsPageSize[1] - size;
- }
- else if (set_defaults)
- {
- h->ImagingBoundingBox[3] = h->PageSize[1];
- h->cupsImagingBBox[3] = 756.0f;
+ h->OutputFaceUp = CUPS_FALSE;
}
}
!strcasecmp(val, "off") ||
!strcasecmp(val, "no"))
h->Separations = CUPS_FALSE;
- else if (set_defaults)
+ else
h->Separations = CUPS_FALSE;
}
if ((val = cupsGetOption("tray-switch", num_options, options)) != NULL ||
!strcasecmp(val, "off") ||
!strcasecmp(val, "no"))
h->TraySwitch = CUPS_FALSE;
- else if (set_defaults)
+ else
h->TraySwitch = CUPS_FALSE;
}
}
- if ((val = cupsGetOption("sides", num_options, options)) != NULL ||
- (val = cupsGetOption("Tumble", num_options, options)) != NULL)
+ if ((val = cupsGetOption("Tumble", num_options, options)) != NULL)
{
- if (!strcasecmp(val, "None") || !strcasecmp(val, "Off") ||
- !strcasecmp(val, "False") || !strcasecmp(val, "No") ||
- !strcasecmp(val, "one-sided") || !strcasecmp(val, "OneSided") ||
- !strcasecmp(val, "two-sided-long-edge") ||
- !strcasecmp(val, "TwoSidedLongEdge") ||
- !strcasecmp(val, "DuplexNoTumble"))
+ if (!strcasecmp(val, "Off") || !strcasecmp(val, "False") ||
+ !strcasecmp(val, "No"))
h->Tumble = CUPS_FALSE;
- else if (!strcasecmp(val, "On") ||
- !strcasecmp(val, "True") || !strcasecmp(val, "Yes") ||
- !strcasecmp(val, "two-sided-short-edge") ||
- !strcasecmp(val, "TwoSidedShortEdge") ||
- !strcasecmp(val, "DuplexTumble"))
+ else if (!strcasecmp(val, "On") || !strcasecmp(val, "True") ||
+ !strcasecmp(val, "Yes"))
h->Tumble = CUPS_TRUE;
}
- h->cupsWidth = h->HWResolution[0] * h->PageSize[0] / 72;
- h->cupsHeight = h->HWResolution[1] * h->PageSize[1] / 72;
-
- if (pwg_raster || set_defaults)
- {
- /* TODO - Support for MediaType number */
- h->cupsMediaType = 0;
- }
-
- if ((val = cupsGetOption("pwg-raster-document-type", num_options,
- options)) != NULL ||
- (val = cupsGetOption("PwgRasterDocumentType", num_options,
- options)) != NULL ||
- (val = cupsGetOption("color-space", num_options, options)) != NULL ||
- (val = cupsGetOption("ColorSpace", num_options, options)) != NULL ||
- (val = cupsGetOption("color-model", num_options, options)) != NULL ||
- (val = cupsGetOption("ColorModel", num_options, options)) != NULL ||
- (val = cupsGetOption("print-color-mode", num_options, options)) != NULL ||
- (val = cupsGetOption("output-mode", num_options, options)) != NULL ||
- (val = cupsGetOption("OutputMode", num_options, options)) != NULL)
+ /* TODO - Support for MediaType number */
+ h->cupsMediaType = 0;
+
+ /* Only for CUPS Raster, if we do not have a sample header from a PPD file */
+ if (pwg_raster == 0 &&
+ ((val = cupsGetOption("pwg-raster-document-type", num_options,
+ options)) != NULL ||
+ (val = cupsGetOption("PwgRasterDocumentType", num_options,
+ options)) != NULL ||
+ (val = cupsGetOption("color-space", num_options, options)) != NULL ||
+ (val = cupsGetOption("ColorSpace", num_options, options)) != NULL ||
+ (val = cupsGetOption("color-model", num_options, options)) != NULL ||
+ (val = cupsGetOption("ColorModel", num_options, options)) != NULL ||
+ (val = cupsGetOption("print-color-mode", num_options, options)) !=
+ NULL ||
+ (val = cupsGetOption("output-mode", num_options, options)) != NULL ||
+ (val = cupsGetOption("OutputMode", num_options, options)) != NULL ||
+ (val = cfIPPAttrEnumValForPrinter(data->printer_attrs,
+ data->job_attrs,
+ "print-color-mode")) != NULL))
{
int bitspercolor, /* Bits per color */
bitsperpixel, /* Bits per pixel */
else if (!strcasecmp(val, "auto"))
{
/* Let "auto" not look like an error */
- if (set_defaults)
- {
- colorspace = 19;
- numcolors = 3;
- }
+ colorspace = 19;
+ numcolors = 3;
}
if (numcolors > 0)
{
}
else
{
- if (set_defaults)
- {
- h->cupsBitsPerColor = 8;
- h->cupsBitsPerPixel = 24;
- h->cupsColorSpace = 19;
- h->cupsNumColors = 3;
- }
+ h->cupsBitsPerColor = 8;
+ h->cupsBitsPerPixel = 24;
+ h->cupsColorSpace = 19;
+ h->cupsNumColors = 3;
}
}
- else if (set_defaults)
+ else
{
h->cupsBitsPerColor = 8;
h->cupsBitsPerPixel = 24;
h->cupsNumColors = 3;
}
- h->cupsBytesPerLine = (h->cupsWidth * h->cupsBitsPerPixel + 7) / 8;
+ /* TODO - Support for color orders 1 (banded) and 2 (planar) */
+ h->cupsColorOrder = 0;
- if (pwg_raster || set_defaults)
- {
- /* TODO - Support for color orders 1 (banded) and 2 (planar) */
- h->cupsColorOrder = 0;
- }
-
- if (pwg_raster || set_defaults)
- {
- /* TODO - Support for these parameters */
- h->cupsCompression = 0;
- h->cupsRowCount = 0;
- h->cupsRowFeed = 0;
- h->cupsRowStep = 0;
- }
+ /* TODO - Support for these parameters */
+ h->cupsCompression = 0;
+ h->cupsRowCount = 0;
+ h->cupsRowFeed = 0;
+ h->cupsRowStep = 0;
- if (pwg_raster || set_defaults)
- {
- /* TODO - Support for cupsBorderlessScalingFactor */
- h->cupsBorderlessScalingFactor = 0.0;
- }
+ /* TODO - Support for cupsBorderlessScalingFactor */
+ h->cupsBorderlessScalingFactor = 0.0;
- if (pwg_raster || set_defaults)
+ /* TODO - Support for custom values in CUPS Raster mode */
+ for (i = 0; i < 16; i ++)
{
- /* TODO - Support for custom values in CUPS Raster mode */
- for (i = 0; i < 16; i ++)
- {
- h->cupsInteger[i] = 0;
- h->cupsReal[i] = 0.0;
- memset(h->cupsString[i], 0, 64);
- }
+ h->cupsInteger[i] = 0;
+ h->cupsReal[i] = 0.0;
+ memset(h->cupsString[i], 0, 64);
}
if (pwg_raster)
h->cupsInteger[0] = impressions;
}
+ /* Printer property, command line options only for development and
+ debugging */
if ((val = cupsGetOption("pwg-raster-document-sheet-back", num_options,
options)) != NULL ||
- (val = cupsGetOption("PwgRasterDocumentSheetBack", num_options,
- options)) != NULL)
+ (val = cupsGetOption("back-side-orientation", num_options,
+ options)) != NULL ||
+ (data->printer_attrs &&
+ ((attr = ippFindAttribute(data->printer_attrs, "urf-supported",
+ IPP_TAG_ZERO)) != NULL ||
+ (attr = ippFindAttribute(data->printer_attrs,
+ "pwg-raster-document-sheet-back",
+ IPP_TAG_ZERO)) != NULL ||
+ (attr = ippFindAttribute(data->printer_attrs,
+ "pclm-raster-back-side",
+ IPP_TAG_ZERO)) != NULL)))
{
+ if (val == NULL)
+ {
+ if (ippGetCount(attr) > 1) // urf-supported
+ {
+ for (i = 0; i < ippGetCount(attr); i ++)
+ {
+ val = ippGetString(attr, i, NULL);
+ if (strncmp(val, "DM", 2) == 0) // Duplex mode field
+ break;
+ }
+ if (i == ippGetCount(attr)) // Not found, no duplex
+ val = "DM1";
+ }
+ else // pwg-raster-document-sheet-back/pclm-raster-back-side
+ val = ippGetString(attr, 0, NULL);
+ }
/* Set CrossFeedTransform and FeedTransform */
if (h->Duplex == CUPS_FALSE)
{
{
if (h->Tumble == CUPS_FALSE)
{
- if (!strcasecmp(val, "Flipped"))
+ if (!strcasecmp(val, "Flipped") ||
+ !strcasecmp(val, "DM2"))
{
h->cupsInteger[1] = 1;
h->cupsInteger[2] = -1;
}
- else if (!strncasecmp(val, "Manual", 6))
+ else if (!strncasecmp(val, "Manual", 6) ||
+ !strcasecmp(val, "DM4"))
{
h->cupsInteger[1] = 1;
h->cupsInteger[2] = 1;
}
- else if (!strcasecmp(val, "Normal"))
+ else if (!strcasecmp(val, "Normal") ||
+ !strcasecmp(val, "DM1"))
{
h->cupsInteger[1] = 1;
h->cupsInteger[2] = 1;
}
- else if (!strcasecmp(val, "Rotated"))
+ else if (!strcasecmp(val, "Rotated") ||
+ !strcasecmp(val, "DM3"))
{
h->cupsInteger[1] = -1;
h->cupsInteger[2] = -1;
}
else
{
- if (!strcasecmp(val, "Flipped"))
+ if (!strcasecmp(val, "Flipped") ||
+ !strcasecmp(val, "DM2"))
{
h->cupsInteger[1] = -1;
h->cupsInteger[2] = 1;
}
- else if (!strncasecmp(val, "Manual", 6))
+ else if (!strncasecmp(val, "Manual", 6) ||
+ !strcasecmp(val, "DM4"))
{
h->cupsInteger[1] = -1;
h->cupsInteger[2] = -1;
}
- else if (!strcasecmp(val, "Normal"))
+ else if (!strcasecmp(val, "Normal") ||
+ !strcasecmp(val, "DM1"))
{
h->cupsInteger[1] = 1;
h->cupsInteger[2] = 1;
}
- else if (!strcasecmp(val, "Rotated"))
+ else if (!strcasecmp(val, "Rotated") ||
+ !strcasecmp(val, "DM3"))
{
h->cupsInteger[1] = 1;
h->cupsInteger[2] = 1;
{
int vendorlength = atoi(val); /* How many bytes of vendor
data? */
- if (vendorlength <= 1088)
+ if (vendorlength > 0 && vendorlength <= 1088)
{
h->cupsInteger[15] = vendorlength;
if ((val = cupsGetOption("vendor-data", num_options,
}
}
- if (pwg_raster || set_defaults)
- {
- /* Set "reserved" fields to 0 */
- memset(h->cupsMarkerType, 0, 64);
- }
+ /* Set "reserved" fields to 0 */
+ memset(h->cupsMarkerType, 0, 64);
if ((val = cupsGetOption("print-rendering-intent", num_options,
options)) != NULL ||
(val = cupsGetOption("PrintRenderingIntent", num_options,
options)) != NULL ||
(val = cupsGetOption("RenderingIntent", num_options,
- options)) != NULL)
+ options)) != NULL ||
+ (val = cfIPPAttrEnumValForPrinter(data->printer_attrs,
+ data->job_attrs,
+ "print-rendering-intent")) != NULL)
{
if (!strcmp(val, "absolute"))
_strlcpy(h->cupsRenderingIntent, "Absolute",
else if (!strcmp(val, "relative"))
_strlcpy(h->cupsRenderingIntent, "Relative",
sizeof(h->cupsRenderingIntent));
- else if (!strcmp(val, "relative-bpc"))
+ else if (!strcmp(val, "relative-bpc") ||
+ !strcmp(val, "RelativeBpc"))
_strlcpy(h->cupsRenderingIntent, "RelativeBpc",
sizeof(h->cupsRenderingIntent));
else if (!strcmp(val, "saturation"))
_strlcpy(h->cupsRenderingIntent, "Saturation",
sizeof(h->cupsRenderingIntent));
}
- else if (set_defaults)
+ else
h->cupsRenderingIntent[0] = '\0';
if (media_source != NULL)
free(media_source);
if (media_type != NULL)
free(media_type);
- if (page_size != NULL)
- free(page_size);
cupsFreeOptions(num_options, options);
-#endif /* HAVE_CUPS_1_7 */
return (0);
}
* Prototypes...
*/
+extern const char * cfRasterColorSpaceString(cups_cspace_t cspace);
extern int cfRasterPrepareHeader(cups_page_header2_t *h,
cf_filter_data_t *data,
cf_filter_out_format_t
const char *color_mode,
cups_cspace_t *cspace,
int *high_depth);
-extern int cfRasterParseIPPOptions(cups_page_header2_t *h,
- cf_filter_data_t *data,
- int pwg_raster,
- int set_defaults);
extern int cfJoinJobOptionsAndAttrs(cf_filter_data_t *data,
int num_options,
cups_option_t **options);
double dimensions[2],
int *image_fit,
int *landscape);
-extern int cfGetBackSideAndHeaderDuplex(ipp_t *printer_attrs,
- cups_page_header2_t
- *header);
-extern int cfGetPrintRenderIntent(cf_filter_data_t *data,
- cups_page_header2_t *header);
+extern int cfGetBackSideOrientation(cf_filter_data_t *data);
+extern const char *cfGetPrintRenderIntent(cf_filter_data_t *data,
+ char *ri, int ri_len);
# ifdef __cplusplus
}
#include <cups/raster.h>
#include <cupsfilters/colormanager.h>
#include <cupsfilters/image.h>
+#include <cupsfilters/raster.h>
#include <arpa/inet.h> // ntohl
void *parameters) /* I - Filter-specific parameters (outformat) */
{
int i;
+ char *t;
rastertopdf_doc_t doc; /* Document information */
FILE *outputfp; /* Output data stream */
cf_filter_out_format_t outformat; /* Output format */
struct pdf_info pdf;
cups_raster_t *ras; /* Raster stream for printing */
cups_page_header2_t header; /* Page header from file */
- ppd_attr_t *attr; /* PPD attribute */
ipp_t *printer_attrs = data->printer_attrs; /* Printer attributes from printer data*/
ipp_attribute_t *ipp_attr; /* Printer attribute*/
const char* profile_name = NULL; /* IPP Profile Name */
outformat = CF_FILTER_OUT_FORMAT_PDF;
}
else
- outformat = CF_FILTER_OUT_FORMAT_PDF;
+ {
+ t = data->final_content_type;
+ if (t)
+ {
+ if (strcasestr(t, "pclm"))
+ outformat = CF_FILTER_OUT_FORMAT_PCLM;
+ else if (strcasestr(t, "pdf"))
+ outformat = CF_FILTER_OUT_FORMAT_PDF;
+ else
+ outformat = CF_FILTER_OUT_FORMAT_PDF;
+ }
+ else
+ outformat = CF_FILTER_OUT_FORMAT_PDF;
+ }
+
if (log) log(ld, CF_LOGLEVEL_DEBUG,
"cfFilterRasterToPDF: OUTFORMAT=\"%s\"",
outformat == CF_FILTER_OUT_FORMAT_PDF ? "PDF" : "PCLM");
doc.iscanceleddata = icd;
/* support the CUPS "cm-calibration" option */
- cm_calibrate = cfCmGetCupsColorCalibrateMode(data, data->options, data->num_options);
+ cm_calibrate = cfCmGetCupsColorCalibrateMode(data);
if (outformat == CF_FILTER_OUT_FORMAT_PCLM ||
cm_calibrate == CF_CM_CALIBRATION_ENABLED)
else
doc.cm_disabled = cfCmIsPrinterCmDisabled(data);
- if (outformat == CF_FILTER_OUT_FORMAT_PCLM && data->ppd == NULL
- && printer_attrs == NULL )
+ if (outformat == CF_FILTER_OUT_FORMAT_PCLM && printer_attrs == NULL)
{
if (log) log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterRasterToPDF: PCLm output: Neither a PPD file nor printer IPP attributes are supplied, PCLm output not possible.");
+ "cfFilterRasterToPDF: PCLm output: No printer IPP attributes are supplied, PCLm output not possible.");
return 1;
}
// Process pages as needed...
Page = 0;
- /* Get PCLm attributes from PPD */
- if (data->ppd && outformat == CF_FILTER_OUT_FORMAT_PCLM)
- {
- char *attr_name = (char *)"cupsPclmStripHeightPreferred";
- if ((attr = ppdFindAttr(data->ppd, attr_name, NULL)) != NULL)
- {
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterRasterToPDF: PPD PCLm attribute \"%s\" with value \"%s\"",
- attr_name, attr->value);
- pdf.pclm_strip_height_preferred = atoi(attr->value);
- }
- else
- pdf.pclm_strip_height_preferred = 16; /* default strip height */
-
- attr_name = (char *)"cupsPclmStripHeightSupported";
- if ((attr = ppdFindAttr(data->ppd, attr_name, NULL)) != NULL)
- {
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterRasterToPDF: PPD PCLm attribute \"%s\" with value \"%s\"",
- attr_name, attr->value);
- pdf.pclm_strip_height_supported.clear(); // remove default value = 16
- std::vector<std::string> vec = split_strings(attr->value, ",");
- for (size_t i = 0; i < vec.size(); i ++)
- pdf.pclm_strip_height_supported.push_back(atoi(vec[i].c_str()));
- vec.clear();
- }
-
- attr_name = (char *)"cupsPclmRasterBackSide";
- if ((attr = ppdFindAttr(data->ppd, attr_name, NULL)) != NULL)
- {
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterRasterToPDF: PPD PCLm attribute \"%s\" with value \"%s\"",
- attr_name, attr->value);
- pdf.pclm_raster_back_side = attr->value;
- }
-
- attr_name = (char *)"cupsPclmSourceResolutionSupported";
- if ((attr = ppdFindAttr(data->ppd, attr_name, NULL)) != NULL)
- {
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterRasterToPDF: PPD PCLm attribute \"%s\" with value \"%s\"",
- attr_name, attr->value);
- pdf.pclm_source_resolution_supported = split_strings(attr->value, ",");
- }
-
- attr_name = (char *)"cupsPclmSourceResolutionDefault";
- if ((attr = ppdFindAttr(data->ppd, attr_name, NULL)) != NULL)
- {
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterRasterToPDF: PPD PCLm attribute \"%s\" with value \"%s\"",
- attr_name, attr->value);
- pdf.pclm_source_resolution_default = attr->value;
- }
- else if (pdf.pclm_source_resolution_supported.size() > 0)
- {
- pdf.pclm_source_resolution_default =
- pdf.pclm_source_resolution_supported[0];
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterRasterToPDF: PPD PCLm attribute \"%s\" missing, taking first item of \"cupsPclmSourceResolutionSupported\" as default resolution",
- attr_name);
- }
- else
- {
- if (log) log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterRasterToPDF: PCLm output: PPD file does not contain printer resolution information for PCLm.");
- return 1;
- }
-
- attr_name = (char *)"cupsPclmCompressionMethodPreferred";
- if ((attr = ppdFindAttr(data->ppd, attr_name, NULL)) != NULL)
- {
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterRasterToPDF: PPD PCLm attribute \"%s\" with value \"%s\"",
- attr_name, attr->value);
- std::vector<std::string> vec = split_strings(attr->value, ",");
-
- // get all compression methods supported by the printer
- for (std::vector<std::string>::iterator it = vec.begin();
- it != vec.end(); ++it)
- {
- std::string compression_method = *it;
- for (char& x: compression_method)
- x = tolower(x);
- if (compression_method == "flate")
- pdf.pclm_compression_method_preferred.push_back(FLATE_DECODE);
- else if (compression_method == "rle")
- pdf.pclm_compression_method_preferred.push_back(RLE_DECODE);
- else if (compression_method == "jpeg")
- pdf.pclm_compression_method_preferred.push_back(DCT_DECODE);
- }
-
- }
- // If the compression methods is none of the above or is erreneous
- // use FLATE as compression method and show a warning.
- if (pdf.pclm_compression_method_preferred.empty())
- {
- if (log) log(ld, CF_LOGLEVEL_WARN,
- "(rastertopclm) Unable parse PPD attribute \"%s\". "
- "Using FLATE for encoding image streams.", attr_name);
- pdf.pclm_compression_method_preferred.push_back(FLATE_DECODE);
- }
- }
- else if(outformat == CF_FILTER_OUT_FORMAT_PCLM && printer_attrs)
+ /* Get PCLm parameters from printer IPP attributes */
+ if (outformat == CF_FILTER_OUT_FORMAT_PCLM)
{
if (log)
{
if (log) log(ld, CF_LOGLEVEL_INFO,
"cfFilterRasterToPDF: Starting page %d.", Page);
+ // Update rendering intent with user settings or the default
+ cfGetPrintRenderIntent(data, header.cupsRenderingIntent,
+ sizeof(header.cupsRenderingIntent));
+
// Use "profile=profile_name.icc" to embed 'profile_name.icc' into the PDF
// for testing. Forces color management to enable.
if (outformat == CF_FILTER_OUT_FORMAT_PDF &&
*/
#include "filter.h"
-#include <ppd/ppd.h>
+#include "raster.h"
+#include "ipp.h"
#include <cups/raster.h>
#include <unistd.h>
#include <fcntl.h>
lineoffset; /* Offset into line */
int tmp;
unsigned char white; /* White pixel */
- /* PPD file */
- ppd_attr_t *back = NULL; /* cupsBackSide attribute */
- ppd_cache_t *cache = NULL; /* PPD cache */
- pwg_size_t *pwg_size; /* PWG media size */
- pwg_media_t *pwg_media; /* PWG media name */
- /* Number of options */
+ int back; /* Back side orientation */
+ char buf[64];
+ int width,
+ height,
+ left,
+ right,
+ bottom,
+ top;
+ int num_options = 0;/* Number of options */
cups_option_t *options = NULL;/* Options */
const char *val; /* Option value */
cf_filter_iscanceledfunc_t iscanceled = data->iscanceledfunc;
void *icd = data->iscanceleddata;
cf_logfunc_t log = data->logfunc;
void *ld = data->logdata;
- cf_filter_out_format_t output_format;
+ int res = 0;
- if (parameters)
- {
- output_format = *(cf_filter_out_format_t *)parameters;
- if (output_format == CF_FILTER_OUT_FORMAT_PWG_RASTER)
+ val = data->final_content_type;
+ if (val) {
+ if (strcasestr(val, "pwg"))
outras = cupsRasterOpen(outputfd, CUPS_RASTER_WRITE_PWG);
- else if (output_format == CF_FILTER_OUT_FORMAT_APPLE_RASTER)
+ else if (strcasestr(val, "urf"))
outras = cupsRasterOpen(outputfd, CUPS_RASTER_WRITE_APPLE);
else
{
if (log) log(ld, CF_LOGLEVEL_ERROR,
"cfFilterRasterToPWG: Invalid output format specified. Only PWG Raster and Apple Raster/URF are supported.");
+
+ close(inputfd);
+ close(outputfd);
return (1);
}
}
else
{
- if (log) log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterRasterToPWG: Output format not specified.");
- return (1);
+ if (log) log(ld, CF_LOGLEVEL_WARN,
+ "cfFilterRasterToPWG: Output format not specified, defaulting to PWG Raster.");
+
+ outras = cupsRasterOpen(outputfd, CUPS_RASTER_WRITE_PWG);
}
- inras = cupsRasterOpen(inputfd, CUPS_RASTER_READ);
+ num_options = cfJoinJobOptionsAndAttrs(data, num_options, &options);
- if (!data->ppd)
- {
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterRasterToPWG: PPD file is not specified.");
- }
- else
- {
- back = ppdFindAttr(data->ppd, "cupsBackSide", NULL);
- cache = data->ppd->cache;
- }
+ inras = cupsRasterOpen(inputfd, CUPS_RASTER_READ);
while (cupsRasterReadHeader2(inras, &inheader))
{
"cfFilterRasterToPWG: Unsupported raster data.");
if (log) log(ld, CF_LOGLEVEL_DEBUG,
"cfFilterRasterToPWG: Bad bottom/left/top margin on page %d.", page);
- return (1);
+ res = 1;
+ goto fail;
}
switch (inheader.cupsColorSpace)
if (log) log(ld,CF_LOGLEVEL_DEBUG,
"cfFilterRasterToPWG: Unsupported cupsColorSpace %d on page %d.",
inheader.cupsColorSpace, page);
- return (1);
+ res = 1;
+ goto fail;
}
if (inheader.cupsColorOrder != CUPS_ORDER_CHUNKED)
if (log) log(ld,CF_LOGLEVEL_DEBUG,
"cfFilterRasterToPWG: Unsupported cupsColorOrder %d on page %d.",
inheader.cupsColorOrder, page);
- return (1);
+ res = 1;
+ goto fail;
}
if (inheader.cupsBitsPerPixel != 1 &&
if (log) log(ld,CF_LOGLEVEL_DEBUG,
"cfFilterRasterToPWG: Unsupported cupsBitsPerColor %d on page %d.",
inheader.cupsBitsPerColor, page);
- return (1);
+ res = 1;
+ goto fail;
}
memcpy(&outheader, &inheader, sizeof(outheader));
outheader.cupsInteger[14] = 0; /* VendorIdentifier */
outheader.cupsInteger[15] = 0; /* VendorLength */
- if ((val = cupsGetOption("print-content-optimize", data->num_options,
+ if ((val = cupsGetOption("print-content-optimize", num_options,
options)) != NULL)
{
if (!strcmp(val, "automatic"))
}
if ((val = cupsGetOption("print-quality",
- data->num_options, options)) != NULL)
+ num_options, options)) != NULL)
{
unsigned quality = (unsigned)atoi(val); /* print-quality value */
}
}
- if ((val = cupsGetOption("print-rendering-intent", data->num_options,
- options)) != NULL)
- {
- if (!strcmp(val, "absolute"))
- strncpy(outheader.cupsRenderingIntent, "Absolute",
- sizeof(outheader.cupsRenderingIntent));
- else if (!strcmp(val, "automatic"))
- strncpy(outheader.cupsRenderingIntent, "Automatic",
- sizeof(outheader.cupsRenderingIntent));
- else if (!strcmp(val, "perceptual"))
- strncpy(outheader.cupsRenderingIntent, "Perceptual",
- sizeof(outheader.cupsRenderingIntent));
- else if (!strcmp(val, "relative"))
- strncpy(outheader.cupsRenderingIntent, "Relative",
- sizeof(outheader.cupsRenderingIntent));
- else if (!strcmp(val, "relative-bpc"))
- strncpy(outheader.cupsRenderingIntent, "RelativeBpc",
- sizeof(outheader.cupsRenderingIntent));
- else if (!strcmp(val, "saturation"))
- strncpy(outheader.cupsRenderingIntent, "Saturation",
- sizeof(outheader.cupsRenderingIntent));
- else
- {
- if (log) log(ld,CF_LOGLEVEL_DEBUG,
- "cfFilterRasterToPWG: Unsupported print-rendering-intent value.");
- outheader.cupsRenderingIntent[0] = '\0';
- }
- }
+ /* Update rendering intent with user settings or the default */
+ outheader.cupsRenderingIntent[0] = '\0';
+ cfGetPrintRenderIntent(data, outheader.cupsRenderingIntent,
+ sizeof(outheader.cupsRenderingIntent));
- if (inheader.cupsPageSizeName[0] &&
- (pwg_size = ppdCacheGetSize(cache,
- inheader.cupsPageSizeName)) != NULL &&
- pwg_size->map.pwg)
+ /* First try to use the input page size name for the output page,
+ check whether this size is supported by theprinter */
+ buf[0] = '\0';
+ if (inheader.cupsPageSizeName[0])
{
- strncpy(outheader.cupsPageSizeName, pwg_size->map.pwg,
- sizeof(outheader.cupsPageSizeName) - 1);
+ /* Take only a page size name for a page size the printer actually
+ supports */
+ snprintf(buf, sizeof(buf), "%.63s", inheader.cupsPageSizeName);
+ cfGenerateSizes(data->printer_attrs, CF_GEN_SIZES_SEARCH, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ buf, NULL);
}
+ if (buf[0])
+ snprintf(outheader.cupsPageSizeName,
+ sizeof(outheader.cupsPageSizeName),
+ "%.63s", buf);
else
{
- pwg_media =
- pwgMediaForSize((int)(2540.0 * inheader.cupsPageSize[0] / 72.0),
- (int)(2540.0 * inheader.cupsPageSize[1] / 72.0));
-
- if (pwg_media)
- strncpy(outheader.cupsPageSizeName, pwg_media->pwg,
- sizeof(outheader.cupsPageSizeName) - 1);
+ /* No name found, find the printer's page size by the size dimensions
+ and margins */
+ width = (int)(2540.0 * inheader.cupsPageSize[0] / 72.0);
+ height = (int)(2540.0 * inheader.cupsPageSize[1] / 72.0);
+ left = (int)(2540.0 * inheader.ImagingBoundingBox[0] / 72.0);
+ bottom = (int)(2540.0 * inheader.ImagingBoundingBox[1] / 72.0);
+ right = width - (int)(2540.0 * inheader.ImagingBoundingBox[2] / 72.0);
+ top = height - (int)(2540.0 * inheader.ImagingBoundingBox[3] / 72.0);
+ cfGenerateSizes(data->printer_attrs, CF_GEN_SIZES_SEARCH, NULL, NULL,
+ &width, &height, &left, &bottom, &right, &top,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ buf, NULL);
+ if (buf[0])
+ snprintf(outheader.cupsPageSizeName,
+ sizeof(outheader.cupsPageSizeName),
+ "%.63s", buf);
else
{
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterRasterToPWG: Unsupported PageSize %.2fx%.2f.",
+ "cfFilterRasterToPWG: Page size %.2fx%.2f not supported by printer.",
inheader.cupsPageSize[0], inheader.cupsPageSize[1]);
outheader.cupsPageSizeName[0] = '\0';
}
}
if (inheader.Duplex && !(page & 1) &&
- back && strcasecmp(back->value, "Normal"))
+ (back = cfGetBackSideOrientation(data)) > 0 &&
+ (back &= 7) != CF_BACKSIDE_NORMAL)
{
- if (strcasecmp(back->value, "Flipped"))
+ outheader.Duplex = CUPS_TRUE;
+ outheader.Tumble = inheader.Tumble;
+
+ if (back == CF_BACKSIDE_FLIPPED)
{
if (inheader.Tumble)
{
/* ImageBoxBottom */
}
}
- else if (strcasecmp(back->value, "ManualTumble"))
+ else if (back == CF_BACKSIDE_MANUAL_TUMBLE)
{
if (inheader.Tumble)
{
/* ImageBoxBottom */
}
}
- else if (strcasecmp(back->value, "Rotated"))
+ else if (back == CF_BACKSIDE_ROTATED)
{
if (inheader.Tumble)
{
*/
if (log) log(ld,CF_LOGLEVEL_DEBUG,
- "cfFilterRasterToPWG: Unsupported cupsBackSide value.");
+ "cfFilterRasterToPWG: Unsupported back side orientation value.");
outheader.cupsInteger[1] = 1; /* CrossFeedTransform */
outheader.cupsInteger[2] = 1; /* FeedTransform */
}
else
{
+ outheader.Duplex = inheader.Duplex;
+ outheader.Tumble = inheader.Tumble;
+
outheader.cupsInteger[1] = 1; /* CrossFeedTransform */
outheader.cupsInteger[2] = 1; /* FeedTransform */
"cfFilterRasterToPWG: Error sending raster data.");
if (log) log(ld,CF_LOGLEVEL_DEBUG,
"cfFilterRasterToPWG: Unable to write header for page %d.", page);
- return (1);
+ res = 1;
+ goto fail;
}
/*
if (log) log(ld,CF_LOGLEVEL_DEBUG,
"cfFilterRasterToPWG: Unable to write line %d for page %d.",
page_top - y + 1, page);
- return (1);
+ res = 1;
+ goto fail;
}
for (y = inheader.cupsHeight; y > 0; y --)
if (log) log(ld,CF_LOGLEVEL_DEBUG,
"cfFilterRasterToPWG: Unable to read line %d for page %d.",
inheader.cupsHeight - y + page_top + 1, page);
- return (1);
+ res = 1;
+ goto fail;
}
if (!cupsRasterWritePixels(outras, line, outheader.cupsBytesPerLine))
if (log) log(ld,CF_LOGLEVEL_DEBUG,
"cfFilterRasterToPWG: Unable to write line %d for page %d.",
inheader.cupsHeight - y + page_top + 1, page);
- return (1);
+ res = 1;
+ goto fail;
}
}
"cfFilterRasterToPWG: Unable to write line %d for page %d.",
page_bottom - y + page_top + inheader.cupsHeight + 1,
page);
- return (1);
+ res = 1;
+ goto fail;
}
free(line);
}
+ fail:
+
cupsRasterClose(inras);
close(inputfd);
cupsRasterClose(outras);
close(outputfd);
- return (0);
+ cupsFreeOptions(num_options, options);
+
+ return (res);
}
* cfRGBDelete() - Delete a color separation.
* cfRGBDoGray() - Do a grayscale separation...
* cfRGBDoRGB() - Do a RGB separation...
- * cfRGBLoad() - Load a RGB color profile from a PPD file.
* cfRGBNew() - Create a new RGB color separation.
*/
}
-/*
- * 'cfRGBLoad()' - Load a RGB color profile from a PPD file.
- */
-
-cf_rgb_t * /* O - New color profile */
-cfRGBLoad(ppd_file_t *ppd, /* I - PPD file */
- const char *colormodel, /* I - Color model */
- const char *media, /* I - Media type */
- const char *resolution, /* I - Resolution */
- cf_logfunc_t log, /* I - Log function */
- void *ld) /* I - Log function data */
-{
- int i, /* Looping var */
- cube_size, /* Size of color lookup cube */
- num_channels, /* Number of color channels */
- num_samples; /* Number of color samples */
- cf_sample_t *samples; /* Color samples */
- float values[7]; /* Color sample values */
- char spec[PPD_MAX_NAME]; /* Profile name */
- ppd_attr_t *attr; /* Attribute from PPD file */
- cf_rgb_t *rgbptr; /* RGB color profile */
-
-
- /*
- * Find the following attributes:
- *
- * cupsRGBProfile - Specifies the cube size, number of channels, and
- * number of samples
- * cupsRGBSample - Specifies an RGB to CMYK color sample
- */
-
- if ((attr = cfFindAttr(ppd, "cupsRGBProfile", colormodel, media,
- resolution, spec, sizeof(spec), log, ld)) == NULL)
- {
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "No cupsRGBProfile attribute found for the current settings!");
- return (NULL);
- }
-
- if (!attr->value || sscanf(attr->value, "%d%d%d", &cube_size, &num_channels,
- &num_samples) != 3)
- {
- if (log) log(ld, CF_LOGLEVEL_ERROR,
- "Bad cupsRGBProfile attribute \'%s\'!",
- attr->value ? attr->value : "(null)");
- return (NULL);
- }
-
- if (cube_size < 2 || cube_size > 16 ||
- num_channels < 1 || num_channels > CF_MAX_RGB ||
- num_samples != (cube_size * cube_size * cube_size))
- {
- if (log) log(ld, CF_LOGLEVEL_ERROR,
- "Bad cupsRGBProfile attribute \'%s\'!",
- attr->value);
- return (NULL);
- }
-
- /*
- * Allocate memory for the samples and read them...
- */
-
- if ((samples = calloc(num_samples, sizeof(cf_sample_t))) == NULL)
- {
- if (log) log(ld, CF_LOGLEVEL_ERROR,
- "Unable to allocate memory for RGB profile!");
- return (NULL);
- }
-
- /*
- * Read all of the samples...
- */
-
- for (i = 0; i < num_samples; i ++)
- if ((attr = ppdFindNextAttr(ppd, "cupsRGBSample", spec)) == NULL)
- break;
- else if (!attr->value)
- {
- if (log) log(ld, CF_LOGLEVEL_ERROR,
- "Bad cupsRGBSample value!");
- break;
- }
- else if (sscanf(attr->value, "%f%f%f%f%f%f%f", values + 0,
- values + 1, values + 2, values + 3, values + 4, values + 5,
- values + 6) != (3 + num_channels))
- {
- if (log) log(ld, CF_LOGLEVEL_ERROR,
- "Bad cupsRGBSample value!");
- break;
- }
- else
- {
- samples[i].rgb[0] = (int)(255.0 * values[0] + 0.5);
- samples[i].rgb[1] = (int)(255.0 * values[1] + 0.5);
- samples[i].rgb[2] = (int)(255.0 * values[2] + 0.5);
- samples[i].colors[0] = (int)(255.0 * values[3] + 0.5);
- if (num_channels > 1)
- samples[i].colors[1] = (int)(255.0 * values[4] + 0.5);
- if (num_channels > 2)
- samples[i].colors[2] = (int)(255.0 * values[5] + 0.5);
- if (num_channels > 3)
- samples[i].colors[3] = (int)(255.0 * values[6] + 0.5);
- }
-
- /*
- * If everything went OK, create the color profile...
- */
-
- if (i == num_samples)
- rgbptr = cfRGBNew(num_samples, samples, cube_size, num_channels);
- else
- rgbptr = NULL;
-
- /*
- * Free the temporary sample array and return...
- */
-
- free(samples);
-
- return (rgbptr);
-}
-
-
/*
* 'cfRGBNew()' - Create a new RGB color separation.
*/
#include <config.h>
#include <string.h>
#include <ctype.h>
+#include <stdio.h>
#ifdef WIN32
# include <io.h>
#else
cups_page_header2_t h; /* CUPS Raster page header, to */
/* accommodate results of command */
- /* line parsing for PPD-less queue */
+ /* line/IPP attribute parsing */
cf_filter_texttopdf_parameter_t env_vars;
int NumKeywords;
float PageLeft, /* Left margin */
static void write_pretty_header();
static int write_prolog(const char *title, const char *user,
const char *classification, const char *label,
- ppd_file_t *ppd, texttopdf_doc_t *doc,
+ texttopdf_doc_t *doc,
cf_logfunc_t log, void *ld);
static void write_page(texttopdf_doc_t *doc);
static void write_epilogue(texttopdf_doc_t *doc);
int stdoutbackupfd; /* The "real" stdout is backupped here while */
/* stdout is redirected */
int ret = 0; /* Return value */
+ cups_cspace_t cspace = (cups_cspace_t)(-1);
/*
* Process command-line options and write the prolog...
*/
- if (data->ppd)
- {
- ppdMarkOptions(data->ppd, data->num_options, data->options);
- }
-
if ((val = cupsGetOption("prettyprint",
data->num_options, data->options)) != NULL &&
strcasecmp(val, "no") && strcasecmp(val, "off") &&
}
}
- cfFilterSetCommonOptions(data->ppd, data->num_options, data->options, 1,
- &(doc.Orientation), &(doc.Duplex),
- &(doc.LanguageLevel), &(doc.ColorDevice),
- &(doc.PageLeft), &(doc.PageRight), &(doc.PageTop),
- &(doc.PageBottom), &(doc.PageWidth), &(doc.PageLength),
- log, ld);
-
- if (!data->ppd) {
- cfRasterParseIPPOptions(&(doc.h), data, 0, 1);
- doc.Orientation = doc.h.Orientation;
- doc.Duplex = doc.h.Duplex;
- doc.ColorDevice = doc.h.cupsNumColors <= 1 ? 0 : 1;
- doc.PageWidth = doc.h.cupsPageSize[0] != 0.0 ? doc.h.cupsPageSize[0] :
- (float)doc.h.PageSize[0];
- doc.PageLength = doc.h.cupsPageSize[1] != 0.0 ? doc.h.cupsPageSize[1] :
- (float)doc.h.PageSize[1];
- doc.PageLeft = doc.h.cupsImagingBBox[0] != 0.0 ? doc.h.cupsImagingBBox[0] :
- (float)doc.h.ImagingBoundingBox[0];
- doc.PageBottom = doc.h.cupsImagingBBox[1] != 0.0 ?
- doc.h.cupsImagingBBox[1] : (float)doc.h.ImagingBoundingBox[1];
- doc.PageRight = doc.h.cupsImagingBBox[2] != 0.0 ? doc.h.cupsImagingBBox[2] :
- (float)doc.h.ImagingBoundingBox[2];
- doc.PageTop = doc.h.cupsImagingBBox[3] != 0.0 ? doc.h.cupsImagingBBox[3] :
- (float)doc.h.ImagingBoundingBox[3];
- doc.Copies = doc.h.NumCopies;
+ cfRasterPrepareHeader(&(doc.h), data, CF_FILTER_OUT_FORMAT_CUPS_RASTER,
+ CF_FILTER_OUT_FORMAT_CUPS_RASTER, 0, &cspace);
+ doc.Orientation = doc.h.Orientation;
+ doc.Duplex = doc.h.Duplex;
+ doc.ColorDevice = doc.h.cupsNumColors <= 1 ? 0 : 1;
+ doc.PageWidth = doc.h.cupsPageSize[0] != 0.0 ? doc.h.cupsPageSize[0] :
+ (float)doc.h.PageSize[0];
+ doc.PageLength = doc.h.cupsPageSize[1] != 0.0 ? doc.h.cupsPageSize[1] :
+ (float)doc.h.PageSize[1];
+ doc.PageLeft = doc.h.cupsImagingBBox[0] != 0.0 ? doc.h.cupsImagingBBox[0] :
+ (float)doc.h.ImagingBoundingBox[0];
+ doc.PageBottom = doc.h.cupsImagingBBox[1] != 0.0 ?
+ doc.h.cupsImagingBBox[1] : (float)doc.h.ImagingBoundingBox[1];
+ doc.PageRight = doc.h.cupsImagingBBox[2] != 0.0 ? doc.h.cupsImagingBBox[2] :
+ (float)doc.h.ImagingBoundingBox[2];
+ doc.PageTop = doc.h.cupsImagingBBox[3] != 0.0 ? doc.h.cupsImagingBBox[3] :
+ (float)doc.h.ImagingBoundingBox[3];
+ doc.Copies = doc.h.NumCopies;
+
+ /* Check whether we do borderless printing with overspray and let text only
+ get printed on the actual media size */
+ if (doc.h.cupsPageSizeName[0] != '\0')
+ {
+ /* The page size name in te header corresponds to the actual size of
+ the media, so find the size dimensions */
+ pwg_media_t *size_found = NULL;
+ strncpy(keyword, doc.h.cupsPageSizeName, sizeof(keyword));
+ if ((keyptr = strchr(keyword, '.')) != NULL)
+ *keyptr = '\0';
+ if ((size_found = pwgMediaForPPD(keyword)) != NULL ||
+ (size_found = pwgMediaForLegacy(keyword)) != NULL ||
+ (size_found = pwgMediaForPWG(keyword)) != NULL)
+ {
+ /* Dimensions in PostScript points */
+ float w = size_found->width / 2540.0 * 72.0;
+ float l = size_found->length / 2540.0 * 72.0;
+ if (w < doc.PageWidth)
+ {
+ /* Width in header > actual media width => overspray */
+ /* As the overspray is to cover tolerances in paper traction
+ and the paper can be mis-aligned to any size, we let
+ margins be at least double the overspray width on each
+ side (not dividing by 2) */
+ float margin_needed = doc.PageWidth - w;
+ if (doc.PageLeft < margin_needed)
+ doc.PageLeft = margin_needed;
+ if (doc.PageWidth - doc.PageRight < margin_needed)
+ doc.PageRight = doc.PageWidth - margin_needed;
+ }
+ if (l < doc.PageLength)
+ {
+ /* Length in header > actual media length => overspray */
+ /* As the overspray is to cover tolerances in paper traction
+ and the paper can be mis-aligned to any size, we let
+ margins be at least double the overspray width on each
+ side (not dividing by 2) */
+ float margin_needed = doc.PageLength - l;
+ if (doc.PageBottom < margin_needed)
+ doc.PageBottom = margin_needed;
+ if (doc.PageLength - doc.PageTop < margin_needed)
+ doc.PageTop = doc.PageLength - margin_needed;
+ }
+ }
}
if ((val = cupsGetOption("wrap", data->num_options, data->options)) == NULL)
doc.env_vars.classification,
cupsGetOption("page-label", data->num_options,
data->options),
- data->ppd, &doc, log, ld);
+ &doc, log, ld);
if (ret)
goto out;
}
(doc->NumPages)++;
if (doc->PrettyPrint)
- write_pretty_header(doc->pdf);
+ write_pretty_header(doc);
for (line = 0; line < doc->SizeLines; line ++)
write_line(line, doc->Page[line], doc);
const char *user, /* I - Username */
const char *classification, /* I - Classification */
const char *label, /* I - Page label */
- ppd_file_t *ppd, /* I - PPD file info */
texttopdf_doc_t *doc,
cf_logfunc_t log,
void *ld)
* texttotext
*
* Filter to print text files on text-only printers. The filter has
- * several configuration options controlled by a PPD file so that it
- * should work with most printer models.
+ * several configuration options so that it should work with most
+ * printer models.
*
* Copyright 2007-2011 by Apple Inc.
* Copyright 1997-2006 by Easy Software Products.
#include <config.h>
#include <cups/cups.h>
-#include <ppd/ppd.h>
#include <cups/file.h>
#include <signal.h>
#include <sys/wait.h>
#include <ctype.h>
#include <iconv.h>
#include <cupsfilters/image-private.h>
+#include "ipp.h"
#include "filter.h"
/*
int exit_status = 0; /* Exit status */
int fd; /* Copy file descriptor */
- char buffer[8192]; /* Copy buffer */
int num_copies; /* Number of copies */
- ppd_file_t *ppd; /* PPD file */
int num_options; /* Number of options */
cups_option_t *options; /* Options */
- const char *val, *val2; /* Option value */
- ppd_attr_t *ppd_attr; /* Attribute taken from the PPD */
+ const char *val; /* Option value */
int num_lines = 66, /* Lines per page */
num_columns = 80; /* Characters per line */
int page_left = 0, /* Page margins */
page_right = 0,
page_top = 0,
page_bottom = 0,
- num_lines_per_inch = 6,
- num_chars_per_inch = 10;
+ num_lines_per_inch = 0,
+ num_chars_per_inch = 0;
int text_width, /* Width of the text area on the page */
text_height; /* Height of the text area on the
page */
empty (no visible characters)? */
int previous_is_cr; /* Is the previous character processed
a Carriage Return? */
+ int new_line_started = 0; /* Is the proceeding of starting a
+ new line (left margin, new page's
+ top margin, wrapped word) already
+ done for this line? */
int skip_rest_of_line = 0; /* Are we truncating an overlong
line? */
int skip_spaces = 0; /* Are we skipping spaces at a line
int num_pages = 0; /* Number of pages which get actually
printed */
- ipp_t *printer_attrs = NULL;
- ipp_t *job_attrs = NULL;
+ ipp_t *printer_attrs = data->printer_attrs;
+ ipp_t *job_attrs = data->job_attrs;
ipp_attribute_t *ipp;
- ipp_t *defsize;
+ ipp_t *media_col_entry;
+ float paperdimensions[2];
char buf[2048];
cf_logfunc_t log = data->logfunc;
num_copies = 1;
/*
- * Get the options from the fifth command line argument
+ * Parse the options and IPP attributes
*/
num_options = data->num_options;
-
- /*
- * Load the PPD file and mark options...
- */
-
- ppd = data->ppd;
options = data->options;
- if (ppd)
- {
- ppdMarkOptions(ppd, num_options, options);
- }
- /*
- * Parse the options
- */
-
- /* Default page size attributes as per printer attributes */
- defsize = ippGetCollection(ippFindAttribute(printer_attrs,
- "media-col-default", IPP_TAG_ZERO), 0);
-
- if((val = cupsGetOption("NumLinesPerInch", num_options, options))!= NULL ||
- (ipp = ippFindAttribute(job_attrs,"num-lines-per-inch", IPP_TAG_INTEGER)) != NULL ||
- (ipp = ippFindAttribute(printer_attrs,"num-lines-per-inch-default", IPP_TAG_INTEGER)) != NULL ||
- (ppd_attr = ppdFindAttr(ppd, "DefaultNumLinesPerInch",NULL))!=NULL){
- if(val == NULL && ipp!=NULL){
- ippAttributeString(ipp, buf, sizeof(buf));
- val = buf;
- }
- if(val == NULL){
- val = ppd_attr->value;
- }
+ /* Number of lines and columns per inch This is mainly for
+ development and debugging. With these set and the page size given
+ as width and length dimension, the number of lines and columns on
+ the page gets calculated. A way for using custom sizes. With
+ these not set, the media-col-database entry for the page size is
+ looked up and if it has the extra integer entries "num-lines" and
+ "num-columns", the numbers here are used. */
+ if ((val = cupsGetOption("NumLinesPerInch",
+ num_options, options)) != NULL ||
+ (val = cupsGetOption("num-lines-per-inch",
+ num_options, options)) != NULL ||
+ (ipp = ippFindAttribute(job_attrs, "num-lines-per-inch",
+ IPP_TAG_INTEGER)) != NULL ||
+ (ipp = ippFindAttribute(printer_attrs, "num-lines-per-inch-default",
+ IPP_TAG_INTEGER)) != NULL)
+ {
+ if (val == NULL)
+ {
+ ippAttributeString(ipp, buf, sizeof(buf));
+ val = buf;
+ }
+ if (val && val[0])
num_lines_per_inch = atoi(val);
+ if (log)
+ {
+ if (num_lines_per_inch <= 0)
+ log(ld, CF_LOGLEVEL_DEBUG,
+ "cfFilterTextToText: Number of lines per inch not set, if page dimensions are given, find number of lines per page via pre-defined page sizes");
+ else
+ log(ld, CF_LOGLEVEL_DEBUG,
+ "cfFilterTextToText: Number of lines per inch: %d",
+ num_lines_per_inch);
}
+ }
- if((val = cupsGetOption("NumCharsPerInch", num_options, options))!= NULL ||
- (ipp = ippFindAttribute(job_attrs,"num-chars-per-inch", IPP_TAG_INTEGER)) != NULL ||
- (ipp = ippFindAttribute(printer_attrs,"num-chars-per-inch-default", IPP_TAG_INTEGER)) != NULL ||
- (ppd_attr = ppdFindAttr(ppd, "DefautlNumCharsPerInch", NULL))!=NULL){
- if(val == NULL && ipp!=NULL){
- ippAttributeString(ipp, buf, sizeof(buf));
- val = buf;
- }
- if(val == NULL){
- val = ppd_attr->value;
- }
- num_chars_per_inch = atoi(val);
- }
- if(log) log(ld, CF_LOGLEVEL_DEBUG,"cfFilterTextToText: num of lines per inch = %d",num_lines_per_inch);
- if(log) log(ld, CF_LOGLEVEL_DEBUG,"cfFilterTextToText: num of chars per inch = %d",num_chars_per_inch);
-
- /* With the "PageSize"/"PageRegion" options we only determine the number
- of lines and columns of a page, we do not use the geometry defined by
- "PaperDimension" and "ImageableArea" in the PPD */
- if ((val = cupsGetOption("PageSize", num_options, options)) != NULL ||
- (val = cupsGetOption("PageRegion", num_options, options)) != NULL ||
- (ipp = ippFindAttribute(job_attrs, "page-size", IPP_TAG_ZERO ))!=NULL ||
- (ipp = ippFindAttribute(job_attrs, "page-region", IPP_TAG_ZERO))!=NULL||
- (ppd_attr = ppdFindAttr(ppd, "DefaultPageSize", NULL)) != NULL ||
- (ppd_attr = ppdFindAttr(ppd, "DefaultPageRegion", NULL)) != NULL) {
- if (val == NULL && ipp!=NULL){
+ if ((val = cupsGetOption("NumCharsPerInch",
+ num_options, options)) != NULL ||
+ (val = cupsGetOption("num-chars-per-inch",
+ num_options, options)) != NULL ||
+ (ipp = ippFindAttribute(job_attrs,"num-chars-per-inch",
+ IPP_TAG_INTEGER)) != NULL ||
+ (ipp = ippFindAttribute(printer_attrs, "num-chars-per-inch-default",
+ IPP_TAG_INTEGER)) != NULL)
+ {
+ if (val == NULL)
+ {
ippAttributeString(ipp, buf, sizeof(buf));
val = buf;
}
- if(val==NULL)
- val = ppd_attr->value;
-
- if(log) log(ld, CF_LOGLEVEL_DEBUG,"cfFilterTextToText: PageSize: %s", val);
- snprintf(buffer, sizeof(buffer), "Default%sNumLines", val);
- if ((val2 = cupsGetOption(buffer + 7, num_options, options)) != NULL ||
- (ipp = ippFindAttribute(job_attrs, buffer+7, IPP_TAG_ZERO))!= NULL ||
- (ipp = ippFindAttribute(printer_attrs, buffer, IPP_TAG_ZERO))!=NULL ||
- (ppd_attr = ppdFindAttr(ppd, buffer, NULL)) != NULL) {
- char buf2[2048];
- if (val2 == NULL && ipp!=NULL){
- ippAttributeString(ipp, buf2, sizeof(buf2));
- val2 = buf2;
- }
- if(val2==NULL)
- val2 = ppd_attr->value;
- if (!strncasecmp(val2, "Custom.", 7))
- val2 += 7;
- num_lines = atoi(val2);
- }
- snprintf(buffer, sizeof(buffer), "Default%sNumColumns", val);
- if ((val2 = cupsGetOption(buffer + 7, num_options, options)) != NULL ||
- (ipp = ippFindAttribute(job_attrs, buffer+7, IPP_TAG_ZERO))!=NULL ||
- (ipp = ippFindAttribute(printer_attrs, buffer, IPP_TAG_ZERO))!=NULL ||
- (ppd_attr = ppdFindAttr(ppd, buffer, NULL))!=NULL) {
- char buf2[2048];
- if (val2 == NULL && ipp!=NULL){
- ippAttributeString(ipp, buf2, sizeof(buf2));
- val2 = buf2;
- }
-if(val2==NULL)
- val2 = ppd_attr->value;
- if (!strncasecmp(val2, "Custom.", 7))
- val2 += 7;
- num_columns = atoi(val2);
- }
- if (num_lines <= 0) {
- if(log) log(ld, CF_LOGLEVEL_DEBUG,"cfFilterTextToText: Invalid number of lines %d, using default: 66",
- num_lines);
- num_lines = 66;
- }
- if (num_columns <= 0) {
- if(log) log(ld, CF_LOGLEVEL_DEBUG,"cfFilterTextToText: Invalid number of columns %d, using default: 80",
- num_columns);
- num_columns = 80;
+ if (val && val[0])
+ num_chars_per_inch = atoi(val);
+ if (log)
+ {
+ if (num_chars_per_inch <= 0)
+ log(ld, CF_LOGLEVEL_DEBUG,
+ "cfFilterTextToText: Number of charcters per inch not set, if page dimensions are given, find number of characters per line via pre-defined page sizes");
+ else
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "cfFilterTextToText: Number of characters per inch = %d",
+ num_chars_per_inch);
}
}
- else if((ipp = ippFindAttribute(defsize, "media-size", IPP_TAG_ZERO))!= NULL){
- ipp_t *media_size = ippGetCollection(ipp, 0);
- int x_dim = ippGetInteger(ippFindAttribute(media_size, "x-dimension", IPP_TAG_ZERO),0);
- int y_dim = ippGetInteger(ippFindAttribute(media_size, "y-dimension", IPP_TAG_ZERO),0);
- num_lines = (int)((y_dim/72.0)*(num_lines_per_inch)); /* Since y_dim and x_dim are in points,
- divide them by 72 to convert in inch */
- num_columns = (int)((x_dim/72.0)*(num_chars_per_inch));
- }
- else if((ipp = ippFindAttribute(printer_attrs, "media-default", IPP_TAG_ZERO))!=NULL){
- pwg_media_t *pwg = pwgMediaForPWG(ippGetString(ipp, 0, NULL));
- int x_dim = pwg->width;
- int y_dim = pwg->length;
- num_lines = (int)((y_dim/72.0)*(num_lines_per_inch));
- num_columns = (int)((x_dim/72.0)*(num_chars_per_inch));
+
+ cfGetPageDimensions(printer_attrs, job_attrs, num_options, options,
+ NULL, 0,
+ &(paperdimensions[0]), &(paperdimensions[1]),
+ NULL, NULL, NULL, NULL, NULL, &media_col_entry);
+ if (media_col_entry)
+ {
+ /* We have a media-col-database and the requested/default page size
+ is contained in it (= size is supported), check whether we have
+ a number of lines/columns registered via extra interger entries
+ "num-columns" and "num-lines". */
+ num_columns = ippGetInteger(ippFindAttribute(media_col_entry,
+ "num-columns",
+ IPP_TAG_ZERO), 0);
+ num_lines = ippGetInteger(ippFindAttribute(media_col_entry,
+ "num-lines",
+ IPP_TAG_ZERO), 0);
}
+
+ if (num_chars_per_inch > 0 && paperdimensions[0] > 0)
+ num_columns = (int)((paperdimensions[0] / 72.0) * (num_chars_per_inch));
+ if (num_lines_per_inch > 0 && paperdimensions[1] > 0)
+ num_lines = (int)((paperdimensions[1] / 72.0) * (num_lines_per_inch));
+
if (num_lines <= 0) {
if(log) log(ld, CF_LOGLEVEL_DEBUG,"cfFilterTextToText: Invalid number of lines %d, using default: 66",
num_lines);
/* Direct specification of number of lines/columns, mainly for debugging
and development */
- if ((val = cupsGetOption("page-height", num_options, options)) != NULL ||
+ if ((val = cupsGetOption("PageHeight", num_options, options)) != NULL ||
+ (val = cupsGetOption("page-height", num_options, options)) != NULL ||
(ipp = ippFindAttribute(job_attrs, "page-height", IPP_TAG_INTEGER))!=NULL) {
if(val == NULL){
ippAttributeString(ipp, buf, sizeof(buf));
if(log) log(ld, CF_LOGLEVEL_DEBUG, "cfFilterTextToText: Invalid number of lines %d, using default value: %d",
i, num_lines);
}
- if ((val = cupsGetOption("page-width", num_options, options)) != NULL ||
+ if ((val = cupsGetOption("PageWidth", num_options, options)) != NULL ||
+ (val = cupsGetOption("page-width", num_options, options)) != NULL ||
(ipp = ippFindAttribute(job_attrs, "page-width", IPP_TAG_INTEGER))!=NULL) {
if(val == NULL){
ippAttributeString(ipp, buf, sizeof(buf));
if(log) log(ld, CF_LOGLEVEL_DEBUG, "cfFilterTextToText: Lines per page: %d; Characters per line: %d",
num_lines, num_columns);
- if ((val = cupsGetOption("page-left", num_options, options)) != NULL ||
- (ipp = ippFindAttribute(job_attrs, "page-left", IPP_TAG_INTEGER))!=NULL ||
- (ppd_attr = ppdFindAttr(ppd, "Defaultpage-left", NULL)) != NULL ||
- (ipp = ippFindAttribute(defsize, "media-left-margin", IPP_TAG_INTEGER))!=NULL) {
- if (val == NULL && ipp!=NULL){
+ if ((val = cupsGetOption("PageLeft",
+ num_options, options)) != NULL ||
+ (val = cupsGetOption("page-left",
+ num_options, options)) != NULL ||
+ (ipp = ippFindAttribute(job_attrs, "page-left",
+ IPP_TAG_INTEGER)) != NULL ||
+ (ipp = ippFindAttribute(printer_attrs, "page-left-default",
+ IPP_TAG_INTEGER)) != NULL)
+ {
+ if (val == NULL)
+ {
ippAttributeString(ipp, buf, sizeof(buf));
val = buf;
}
- if(val == NULL && ppd_attr!=NULL)
- val = ppd_attr->value;
- if (!strncasecmp(val, "Custom.", 7))
- val += 7;
- page_left = atoi(val);
- if (page_left < 0 || page_left > num_columns - 1) {
- if(log) log(ld, CF_LOGLEVEL_DEBUG, "cfFilterTextToText: Invalid left margin %d, setting to 0",
- page_left);
- page_left = 0;
+ if (val && val[0])
+ {
+ if (!strncasecmp(val, "Custom", 6))
+ val += 7;
+ page_left = atoi(val);
+ }
+ if (log)
+ {
+ if (page_left < 0 || page_left > num_columns - 1)
+ {
+ log(ld, CF_LOGLEVEL_DEBUG,
+ "cfFilterTextToText: Left margin not set or invalid, use 0 columns");
+ page_left = 0;
+ }
+ else
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "cfFilterTextToText: Left margin: %d columns",
+ page_left);
}
}
- if ((val = cupsGetOption("page-right", num_options, options)) != NULL ||
- (ipp = ippFindAttribute(job_attrs, "page-right", IPP_TAG_INTEGER))!=NULL ||
- (ppd_attr = ppdFindAttr(ppd, "Defaultpage-right", NULL)) != NULL ||
- (ipp = ippFindAttribute(defsize, "media-right-margin", IPP_TAG_INTEGER))!=NULL) {
- if (val == NULL && ipp!=NULL){
+
+ if ((val = cupsGetOption("PageRight",
+ num_options, options)) != NULL ||
+ (val = cupsGetOption("page-right",
+ num_options, options)) != NULL ||
+ (ipp = ippFindAttribute(job_attrs, "page-right",
+ IPP_TAG_INTEGER)) != NULL ||
+ (ipp = ippFindAttribute(printer_attrs, "page-right-default",
+ IPP_TAG_INTEGER)) != NULL)
+ {
+ if (val == NULL)
+ {
ippAttributeString(ipp, buf, sizeof(buf));
val = buf;
}
- if(val == NULL && ppd_attr!=NULL)
- val = ppd_attr->value;
- if (!strncasecmp(val, "Custom.", 7))
- val += 7;
- page_right = atoi(val);
- if (page_right < 0 || page_right > num_columns - page_left - 1) {
- if(log) log(ld, CF_LOGLEVEL_DEBUG, "cfFilterTextToText: Invalid right margin %d, setting to 0",
- page_right);
- page_right = 0;
+ if (val && val[0])
+ {
+ if (!strncasecmp(val, "Custom", 6))
+ val += 7;
+ page_right = atoi(val);
+ }
+ if (log)
+ {
+ if (page_right < 0 || page_right > num_columns - 1)
+ {
+ log(ld, CF_LOGLEVEL_DEBUG,
+ "cfFilterTextToText: Right margin not set or invalid, use 0 columns");
+ page_right = 0;
+ }
+ else
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "cfFilterTextToText: Right margin: %d columns",
+ page_right);
}
}
- if ((val = cupsGetOption("page-top", num_options, options)) != NULL ||
- (ipp = ippFindAttribute(job_attrs,"page-top", IPP_TAG_INTEGER))!=NULL ||
- (ppd_attr = ppdFindAttr(ppd, "Defaultpage-top", NULL)) != NULL ||
- (ipp = ippFindAttribute(defsize, "media-top-margin", IPP_TAG_INTEGER))!=NULL) {
- if (val == NULL && ipp!=NULL){
+
+ if ((val = cupsGetOption("PageTop",
+ num_options, options)) != NULL ||
+ (val = cupsGetOption("page-top",
+ num_options, options)) != NULL ||
+ (ipp = ippFindAttribute(job_attrs, "page-top",
+ IPP_TAG_INTEGER)) != NULL ||
+ (ipp = ippFindAttribute(printer_attrs, "page-top-default",
+ IPP_TAG_INTEGER)) != NULL)
+ {
+ if (val == NULL)
+ {
ippAttributeString(ipp, buf, sizeof(buf));
val = buf;
}
- if(val == NULL && ppd_attr!=NULL)
- val = ppd_attr->value;
-
- if (!strncasecmp(val, "Custom.", 7))
- val += 7;
- page_top = atoi(val);
- if (page_top < 0 || page_top > num_lines - 1) {
- if(log) log(ld, CF_LOGLEVEL_DEBUG, "cfFilterTextToText: Invalid top margin %d, setting to 0",
- page_top);
- page_top = 0;
+ if (val && val[0])
+ {
+ if (!strncasecmp(val, "Custom", 6))
+ val += 7;
+ page_top = atoi(val);
+ }
+ if (log)
+ {
+ if (page_top < 0 || page_top > num_lines - 1)
+ {
+ log(ld, CF_LOGLEVEL_DEBUG,
+ "cfFilterTextToText: Top margin not set or invalid, use 0 lines");
+ page_top = 0;
+ }
+ else
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "cfFilterTextToText: Top margin: %d lines",
+ page_top);
}
}
- if ((val = cupsGetOption("page-bottom", num_options, options)) != NULL ||
- (ipp = ippFindAttribute(job_attrs,"page-bottom",IPP_TAG_INTEGER))!=NULL ||
- (ppd_attr = ppdFindAttr(ppd, "Defaultpage-bottom", NULL)) != NULL ||
- (ipp = ippFindAttribute(defsize, "media-bottom-margin", IPP_TAG_INTEGER))!=NULL) {
- if (val == NULL && ipp!=NULL){
+
+ if ((val = cupsGetOption("PageBottom",
+ num_options, options)) != NULL ||
+ (val = cupsGetOption("page-bottom",
+ num_options, options)) != NULL ||
+ (ipp = ippFindAttribute(job_attrs, "page-bottom",
+ IPP_TAG_INTEGER)) != NULL ||
+ (ipp = ippFindAttribute(printer_attrs, "page-bottom-default",
+ IPP_TAG_INTEGER)) != NULL)
+ {
+ if (val == NULL)
+ {
ippAttributeString(ipp, buf, sizeof(buf));
val = buf;
}
- if(val==NULL && ppd_attr!=NULL)
- val = ppd_attr->value;
- if (!strncasecmp(val, "Custom.", 7))
- val += 7;
- page_bottom = atoi(val);
- if (page_bottom < 0 || page_bottom > num_lines - page_top - 1) {
- if(log) log(ld, CF_LOGLEVEL_DEBUG, "cfFilterTextToText: Invalid bottom margin %d, setting to 0",
- page_bottom);
- page_bottom = 0;
+ if (val && val[0])
+ {
+ if (!strncasecmp(val, "Custom", 6))
+ val += 7;
+ page_bottom = atoi(val);
+ }
+ if (log)
+ {
+ if (page_bottom < 0 || page_bottom > num_lines - 1)
+ {
+ log(ld, CF_LOGLEVEL_DEBUG,
+ "cfFilterTextToText: Bottom margin not set or invalid, use 0 lines");
+ page_bottom = 0;
+ }
+ else
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "cfFilterTextToText: Bottom margin: %d lines",
+ page_bottom);
}
}
- if(log) log(ld, CF_LOGLEVEL_DEBUG, "cfFilterTextToText: Margins: Left (Columns): %d; Right (Columns): %d; Top (Lines): %d; Bottom (Lines): %d",
- page_left, page_right, page_top, page_bottom);
+
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "cfFilterTextToText: Margins: Left (Columns): %d; Right (Columns): %d; Top (Lines): %d; Bottom (Lines): %d",
+ page_left, page_right, page_top, page_bottom);
text_width = num_columns - page_left - page_right;
text_height = num_lines - page_top - page_bottom;
text_height, text_width);
strcpy(encoding, "ASCII//IGNORE");
- if ((val = cupsGetOption("PrinterEncoding", num_options, options)) != NULL ||
- (ipp = ippFindAttribute(job_attrs, "printer-encoding", IPP_TAG_ZERO))!=NULL ||
- (ppd_attr = ppdFindAttr(ppd, "DefaultPrinterEncoding", NULL)) != NULL ||
- (ipp = ippFindAttribute(printer_attrs, "printer-encoding-default", IPP_TAG_ZERO))!= NULL) {
- if (val == NULL && ipp!=NULL){
+ if ((val = cupsGetOption("PrinterEncoding",
+ num_options, options)) != NULL ||
+ (val = cupsGetOption("printer-encoding",
+ num_options, options)) != NULL ||
+ (ipp = ippFindAttribute(job_attrs, "printer-encoding",
+ IPP_TAG_ZERO)) != NULL ||
+ (ipp = ippFindAttribute(printer_attrs, "printer-encoding-default",
+ IPP_TAG_ZERO)) != NULL)
+ {
+ if (val == NULL)
+ {
ippAttributeString(ipp, buf, sizeof(buf));
val = buf;
}
- if(val == NULL && ppd_attr!=NULL)
- val = ppd_attr->value;
- if (!strncasecmp(val, "Custom.", 7))
- val += 7;
- if (val[0] != '\0') {
- snprintf(encoding, sizeof(encoding), "%.55s//IGNORE", val);
- for (p = encoding; *p; p ++)
- *p = toupper(*p);
+ if (val && val[0])
+ {
+ if (!strncasecmp(val, "Custom", 6))
+ val += 7;
+ if (val[0] != '\0')
+ {
+ snprintf(encoding, sizeof(encoding), "%.55s//IGNORE", val);
+ for (p = encoding; *p; p ++)
+ *p = toupper(*p);
+ }
}
}
- if(log) log(ld, CF_LOGLEVEL_DEBUG, "cfFilterTextToText: Output encoding: %s", encoding);
-
- if ((val = cupsGetOption("OverlongLines", num_options, options)) != NULL ||
- (ipp = ippFindAttribute(job_attrs, "overlong-lines", IPP_TAG_ENUM))!=NULL ||
- (ipp = ippFindAttribute(printer_attrs, "overlong-lines-default", IPP_TAG_ENUM))!=NULL ||
- (ppd_attr = ppdFindAttr(ppd, "DefaultOverlongLines", NULL)) != NULL) {
- if (val == NULL && ipp!=NULL){
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "cfFilterTextToText: Output encoding: %s", encoding);
+
+ if ((val = cupsGetOption("OverLongLines",
+ num_options, options)) != NULL ||
+ (val = cupsGetOption("over-long-lines",
+ num_options, options)) != NULL ||
+ (ipp = ippFindAttribute(job_attrs, "over-long-lines",
+ IPP_TAG_ZERO)) != NULL ||
+ (ipp = ippFindAttribute(printer_attrs, "over-long-lines-default",
+ IPP_TAG_ZERO)) != NULL)
+ {
+ if (val == NULL)
+ {
ippAttributeString(ipp, buf, sizeof(buf));
val = buf;
}
- if(val == NULL)
- val = ppd_attr->value;
- if (!strcasecmp(val, "Truncate"))
+ if (!strcasecmp(val, "truncate"))
overlong_lines = TRUNCATE;
- else if (!strcasecmp(val, "WordWrap"))
+ else if (!strcasecmp(val, "word-wrap") ||
+ !strcasecmp(val, "WordWrap"))
overlong_lines = WORDWRAP;
- else if (!strcasecmp(val, "WrapAtWidth"))
+ else if (!strcasecmp(val, "wrap-at-width") ||
+ !strcasecmp(val, "WrapAtWidth"))
overlong_lines = WRAPATWIDTH;
else
- if(log) log(ld, CF_LOGLEVEL_DEBUG, "cfFilterTextToText: Invalid value for OverlongLines: %s, using default value",
- val);
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "cfFilterTextToText: Invalid value for over-long-lines: %s, using default value",
+ val);
}
- if(log) log(ld, CF_LOGLEVEL_DEBUG, "cfFilterTextToText: Handling of overlong lines: %s",
- (overlong_lines == TRUNCATE ? "Truncate at maximum width" :
- (overlong_lines == WORDWRAP ? "Word-wrap" :
- "Wrap exactly at maximum width")));
-
- if ((val = cupsGetOption("TabWidth", num_options, options)) != NULL ||
- (ipp = ippFindAttribute(job_attrs,"tab-width", IPP_TAG_INTEGER))!=NULL ||
- (ipp = ippFindAttribute(printer_attrs,"tab-width-default", IPP_TAG_INTEGER ))!=NULL ||
- (ppd_attr = ppdFindAttr(ppd, "DefaultTabWidth", NULL)) != NULL) {
- if (val == NULL && ipp!=NULL){
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "cfFilterTextToText: Handling of overlong lines: %s",
+ (overlong_lines == TRUNCATE ? "Truncate at maximum width" :
+ (overlong_lines == WORDWRAP ? "Word-wrap" :
+ "Wrap exactly at maximum width")));
+
+ if ((val = cupsGetOption("TabWidth",
+ num_options, options)) != NULL ||
+ (val = cupsGetOption("tab-width",
+ num_options, options)) != NULL ||
+ (ipp = ippFindAttribute(job_attrs, "tab-width",
+ IPP_TAG_INTEGER)) != NULL ||
+ (ipp = ippFindAttribute(printer_attrs, "tab-width-default",
+ IPP_TAG_INTEGER)) != NULL)
+ {
+ if (val == NULL)
+ {
ippAttributeString(ipp, buf, sizeof(buf));
val = buf;
}
- if(val == NULL && ppd_attr!=NULL)
- val = ppd_attr->value;
- if (!strncasecmp(val, "Custom.", 7))
- val += 7;
- i = atoi(val);
- if (i > 0)
- tab_width = i;
- else
- if(log) log(ld, CF_LOGLEVEL_DEBUG, "cfFilterTextToText: Invalid tab width %d, using default value: %d",
- i, tab_width);
+ if (val && val[0])
+ {
+ if (!strncasecmp(val, "Custom", 6))
+ val += 7;
+ tab_width = atoi(val);
+ }
+ if (log)
+ {
+ if (tab_width <= 0 || tab_width > num_columns - 1)
+ log(ld, CF_LOGLEVEL_DEBUG,
+ "cfFilterTextToText: Tab width not set or invalid, use default");
+ else
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "cfFilterTextToText: Tab width: %d columns",
+ tab_width);
+ }
}
- if(log) log(ld, CF_LOGLEVEL_DEBUG, "cfFilterTextToText: Tab width: %d", tab_width);
-
- if ((val = cupsGetOption("Pagination", num_options, options)) != NULL ||
- (ipp = ippFindAttribute(job_attrs, "pagination", IPP_TAG_BOOLEAN))!=NULL ||
- (ipp = ippFindAttribute(printer_attrs, "pagination-default", IPP_TAG_BOOLEAN))!=NULL ||
- (ppd_attr = ppdFindAttr(ppd, "DefaultPagination", NULL)) != NULL) {
- if (val == NULL && ipp!=NULL){
- ippAttributeString(ipp, buf,sizeof(buf));
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "cfFilterTextToText: Tab width: %d", tab_width);
+
+ if ((val = cupsGetOption("Pagination",
+ num_options, options)) != NULL ||
+ (val = cupsGetOption("pagination",
+ num_options, options)) != NULL ||
+ (ipp = ippFindAttribute(job_attrs, "pagination",
+ IPP_TAG_ZERO)) != NULL ||
+ (ipp = ippFindAttribute(printer_attrs, "pagination-default",
+ IPP_TAG_ZERO)) != NULL)
+ {
+ if (val == NULL)
+ {
+ ippAttributeString(ipp, buf, sizeof(buf));
val = buf;
}
- if(val == NULL && ppd_attr!=NULL)
- val = ppd_attr->value;
if (is_true(val))
pagination = 1;
else if (is_false(val))
pagination = 0;
else
- if(log) log(ld, CF_LOGLEVEL_DEBUG, "cfFilterTextToText: Invalid value for Pagination: %s, using default value",
- val);
+ if(log) log(ld, CF_LOGLEVEL_DEBUG,
+ "cfFilterTextToText: Invalid value for pagination: %s, using default value",
+ val);
}
- if(log) log(ld, CF_LOGLEVEL_DEBUG, "cfFilterTextToText: Pagination (Print in defined pages): %s",
- (pagination ? "Yes" : "No"));
-
- if ((val = cupsGetOption("SendFF", num_options, options)) != NULL ||
- (ipp = ippFindAttribute(job_attrs, "sendff", IPP_TAG_BOOLEAN))!=NULL ||
- (ipp = ippFindAttribute(printer_attrs, "sendff-default", IPP_TAG_BOOLEAN))!=NULL ||
- (ppd_attr = ppdFindAttr(ppd, "DefaultSendFF", NULL)) != NULL) {
- if (val == NULL && ipp!=NULL){
+ if(log) log(ld, CF_LOGLEVEL_DEBUG,
+ "cfFilterTextToText: Pagination (Print in defined pages): %s",
+ (pagination ? "Yes" : "No"));
+
+ if ((val = cupsGetOption("SendFF",
+ num_options, options)) != NULL ||
+ (val = cupsGetOption("send-ff",
+ num_options, options)) != NULL ||
+ (ipp = ippFindAttribute(job_attrs, "send-ff",
+ IPP_TAG_ZERO)) != NULL ||
+ (ipp = ippFindAttribute(printer_attrs, "send-ff-default",
+ IPP_TAG_ZERO)) != NULL)
+ {
+ if (val == NULL)
+ {
ippAttributeString(ipp, buf, sizeof(buf));
val = buf;
}
- if(val==NULL && ppd_attr!=NULL)
- val = ppd_attr->value;
if (is_true(val))
send_ff = 1;
else if (is_false(val))
send_ff = 0;
else
- if(log) log(ld, CF_LOGLEVEL_DEBUG, "cfFilterTextToText: Invalid value for SendFF: %s, using default value",
- val);
+ if(log) log(ld, CF_LOGLEVEL_DEBUG,
+ "cfFilterTextToText: Invalid value for send-ff: %s, using default value",
+ val);
}
- if(log) log(ld, CF_LOGLEVEL_DEBUG, "cfFilterTextToText: Send Form Feed character at end of page: %s",
- (send_ff ? "Yes" : "No"));
-
- if ((val = cupsGetOption("NewlineCharacters", num_options, options)) !=
- NULL ||
- (ipp = ippFindAttribute(job_attrs, "newline-characters", IPP_TAG_ENUM))!=NULL ||
- (ipp = ippFindAttribute(printer_attrs, "newline-characters-default", IPP_TAG_ENUM))!=NULL ||
- (ppd_attr = ppdFindAttr(ppd, "DefaultNewlineCharacters", NULL)) != NULL) {
- if (val == NULL && ipp!=NULL){
+ if(log) log(ld, CF_LOGLEVEL_DEBUG,
+ "cfFilterTextToText: Send Form Feed character at end of page: %s",
+ (send_ff ? "Yes" : "No"));
+
+ if ((val = cupsGetOption("NewlineCharacters",
+ num_options, options)) != NULL ||
+ (val = cupsGetOption("newline-characters",
+ num_options, options)) != NULL ||
+ (ipp = ippFindAttribute(job_attrs, "newline-characters",
+ IPP_TAG_ZERO)) != NULL ||
+ (ipp = ippFindAttribute(printer_attrs, "newline-characters-default",
+ IPP_TAG_ZERO)) != NULL)
+ {
+ if (val == NULL)
+ {
ippAttributeString(ipp, buf, sizeof(buf));
val = buf;
}
- if(val == NULL && ppd_attr!=NULL)
- val = ppd_attr->value;
- if (!strcasecmp(val, "LF"))
+ if (!strcasecmp(val, "lf"))
newline_char = LF;
- else if (!strcasecmp(val, "CR"))
+ else if (!strcasecmp(val, "cr"))
newline_char = CR;
- else if (!strcasecmp(val, "CRLF"))
+ else if (!strcasecmp(val, "crlf"))
newline_char = CRLF;
else
- if(log) log(ld, CF_LOGLEVEL_DEBUG, "cfFilterTextToText: Invalid value for NewlineCharacters: %s, using default value",
- val);
+ if(log) log(ld, CF_LOGLEVEL_DEBUG,
+ "cfFilterTextToText: Invalid value for newline-characters: %s, using default value",
+ val);
}
- if(log) log(ld, CF_LOGLEVEL_DEBUG, "cfFilterTextToText: Characters sent to make printer start a new line: %s",
- (newline_char == LF ? "Line Feed (LF)" :
- (newline_char == CR ? "Carriage Return (CR)" :
- "Carriage Return (CR) and Line Feed (LF)")));
+ if(log) log(ld, CF_LOGLEVEL_DEBUG,
+ "cfFilterTextToText: Characters sent to make printer start a new line: %s",
+ (newline_char == LF ? "Line Feed (LF)" :
+ (newline_char == CR ? "Carriage Return (CR)" :
+ "Carriage Return (CR) and Line Feed (LF)")));
if ((val = cupsGetOption("page-ranges", num_options, options)) !=
NULL ||
(odd_pages ? "only the odd pages" :
"no pages")));
- if ((val = cupsGetOption("output-order", num_options, options)) !=
+ if ((val = cupsGetOption("OutputOrder", num_options, options)) !=
+ NULL ||
+ (val = cupsGetOption("output-order", num_options, options)) !=
NULL ||
(ipp = ippFindAttribute(job_attrs,"output-order", IPP_TAG_ZERO))!=NULL) {
if(val == NULL){
else if (newline_char == CRLF)
newline_char_str = "\r\n";
- /* Size of the output page in bytes (only 1-byte-per-character supported)
+ /* Size of the output page in bytes (up to 4-byte-per-character)
in the worst case, no blank lines at top and bottom, no blank right
margin, 2 characters for newline (CR + LF) plus form feed plus closing
zero */
- page_size = (num_columns + 2) * num_lines + 2;
+ page_size = ((num_columns + 2) * num_lines + 2) * 4;
/* Allocate output page buffer */
out_page = calloc(page_size, sizeof(char));
page_array = cupsArrayNew(NULL, NULL);
}
- /* Main loop for readin the input file, converting the encoding, formatting
+ /* Main loop for reading the input file, converting the encoding, formatting
the output, and printing the pages */
destptr = out_page;
page_empty = 1;
column = 0;
previous_is_cr = 0;
insize = 0;
+ new_line_started = 0;
do {
/* Reset input pointer */
inptr = inbuf;
if (insize > 0) { /* Do we have data to convert? */
/* Do the conversion. */
nconv = iconv (cd, &inptr, &insize, &outptr, &outsize);
- if (nconv == (size_t) -1) {
+ if (log && nconv == (size_t) -1)
+ log(ld, CF_LOGLEVEL_DEBUG,
+ "cfFilterTextToText: iconv() message: %s", strerror(errno));
+ if (nconv == (size_t) -1 && insize > 0) {
/* Not everything went right. It might only be
an unfinished byte sequence at the end of the
- buffer. Or it is a real problem. */
+ output buffer. Or it is a real problem. */
if (errno == EINVAL || errno == E2BIG) {
/* This is harmless. Simply move the unused
bytes to the beginning of the buffer so that
/* Position cursor in next line */
line ++;
column = 0;
+ new_line_started = 0;
}
}
if ((line >= text_height && /* Current page is full */
/* Log the page output (only once, when printing the first buffer
load) */
if (num_pages == 1)
- {
- if(log) log(ld, CF_LOGLEVEL_INFO, "cfFilterTextToText: 1 1");
- }
+ {
+ if(log) log(ld, CF_LOGLEVEL_CONTROL, "PAGE: 1 1");
+ }
+ cupsFilePuts(outputfp, out_page);
} else if ((num_copies == 1 || !collate) && !reverse_order) {
/* Log the page output */
- if(log) log(ld, CF_LOGLEVEL_INFO, "cfFilterTextToText: %d %d", num_pages, num_copies);
+ if(log) log(ld, CF_LOGLEVEL_CONTROL, "PAGE: %d %d", num_pages, num_copies);
+ cupsFilePuts(outputfp, out_page);
} else {
/* Save the page in the page array */
cupsArrayAdd(page_array, strdup(out_page));
page_empty = 1;
line = 0;
column = 0;
+ new_line_started = 0;
page ++;
}
if (outbuf[0] == '\0') /* End of input file */
break;
- if (column == 0) { /* Start of new line */
+ if (column == 0 && !new_line_started) { /* Start of new line */
+ new_line_started = 1;
if (line == 0 && pagination) /* Start of new page */
for (i = 0; i < page_top; i ++)
for (j = 0; newline_char_str[j]; j ++)
/* Position cursor in next line */
line ++;
column = 0;
+ new_line_started = 0;
/* Finished truncating an overlong line */
skip_rest_of_line = 0;
skip_spaces = 0;
for (j = 0; newline_char_str[j]; j ++)
*(destptr ++) = newline_char_str[j];
column = 0;
+ new_line_started = 0;
/* Finished truncating an overlong line */
skip_rest_of_line = 0;
skip_spaces = 0;
}
}
}
- cupsFilePuts(outputfp, out_page);
} while (outbuf[0] != '\0'); /* End of input file */
close(fd);
#include <ctype.h>
#include <limits.h>
#include <cups/cups.h>
-#include <ppd/ppd.h>
int /* O - Error status */
cfFilterUniversal(int inputfd, /* I - File descriptor input stream */
char output_type[256];
cf_filter_out_format_t *outformat;
cf_filter_filter_in_chain_t *filter, *next;
- cf_filter_universal_parameter_t universal_parameters;
- ppd_file_t *ppd;
- ppd_cache_t *cache;
+ cf_filter_universal_parameter_t *universal_parameters;
cf_logfunc_t log = data->logfunc;
void *ld = data->logdata;
int ret = 0;
- universal_parameters = *(cf_filter_universal_parameter_t *)parameters;
- input = universal_parameters.input_format;
+ universal_parameters = (cf_filter_universal_parameter_t *)parameters;
+ input = data->content_type;
if (input == NULL)
{
if (log) log(ld, CF_LOGLEVEL_ERROR,
"cfFilterUniversal: No input data format supplied.");
return (1);
}
- final_output = universal_parameters.output_format;
- if (final_output == NULL)
- {
- if (log) log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterUniversal: No output data format supplied.");
- return (1);
- }
- strncpy(output, final_output, sizeof(output) - 1);
- ppd = data->ppd;
- cache = ppd ? ppd->cache : NULL;
-
- /* Check whether our output format (under CUPS it is taken from the
- FINAL_CONTENT_TYPE env variable) is the destination format (2nd
- word) of a "*cupsFilter2: ..." line (string has 4 words), in this
- case the specified filter (4th word) does the last step,
- converting from the input format (1st word) of the line to the
- destination format and so we only need to convert to the input
- format. In this case we need to correct our output format.
-
- If there is more than one line with the given output format and
- an inpout format we can produce, we select the one with the
- lowest cost value (3rd word) as this is the one which CUPS should have
- chosen for this job.
-
- If we have "*cupsFilter: ..." lines (without "2", string with 3
- words) we do not need to do anything special, as the input format
- specified is the FIMAL_CONTENT_TYPE which CUPS supplies to us and
- into which we have to convert. So we quit parsing if the first
- line has only 3 words, as if CUPS uses the "*cupsFilter: ..."
- lines only if there is no "*cupsFilter2: ..." line min the PPD,
- so if we encounter a line with only 3 words the other lines will
- have only 3 words, too and nothing has to be done. */
-
- if (ppd && ppd->num_filters && cache)
+ final_output = data->final_content_type;
+ if (final_output == NULL)
{
- int lowest_cost = INT_MAX;
- char *filter;
-
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterUniversal: \"*cupsFilter(2): ...\" lines in the PPD file:");
-
- for (filter = (char *)cupsArrayFirst(cache->filters);
- filter;
- filter = (char *)cupsArrayNext(cache->filters))
+ final_output = universal_parameters->actual_output_type;
+ if (final_output == NULL)
{
- char buf[256];
- char *ptr,
- *in = NULL,
- *out = NULL,
- *coststr = NULL;
- int cost;
-
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterUniversal: %s", filter);
-
- /* String of the "*cupsfilter:" or "*cupsfilter2:" line */
- strncpy(buf, filter, sizeof(buf) - 1);
-
- /* Separate the words */
- in = ptr = buf;
- while (*ptr && !isspace(*ptr)) ptr ++;
- if (!*ptr) goto error;
- *ptr = '\0';
- ptr ++;
- while (*ptr && isspace(*ptr)) ptr ++;
- if (!*ptr) goto error;
- out = ptr;
- while (*ptr && !isspace(*ptr)) ptr ++;
- if (!*ptr) goto error;
- *ptr = '\0';
- ptr ++;
- while (*ptr && isspace(*ptr)) ptr ++;
- if (!*ptr) goto error;
- coststr = ptr;
- if (!isdigit(*ptr)) goto error;
- while (*ptr && !isspace(*ptr)) ptr ++;
- if (!*ptr) goto error;
- *ptr = '\0';
- ptr ++;
- while (*ptr && isspace(*ptr)) ptr ++;
- if (!*ptr) goto error;
- cost = atoi(coststr);
-
- /* Valid "*cupsFilter2: ..." line ... */
- if (/* Must be of lower cost than what we selected before */
- cost < lowest_cost &&
- /* Must have our FINAL_CONTENT_TYPE as output */
- strcasecmp(out, final_output) == 0 &&
- /* Must have as input a format we are able to produce */
- (strcasecmp(in, "application/vnd.cups-raster") == 0 ||
- strcasecmp(in, "application/vnd.cups-pdf") == 0 ||
- strcasecmp(in, "application/vnd.cups-postscript") == 0 ||
- strcasecmp(in, "application/pdf") == 0 ||
- strcasecmp(in, "image/pwg-raster") == 0 ||
- strcasecmp(in, "image/urf") == 0 ||
- strcasecmp(in, "application/PCLm") == 0 ||
- strcasecmp(in, "application/postscript") == 0))
- {
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterUniversal: --> Selecting this line");
- /* Take the input format of the line as output format for us */
- strncpy(output, in, sizeof(output));
- /* Update the minimum cost found */
- lowest_cost = cost;
- /* We cannot find a "better" solution ... */
- if (lowest_cost == 0)
- {
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterUniversal: Cost value is down to zero, stopping reading further lines");
- break;
- }
- }
-
- continue;
-
- error:
- if (lowest_cost == INT_MAX && coststr)
- {
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterUniversal: PPD uses \"*cupsFilter: ...\" lines, so we always convert to format given by FINAL_CONTENT_TYPE");
- break;
- }
if (log) log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterUniversal: Invalid \"*cupsFilter2: ...\" line in PPD: %s",
- filter);
+ "cfFilterUniversal: No output data format supplied.");
+ return (1);
}
-
}
- if (strcasecmp(output, final_output) != 0)
- {
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterUniversal: Converting from %s to %s, final output will be %s",
- input, output, final_output);
- }
+ if (universal_parameters->actual_output_type)
+ strncpy(output, universal_parameters->actual_output_type,
+ sizeof(output) - 1);
else
- {
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterUniversal: Converting from %s to %s", input, output);
- }
+ strncpy(output, data->final_content_type, sizeof(output) - 1);
+
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "cfFilterUniversal: Converting from %s to %s", input, output);
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "cfFilterUniversal: Final output format for job: %s",
+ final_output);
sscanf(input, "%15[^/]/%255s", input_super, input_type);
sscanf(output, "%15[^/]/%255s", output_super, output_type);
(!strcmp(input_super, "application") && input_type[0] == 'x'))
{
filter = malloc(sizeof(cf_filter_filter_in_chain_t));
- cf_filter_texttopdf_parameter_t* parameters =
+ cf_filter_texttopdf_parameter_t* tparameters =
(cf_filter_texttopdf_parameter_t *) malloc(sizeof(cf_filter_texttopdf_parameter_t));
- *parameters = universal_parameters.texttopdf_params;
+ *tparameters = universal_parameters->texttopdf_params;
filter->function = cfFilterTextToPDF;
- filter->parameters = parameters;
+ filter->parameters = tparameters;
filter->name = "texttopdf";
cupsArrayAdd(filter_chain, filter);
if (log) log(ld, CF_LOGLEVEL_DEBUG,
"cfFilterUniversal: Adding %s to chain",
filter->name);
}
- else if(!strcmp(output, "application/postscript") ||
- !strcmp(output, "application/vnd.cups-postscript"))
- {
- filter = malloc(sizeof(cf_filter_filter_in_chain_t));
- filter->function = cfFilterPDFToPS;
- filter->parameters = NULL;
- filter->name = "pdftops";
- if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterUniversal: Adding %s to chain", filter->name);
- cupsArrayAdd(filter_chain, filter);
- }
else
{
// Output format is not PDF and unknown -> Error
*/
#include <cupsfilters/filter.h>
+#include <ppd/ppd-filter.h>
#include <config.h>
#include <signal.h>
#endif /* HAVE_SIGSET */
/*
- * Fire up the cfFilterPDFToRaster() filter function
+ * Fire up the ppdFilterPDFToRaster() filter function
*/
char buf[1024];
datadir = CUPS_DATADIR;
snprintf(buf, sizeof(buf), "%s/data", datadir);
- ret = cfFilterCUPSWrapper(argc, argv, cfFilterBannerToPDF, buf, &JobCanceled);
+ ret = ppdFilterCUPSWrapper(argc, argv, cfFilterBannerToPDF, buf,
+ &JobCanceled);
if (ret)
fprintf(stderr, "ERROR: bannertopdf filter function failed.\n");
#include <cups/cups.h>
#include <ppd/ppd.h>
#include <cupsfilters/driver.h>
+#include <cupsfilters/image.h>
+#include "escp.h"
#include <string.h>
#include <ctype.h>
-#include "escp.h"
/*
#include <cups/cups.h>
#include <ppd/ppd.h>
#include <cupsfilters/driver.h>
+#include <cupsfilters/image.h>
+#include "pcl.h"
#include <string.h>
#include <ctype.h>
-#include "pcl.h"
/*
_log("INFO: Using qualifer: '%s.%s.%s'\n",
qualifier[0], qualifier[1], qualifier[2]);
- cfCmGetPrinterIccProfile(data, (char **)&icc_profile, 0);
-
/* fall back to PPD */
if (icc_profile == NULL) {
_log("INFO: need to look in PPD for matching qualifer\n");
*/
#include <cupsfilters/filter.h>
+#include <ppd/ppd-filter.h>
#include <signal.h>
#endif /* HAVE_SIGSET */
/*
- * Fire up the cfFilterGhostscript() filter function.
+ * Fire up the ppdFilterGhostscript() filter function.
*/
cf_filter_out_format_t outformat = CF_FILTER_OUT_FORMAT_PDF;
- ret = cfFilterCUPSWrapper(argc, argv, cfFilterGhostscript, &outformat,
- &JobCanceled);
+ ret = ppdFilterCUPSWrapper(argc, argv, cfFilterGhostscript, &outformat,
+ &JobCanceled);
if (ret)
fprintf(stderr, "ERROR: gstopdf filter failed.\n");
*/
#include <cupsfilters/filter.h>
+#include <ppd/ppd-filter.h>
#include <signal.h>
#endif /* HAVE_SIGSET */
/*
- * Fire up the cfFilterGhostscript() filter function.
+ * Fire up the ppdFilterGhostscript() filter function.
*/
cf_filter_out_format_t outformat = CF_FILTER_OUT_FORMAT_PXL;
- ret = cfFilterCUPSWrapper(argc, argv, cfFilterGhostscript, &outformat,
- &JobCanceled);
+ ret = ppdFilterCUPSWrapper(argc, argv, cfFilterGhostscript, &outformat,
+ &JobCanceled);
if (ret)
fprintf(stderr, "ERROR: gstopxl filter failed.\n");
*/
#include <cupsfilters/filter.h>
+#include <ppd/ppd-filter.h>
#include <signal.h>
#endif /* HAVE_SIGSET */
/*
- * Fire up the cfFilterGhostscript() filter function.
+ * Fire up the ppdFilterGhostscript() filter function.
*/
- cf_filter_out_format_t outformat = CF_FILTER_OUT_FORMAT_CUPS_RASTER;
- char *t = getenv("FINAL_CONTENT_TYPE");
- if (t) {
- if (strcasestr(t, "pwg"))
- outformat = CF_FILTER_OUT_FORMAT_PWG_RASTER;
- else if (strcasestr(t, "urf"))
- outformat = CF_FILTER_OUT_FORMAT_APPLE_RASTER;
- else if (strcasestr(t, "pclm"))
- outformat = CF_FILTER_OUT_FORMAT_PCLM;
- }
-
- ret = cfFilterCUPSWrapper(argc, argv, cfFilterGhostscript, &outformat,
- &JobCanceled);
+ ret = ppdFilterCUPSWrapper(argc, argv, cfFilterGhostscript, NULL,
+ &JobCanceled);
if (ret)
fprintf(stderr, "ERROR: gstoraster filter failed.\n");
*/
#include <cupsfilters/filter.h>
+#include <ppd/ppd-filter.h>
#include <signal.h>
#endif /* HAVE_SIGSET */
/*
- * Fire up the cfFilterImageToPDF() filter function
+ * Fire up the ppdFilterImageToPDF() filter function
*/
- ret = cfFilterCUPSWrapper(argc, argv, cfFilterImageToPDF, NULL, &JobCanceled);
+ ret = ppdFilterCUPSWrapper(argc, argv, ppdFilterImageToPDF, NULL,
+ &JobCanceled);
if (ret)
fprintf(stderr, "ERROR: imagetopdf filter function failed.\n");
*/
#include <cupsfilters/filter.h>
+#include <ppd/ppd-filter.h>
#include <signal.h>
* Fire up the cfFilterImageToPS() filter function
*/
- ret = cfFilterCUPSWrapper(argc, argv, cfFilterImageToPS, NULL, &JobCanceled);
+ ret = ppdFilterCUPSWrapper(argc, argv, ppdFilterImageToPS, NULL, &JobCanceled);
if (ret)
fprintf(stderr, "ERROR: imagetops filter function failed.\n");
*/
#include <cupsfilters/filter.h>
+#include <ppd/ppd-filter.h>
#include <signal.h>
#endif /* HAVE_SIGSET */
/*
- * Fire up the cfFilterImageToRaster() filter function
+ * Fire up the ppdFilterImageToRaster() filter function
*/
- cf_filter_out_format_t outformat = CF_FILTER_OUT_FORMAT_CUPS_RASTER;
- char *t = getenv("FINAL_CONTENT_TYPE");
- if (t) {
- if (strcasestr(t, "pwg"))
- outformat = CF_FILTER_OUT_FORMAT_PWG_RASTER;
- else if (strcasestr(t, "urf"))
- outformat = CF_FILTER_OUT_FORMAT_APPLE_RASTER;
- else if (strcasestr(t, "pclm"))
- outformat = CF_FILTER_OUT_FORMAT_PCLM;
- }
-
- ret = cfFilterCUPSWrapper(argc, argv, cfFilterImageToRaster, &outformat, &JobCanceled);
+ ret = ppdFilterCUPSWrapper(argc, argv, cfFilterImageToRaster, NULL, &JobCanceled);
if (ret)
fprintf(stderr, "ERROR: imagetoraster filter function failed.\n");
*/
#include <cupsfilters/filter.h>
+#include <ppd/ppd-filter.h>
#include <signal.h>
/*
#endif /* HAVE_SIGSET */
/*
- * Fire up the cfFilterMuPDFToPWG() filter function
+ * Fire up the ppdFilterMuPDFToPWG() filter function
*/
- cf_filter_out_format_t outformat = CF_FILTER_OUT_FORMAT_CUPS_RASTER;
- char *t = getenv("FINAL_CONTENT_TYPE");
- if (t) {
- if (strcasestr(t, "pwg"))
- outformat = CF_FILTER_OUT_FORMAT_PWG_RASTER;
- else if (strcasestr(t, "urf"))
- outformat = CF_FILTER_OUT_FORMAT_APPLE_RASTER;
- else if (strcasestr(t, "pclm"))
- outformat = CF_FILTER_OUT_FORMAT_PCLM;
- }
-
- ret = cfFilterCUPSWrapper(argc, argv, cfFilterMuPDFToPWG, &outformat, &JobCanceled);
+ ret = ppdFilterCUPSWrapper(argc, argv, cfFilterMuPDFToPWG, NULL, &JobCanceled);
if (ret)
fprintf(stderr, "ERROR: mupdftopwg filter function failed.\n");
*/
#include <cupsfilters/driver.h>
+#include <ppd/ppd.h>
+#include <ppd/ppd-filter.h>
#include "pcl-common.h"
#include <math.h>
* Include necessary headers...
*/
+#include <ppd/ppd.h>
#include <string.h>
#include <ctype.h>
#include "pcl.h"
*/
#include <cupsfilters/filter.h>
+#include <ppd/ppd-filter.h>
/*
* Local globals...
outformat = CF_FILTER_OUT_FORMAT_CUPS_RASTER;
}
- ret = cfFilterCUPSWrapper(argc, argv, cfFilterPCLmToRaster, &outformat, &JobCanceled);
+ ret = ppdFilterCUPSWrapper(argc, argv, cfFilterPCLmToRaster, &outformat, &JobCanceled);
if (ret)
fprintf(stderr, "ERROR: pclmtoraster filter function failed.\n");
/*
* Include necessary headers...
*/
+
#include <cupsfilters/filter.h>
+#include <ppd/ppd-filter.h>
#include <signal.h>
#else
signal(SIGTERM, cancel_job);
#endif /* HAVE_SIGSET */
- char *t = getenv("FINAL_CONTENT_TYPE");
- ret = cfFilterCUPSWrapper(argc, argv, cfFilterPDFToPDF, t, &JobCanceled);
+
+ /*
+ * Fire up the ppdFilterPDFToPDF() filter function
+ */
+
+ ret = ppdFilterCUPSWrapper(argc, argv, ppdFilterPDFToPDF, NULL, &JobCanceled);
+
if (ret)
fprintf(stderr, "ERROR: pdftopdf filter function failed.\n");
*/
#include <cupsfilters/filter.h>
+#include <ppd/ppd-filter.h>
#include <signal.h>
* Fire up the cfFilterPSToPS() filter function
*/
- ret = cfFilterCUPSWrapper(argc, argv, cfFilterPDFToPS, NULL, &JobCanceled);
+ ret = ppdFilterCUPSWrapper(argc, argv, ppdFilterPDFToPS, NULL, &JobCanceled);
if (ret)
fprintf(stderr, "ERROR: pdftops filter function failed.\n");
*/
#include <cupsfilters/filter.h>
+#include <ppd/ppd-filter.h>
#include <signal.h>
/*
#endif /* HAVE_SIGSET */
/*
- * Fire up the cfFilterPDFToRaster() filter function
+ * Fire up the ppdFilterPDFToRaster() filter function
*/
- cf_filter_out_format_t outformat = CF_FILTER_OUT_FORMAT_CUPS_RASTER;
- char *t = getenv("FINAL_CONTENT_TYPE");
- if (t) {
- if (strcasestr(t, "pwg"))
- outformat = CF_FILTER_OUT_FORMAT_PWG_RASTER;
- else if (strcasestr(t, "cups"))
- outformat = CF_FILTER_OUT_FORMAT_CUPS_RASTER;
- else if (strcasestr(t, "urf"))
- outformat = CF_FILTER_OUT_FORMAT_APPLE_RASTER;
- else if (strcasestr(t, "pclm"))
- outformat = CF_FILTER_OUT_FORMAT_PCLM;
- }
-
- ret = cfFilterCUPSWrapper(argc, argv, cfFilterPDFToRaster, &outformat, &JobCanceled);
+ ret = ppdFilterCUPSWrapper(argc, argv, cfFilterPDFToRaster, NULL, &JobCanceled);
if (ret)
fprintf(stderr, "ERROR: pdftoraster filter function failed.\n");
*/
#include <cupsfilters/filter.h>
+#include <ppd/ppd-filter.h>
#include <signal.h>
* Fire up the cfFilterPSToPS() filter function
*/
- ret = cfFilterCUPSWrapper(argc, argv, cfFilterPSToPS, NULL, &JobCanceled);
+ ret = ppdFilterCUPSWrapper(argc, argv, ppdFilterPSToPS, NULL, &JobCanceled);
if (ret)
fprintf(stderr, "ERROR: pstops filter function failed.\n");
*/
#include <cupsfilters/filter.h>
+#include <ppd/ppd-filter.h>
#include <signal.h>
/*
#endif /* HAVE_SIGSET */
/*
- * Fire up the cfFilterPDFToRaster() filter function
+ * Fire up the ppdFilterPWGToRaster() filter function
*/
- cf_filter_out_format_t outformat = CF_FILTER_OUT_FORMAT_CUPS_RASTER;
- char *t = getenv("FINAL_CONTENT_TYPE");
- if (t) {
- if (strcasestr(t, "pwg"))
- outformat = CF_FILTER_OUT_FORMAT_PWG_RASTER;
- else if (strcasestr(t, "urf"))
- outformat = CF_FILTER_OUT_FORMAT_APPLE_RASTER;
- else if (strcasestr(t, "pclm"))
- outformat = CF_FILTER_OUT_FORMAT_PCLM;
- }
-
- ret = cfFilterCUPSWrapper(argc, argv, cfFilterPWGToRaster, &outformat, &JobCanceled);
+ ret = ppdFilterCUPSWrapper(argc, argv, cfFilterPWGToRaster, NULL, &JobCanceled);
if (ret)
fprintf(stderr, "ERROR: pwgtoraster filter function failed.\n");
*/
#include <cupsfilters/driver.h>
+#include <ppd/ppd.h>
#include "escp.h"
#include <signal.h>
#include <string.h>
if (header->cupsColorSpace == CUPS_CSPACE_RGB ||
header->cupsColorSpace == CUPS_CSPACE_W)
- RGB = cfRGBLoad(ppd, colormodel, header->MediaType, resolution,
- logfunc, ld);
+ RGB = ppdRGBLoad(ppd, colormodel, header->MediaType, resolution,
+ logfunc, ld);
else
RGB = NULL;
- CMYK = cfCMYKLoad(ppd, colormodel, header->MediaType, resolution,
- logfunc, ld);
+ CMYK = ppdCMYKLoad(ppd, colormodel, header->MediaType, resolution,
+ logfunc, ld);
if (RGB)
fputs("DEBUG: Loaded RGB separation from PPD.\n", stderr);
switch (PrinterPlanes)
{
case 1 : /* K */
- DitherLuts[0] = cfLutLoad(ppd, colormodel, header->MediaType,
+ DitherLuts[0] = ppdLutLoad(ppd, colormodel, header->MediaType,
resolution, "Black", logfunc, ld);
break;
case 2 : /* Kk */
- DitherLuts[0] = cfLutLoad(ppd, colormodel, header->MediaType,
+ DitherLuts[0] = ppdLutLoad(ppd, colormodel, header->MediaType,
resolution, "Black", logfunc, ld);
- DitherLuts[1] = cfLutLoad(ppd, colormodel, header->MediaType,
+ DitherLuts[1] = ppdLutLoad(ppd, colormodel, header->MediaType,
resolution, "LightBlack", logfunc, ld);
break;
case 3 : /* CMY */
- DitherLuts[0] = cfLutLoad(ppd, colormodel, header->MediaType,
+ DitherLuts[0] = ppdLutLoad(ppd, colormodel, header->MediaType,
resolution, "Cyan", logfunc, ld);
- DitherLuts[1] = cfLutLoad(ppd, colormodel, header->MediaType,
+ DitherLuts[1] = ppdLutLoad(ppd, colormodel, header->MediaType,
resolution, "Magenta", logfunc, ld);
- DitherLuts[2] = cfLutLoad(ppd, colormodel, header->MediaType,
+ DitherLuts[2] = ppdLutLoad(ppd, colormodel, header->MediaType,
resolution, "Yellow", logfunc, ld);
break;
case 4 : /* CMYK */
- DitherLuts[0] = cfLutLoad(ppd, colormodel, header->MediaType,
+ DitherLuts[0] = ppdLutLoad(ppd, colormodel, header->MediaType,
resolution, "Cyan", logfunc, ld);
- DitherLuts[1] = cfLutLoad(ppd, colormodel, header->MediaType,
+ DitherLuts[1] = ppdLutLoad(ppd, colormodel, header->MediaType,
resolution, "Magenta", logfunc, ld);
- DitherLuts[2] = cfLutLoad(ppd, colormodel, header->MediaType,
+ DitherLuts[2] = ppdLutLoad(ppd, colormodel, header->MediaType,
resolution, "Yellow", logfunc, ld);
- DitherLuts[3] = cfLutLoad(ppd, colormodel, header->MediaType,
+ DitherLuts[3] = ppdLutLoad(ppd, colormodel, header->MediaType,
resolution, "Black", logfunc, ld);
break;
case 6 : /* CcMmYK */
- DitherLuts[0] = cfLutLoad(ppd, colormodel, header->MediaType,
+ DitherLuts[0] = ppdLutLoad(ppd, colormodel, header->MediaType,
resolution, "Cyan", logfunc, ld);
- DitherLuts[1] = cfLutLoad(ppd, colormodel, header->MediaType,
+ DitherLuts[1] = ppdLutLoad(ppd, colormodel, header->MediaType,
resolution, "LightCyan", logfunc, ld);
- DitherLuts[2] = cfLutLoad(ppd, colormodel, header->MediaType,
+ DitherLuts[2] = ppdLutLoad(ppd, colormodel, header->MediaType,
resolution, "Magenta", logfunc, ld);
- DitherLuts[3] = cfLutLoad(ppd, colormodel, header->MediaType,
+ DitherLuts[3] = ppdLutLoad(ppd, colormodel, header->MediaType,
resolution, "LightMagenta", logfunc, ld);
- DitherLuts[4] = cfLutLoad(ppd, colormodel, header->MediaType,
+ DitherLuts[4] = ppdLutLoad(ppd, colormodel, header->MediaType,
resolution, "Yellow", logfunc, ld);
- DitherLuts[5] = cfLutLoad(ppd, colormodel, header->MediaType,
+ DitherLuts[5] = ppdLutLoad(ppd, colormodel, header->MediaType,
resolution, "Black", logfunc, ld);
break;
case 7 : /* CcMmYKk */
- DitherLuts[0] = cfLutLoad(ppd, colormodel, header->MediaType,
+ DitherLuts[0] = ppdLutLoad(ppd, colormodel, header->MediaType,
resolution, "Cyan", logfunc, ld);
- DitherLuts[1] = cfLutLoad(ppd, colormodel, header->MediaType,
+ DitherLuts[1] = ppdLutLoad(ppd, colormodel, header->MediaType,
resolution, "LightCyan", logfunc, ld);
- DitherLuts[2] = cfLutLoad(ppd, colormodel, header->MediaType,
+ DitherLuts[2] = ppdLutLoad(ppd, colormodel, header->MediaType,
resolution, "Magenta", logfunc, ld);
- DitherLuts[3] = cfLutLoad(ppd, colormodel, header->MediaType,
+ DitherLuts[3] = ppdLutLoad(ppd, colormodel, header->MediaType,
resolution, "LightMagenta", logfunc, ld);
- DitherLuts[4] = cfLutLoad(ppd, colormodel, header->MediaType,
+ DitherLuts[4] = ppdLutLoad(ppd, colormodel, header->MediaType,
resolution, "Yellow", logfunc, ld);
- DitherLuts[5] = cfLutLoad(ppd, colormodel, header->MediaType,
+ DitherLuts[5] = ppdLutLoad(ppd, colormodel, header->MediaType,
resolution, "Black", logfunc, ld);
- DitherLuts[6] = cfLutLoad(ppd, colormodel, header->MediaType,
+ DitherLuts[6] = ppdLutLoad(ppd, colormodel, header->MediaType,
resolution, "LightBlack", logfunc, ld);
break;
}
* Enable unidirectional printing depending on the mode...
*/
- if ((attr = cfFindAttr(ppd, "cupsESCPDirection", colormodel,
+ if ((attr = ppdFindColorAttr(ppd, "cupsESCPDirection", colormodel,
header->MediaType, resolution, spec,
sizeof(spec), logfunc, ld)) != NULL)
printf("\033U%c", atoi(attr->value));
* Enable/disable microweaving as needed...
*/
- if ((attr = cfFindAttr(ppd, "cupsESCPMicroWeave", colormodel,
+ if ((attr = ppdFindColorAttr(ppd, "cupsESCPMicroWeave", colormodel,
header->MediaType, resolution, spec,
sizeof(spec), logfunc, ld)) != NULL)
printf("\033(i\001%c%c", 0, atoi(attr->value));
* Set the dot size and print speed as needed...
*/
- if ((attr = cfFindAttr(ppd, "cupsESCPDotSize", colormodel,
+ if ((attr = ppdFindColorAttr(ppd, "cupsESCPDotSize", colormodel,
header->MediaType, resolution, spec,
sizeof(spec), logfunc, ld)) != NULL)
printf("\033(e\002%c%c%c", 0, 0, atoi(attr->value));
cfWritePrintData("\033(R\010\000\000REMOTE1", 13);
/*
- * Load defaults...
+ * LoadXS defaults...
*/
cfWritePrintData("LD\000\000", 4);
/*
- * Raster to pclm filter(based on cfFilterRasterToPDF() filter function).
+ * Raster to PCLm filter (based on cfFilterRasterToPDF() filter function).
*/
*/
#include <cupsfilters/filter.h>
+#include <ppd/ppd-filter.h>
#include <signal.h>
#endif /* HAVE_SIGSET */
/*
- * Fire up the cfFilterRasterToPDF() filter function.
+ * Fire up the ppdFilterRasterToPDF() filter function.
*/
cf_filter_out_format_t outformat = CF_FILTER_OUT_FORMAT_PCLM;
- ret = cfFilterCUPSWrapper(argc, argv, cfFilterRasterToPDF, &outformat, &JobCanceled);
+ ret = ppdFilterCUPSWrapper(argc, argv, cfFilterRasterToPDF, &outformat, &JobCanceled);
if (ret)
fprintf(stderr, "ERROR: rastertopclm filter failed.\n");
* Include necessary headers...
*/
+#include "pcl-common.h"
#include <cupsfilters/colormanager.h>
#include <cupsfilters/driver.h>
-#include "pcl-common.h"
-#include <signal.h>
#include <cupsfilters/filter.h>
+#include <ppd/ppd.h>
+#include <ppd/ppd-filter.h>
+#include <signal.h>
/*
* Output modes...
fprintf(stderr, "DEBUG: Resolution = %s\n", resolution);
/* support the "cm-calibration" option */
- cm_calibrate = cfCmGetCupsColorCalibrateMode(data, options, num_options);
+ cm_calibrate = cfCmGetCupsColorCalibrateMode(data);
if (cm_calibrate == CF_CM_CALIBRATION_ENABLED)
cm_disabled = 1;
{
if (header->cupsColorSpace == CUPS_CSPACE_RGB ||
header->cupsColorSpace == CUPS_CSPACE_W)
- RGB = cfRGBLoad(ppd, colormodel, header->MediaType, resolution,
+ RGB = ppdRGBLoad(ppd, colormodel, header->MediaType, resolution,
logfunc, ld);
- CMYK = cfCMYKLoad(ppd, colormodel, header->MediaType, resolution,
+ CMYK = ppdCMYKLoad(ppd, colormodel, header->MediaType, resolution,
logfunc, ld);
}
switch (PrinterPlanes)
{
case 1 : /* K */
- DitherLuts[0] = cfLutLoad(ppd, colormodel, header->MediaType,
+ DitherLuts[0] = ppdLutLoad(ppd, colormodel, header->MediaType,
resolution, "Black", logfunc, ld);
break;
case 3 : /* CMY */
- DitherLuts[0] = cfLutLoad(ppd, colormodel, header->MediaType,
+ DitherLuts[0] = ppdLutLoad(ppd, colormodel, header->MediaType,
resolution, "Cyan", logfunc, ld);
- DitherLuts[1] = cfLutLoad(ppd, colormodel, header->MediaType,
+ DitherLuts[1] = ppdLutLoad(ppd, colormodel, header->MediaType,
resolution, "Magenta", logfunc, ld);
- DitherLuts[2] = cfLutLoad(ppd, colormodel, header->MediaType,
+ DitherLuts[2] = ppdLutLoad(ppd, colormodel, header->MediaType,
resolution, "Yellow", logfunc, ld);
break;
case 4 : /* CMYK */
- DitherLuts[0] = cfLutLoad(ppd, colormodel, header->MediaType,
+ DitherLuts[0] = ppdLutLoad(ppd, colormodel, header->MediaType,
resolution, "Cyan", logfunc, ld);
- DitherLuts[1] = cfLutLoad(ppd, colormodel, header->MediaType,
+ DitherLuts[1] = ppdLutLoad(ppd, colormodel, header->MediaType,
resolution, "Magenta", logfunc, ld);
- DitherLuts[2] = cfLutLoad(ppd, colormodel, header->MediaType,
+ DitherLuts[2] = ppdLutLoad(ppd, colormodel, header->MediaType,
resolution, "Yellow", logfunc, ld);
- DitherLuts[3] = cfLutLoad(ppd, colormodel, header->MediaType,
+ DitherLuts[3] = ppdLutLoad(ppd, colormodel, header->MediaType,
resolution, "Black", logfunc, ld);
break;
case 6 : /* CcMmYK */
- DitherLuts[0] = cfLutLoad(ppd, colormodel, header->MediaType,
+ DitherLuts[0] = ppdLutLoad(ppd, colormodel, header->MediaType,
resolution, "Cyan", logfunc, ld);
- DitherLuts[1] = cfLutLoad(ppd, colormodel, header->MediaType,
+ DitherLuts[1] = ppdLutLoad(ppd, colormodel, header->MediaType,
resolution, "LightCyan", logfunc, ld);
- DitherLuts[2] = cfLutLoad(ppd, colormodel, header->MediaType,
+ DitherLuts[2] = ppdLutLoad(ppd, colormodel, header->MediaType,
resolution, "Magenta", logfunc, ld);
- DitherLuts[3] = cfLutLoad(ppd, colormodel, header->MediaType,
+ DitherLuts[3] = ppdLutLoad(ppd, colormodel, header->MediaType,
resolution, "LightMagenta", logfunc, ld);
- DitherLuts[4] = cfLutLoad(ppd, colormodel, header->MediaType,
+ DitherLuts[4] = ppdLutLoad(ppd, colormodel, header->MediaType,
resolution, "Yellow", logfunc, ld);
- DitherLuts[5] = cfLutLoad(ppd, colormodel, header->MediaType,
+ DitherLuts[5] = ppdLutLoad(ppd, colormodel, header->MediaType,
resolution, "Black", logfunc, ld);
break;
}
printf("\033*p0Y\033*p0X");
}
- if (ppd && ((attr = cfFindAttr(ppd, "cupsPCLQuality", colormodel,
+ if (ppd && ((attr = ppdFindColorAttr(ppd, "cupsPCLQuality", colormodel,
header->MediaType, resolution, spec,
sizeof(spec), logfunc, ld)) != NULL))
{
* vertical resolutions as well as a color count...
*/
- if (ppd && ((attr = cfFindAttr(ppd, "cupsPCLCRDMode", colormodel,
+ if (ppd && ((attr = ppdFindColorAttr(ppd, "cupsPCLCRDMode", colormodel,
header->MediaType, resolution, spec,
sizeof(spec), logfunc, ld)) != NULL))
i = atoi(attr->value);
/*
- * Raster to pdf filter(based on cfFilterRasterToPDF() filter function).
+ * Raster to PDF filter (based on cfFilterRasterToPDF() filter function).
*/
*/
#include <cupsfilters/filter.h>
+#include <ppd/ppd-filter.h>
#include <signal.h>
#endif /* HAVE_SIGSET */
/*
- * Fire up the cfFilterRasterToPDF() filter function.
+ * Fire up the ppdFilterRasterToPDF() filter function.
*/
cf_filter_out_format_t outformat = CF_FILTER_OUT_FORMAT_PDF;
- ret = cfFilterCUPSWrapper(argc, argv, cfFilterRasterToPDF, &outformat, &JobCanceled);
+ ret = ppdFilterCUPSWrapper(argc, argv, cfFilterRasterToPDF, &outformat, &JobCanceled);
if (ret)
fprintf(stderr, "ERROR: rastertopdf filter failed.\n");
*/
#include <cupsfilters/filter.h>
+#include <ppd/ppd-filter.h>
#include <signal.h>
/*
* Fire up the cfFilterRasterToPS() filter function
*/
- ret = cfFilterCUPSWrapper(argc, argv, cfFilterRasterToPS, NULL, &JobCanceled);
+ ret = ppdFilterCUPSWrapper(argc, argv, ppdFilterRasterToPS, NULL,
+ &JobCanceled);
if (ret)
fprintf(stderr, "ERROR: rastertops filter function failed.\n");
*/
#include <cupsfilters/filter.h>
+#include <ppd/ppd-filter.h>
#include <signal.h>
/*
#endif /* HAVE_SIGSET */
/*
- * Fire up the cfFilterPDFToRaster() filter function
+ * Fire up the ppdFilterRasterToPWG() filter function
*/
- cf_filter_out_format_t outformat = CF_FILTER_OUT_FORMAT_PWG_RASTER;
- char *t = getenv("FINAL_CONTENT_TYPE");
- if (t) {
- if (strcasestr(t, "pwg"))
- outformat = CF_FILTER_OUT_FORMAT_PWG_RASTER;
- else if (strcasestr(t, "urf"))
- outformat = CF_FILTER_OUT_FORMAT_APPLE_RASTER;
- }
- ret = cfFilterCUPSWrapper(argc, argv, cfFilterRasterToPWG, &outformat, &JobCanceled);
+
+ ret = ppdFilterCUPSWrapper(argc, argv, cfFilterRasterToPWG, NULL, &JobCanceled);
if (ret)
fprintf(stderr, "ERROR: rastertopwg filter function failed.\n");
int cobj=cfPDFOutAddXRef(pdf);
const char buf[]="BT /a 10 Tf (abc) Tj ET";
cfPDFOutPrintF(pdf,"%d 0 obj\n"
- "<</Length %d\n"
+ "<</Length %ld\n"
">>\n"
"stream\n"
"%s\n"
const int clobj=cfPDFOutAddXRef(pdf);
assert(clobj==cobj+1);
cfPDFOutPrintF(pdf,"%d 0 obj\n"
- "%d\n"
+ "%ld\n"
"endobj\n"
,clobj,streamlen);
*/
#include <cupsfilters/filter.h>
+#include <ppd/ppd-filter.h>
#include <signal.h>
#include <fontconfig/fontconfig.h>
#include <config.h>
#endif /* HAVE_SIGSET */
/*
- * Fire up the cfFilterTextToPDF() filter function
+ * Fire up the ppdFilterTextToPDF() filter function
*/
cf_filter_texttopdf_parameter_t parameters;
char *p;
else
parameters.classification = NULL;
- ret = cfFilterCUPSWrapper(argc, argv, cfFilterTextToPDF, ¶meters, &JobCanceled);
+ ret = ppdFilterCUPSWrapper(argc, argv, cfFilterTextToPDF, ¶meters, &JobCanceled);
if (ret)
fprintf(stderr, "ERROR: texttopdf filter function failed.\n");
*/
#include <cupsfilters/filter.h>
+#include <ppd/ppd-filter.h>
#include <signal.h>
/*
#endif /* HAVE_SIGSET */
/*
- * Fire up the cfFilterTextToText() filter function
+ * Fire up the ppdFilterTextToText() filter function
*/
- ret = cfFilterCUPSWrapper(argc, argv, cfFilterTextToText, NULL, &JobCanceled);
+ ret = ppdFilterCUPSWrapper(argc, argv, cfFilterTextToText, NULL,
+ &JobCanceled);
if (ret)
fprintf(stderr, "ERROR: texttotext filter function failed.\n");
*/
#include <cupsfilters/filter.h>
+#include <ppd/ppd-filter.h>
#include <config.h>
#include <signal.h>
signal(SIGTERM, cancel_job);
#endif /* HAVE_SIGSET */
- if ((p = getenv("CONTENT_TYPE")) != NULL)
- universal_parameters.input_format = strdup(p);
- else
- universal_parameters.input_format = NULL;
-
- if ((p = getenv("FINAL_CONTENT_TYPE")) != NULL)
- universal_parameters.output_format = strdup(p);
- else
- universal_parameters.output_format = NULL;
-
+ universal_parameters.actual_output_type = NULL; /* Determined by PPD file */
+
if ((p = getenv("CUPS_DATADIR")) != NULL)
universal_parameters.texttopdf_params.data_dir = strdup(p);
else
else
universal_parameters.texttopdf_params.char_set = NULL;
- universal_parameters.texttopdf_params.content_type =
- universal_parameters.input_format;
+ if ((p = getenv("CONTENT_TYPE")) != NULL)
+ universal_parameters.texttopdf_params.content_type = strdup(p);
+ else
+ universal_parameters.texttopdf_params.content_type = NULL;
if ((p = getenv("CLASSIFICATION")) != NULL)
universal_parameters.texttopdf_params.classification = strdup(p);
else
universal_parameters.texttopdf_params.classification = NULL;
- ret = cfFilterCUPSWrapper(argc, argv, cfFilterUniversal, &universal_parameters,
- &JobCanceled);
+ ret = ppdFilterCUPSWrapper(argc, argv, ppdFilterUniversal,
+ &universal_parameters, &JobCanceled);
if (ret)
fprintf(stderr, "ERROR: universal filter failed.\n");
- free(universal_parameters.input_format);
- free(universal_parameters.output_format);
free(universal_parameters.texttopdf_params.data_dir);
free(universal_parameters.texttopdf_params.char_set);
+ free(universal_parameters.texttopdf_params.content_type);
free(universal_parameters.texttopdf_params.classification);
return (ret);
includedir=@includedir@
Name: libppd
-Description: Library for handling PPD files
+Description: Library for handling PPD files and PostScript output
Version: @VERSION@
Libs: -L${libdir} -lppd
/*
* PostScript filter function and image file to PostScript filter function
- * for cups-filters.
+ * for libppd.
*
* Copyright © 2020 by Till Kamppeter
* Copyright © 2007-2018 by Apple Inc.
#include <cupsfilters/raster.h>
#include <cupsfilters/image-private.h>
#include <ppd/ppd.h>
+#include <ppd/ppd-filter.h>
#include <cups/file.h>
#include <cups/array.h>
#include <limits.h>
const char *name, const char *value);
/*
- * 'cfFilterPSToPS()' - Filter function to insert PostScript code from
+ * 'ppdFilterPSToPS()' - Filter function to insert PostScript code from
* PPD file (PostScript printer driver) into a
* PostScript data stream
*/
int /* O - Error status */
-cfFilterPSToPS(int inputfd, /* I - File descriptor input stream */
+ppdFilterPSToPS(int inputfd, /* I - File descriptor input stream */
int outputfd, /* I - File descriptor output stream */
int inputseekable, /* I - Is input stream seekable? (unused) */
cf_filter_data_t *data, /* I - Job and printer data */
void *parameters) /* I - Filter-specific parameters (unused) */
{
+ ppd_filter_data_ext_t *filter_data_ext =
+ (ppd_filter_data_ext_t *)cfFilterDataGetExt(data,
+ PPD_FILTER_DATA_EXT);
pstops_doc_t doc; /* Document information */
cups_file_t *inputfp,*fp; /* Print file */
FILE *outputfp; /* Output data stream */
* Process job options...
*/
- if (set_pstops_options(&doc, data->ppd, data->job_id, data->job_user,
+ if (set_pstops_options(&doc, filter_data_ext->ppd,
+ data->job_id, data->job_user,
data->job_title, data->copies,
data->num_options, data->options,
log, ld, iscanceled, icd) == 1)
if(pipe(proc_pipe))
{
if (log) log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterPSToPS: Unable to create pipe for input-page-ranges");
+ "ppdFilterPSToPS: Unable to create pipe for input-page-ranges");
return (1);
}
if ((pstops_pid = fork()) == 0)
if (!iscanceled || !iscanceled(icd))
{
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPSToPS: Unable to open input data stream.");
+ "ppdFilterPSToPS: Unable to open input data stream.");
}
exit (1);
if (!iscanceled || !iscanceled(icd))
{
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPSToPS: Unable to open input data stream.");
+ "ppdFilterPSToPS: Unable to open input data stream.");
}
return (1);
if (!iscanceled || !iscanceled(icd))
{
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPSToPS: Unable to open output data stream.");
+ "ppdFilterPSToPS: Unable to open output data stream.");
}
cupsFileClose(inputfp);
if ((len = (ssize_t)cupsFileGetLine(inputfp, line, sizeof(line))) == 0)
{
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPSToPS: The print file is empty.");
+ "ppdFilterPSToPS: The print file is empty.");
/* Do not treat this an error, if a previous filter eliminated all
pages the job should get dequeued without anything printed. */
return (0);
* Write any "exit server" options that have been selected...
*/
- ppdEmit(data->ppd, outputfp, PPD_ORDER_EXIT);
+ ppdEmit(filter_data_ext->ppd, outputfp, PPD_ORDER_EXIT);
/*
* Write any JCL commands that are needed to print PostScript code...
*/
if (doc.emit_jcl)
- ppdEmitJCL(data->ppd, outputfp, doc.job_id, doc.user, doc.title);
+ ppdEmitJCL(filter_data_ext->ppd, outputfp, doc.job_id, doc.user, doc.title);
/*
* Start with a DSC header...
*/
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPSToPS: Skipping PJL header...");
+ "ppdFilterPSToPS: Skipping PJL header...");
while (strstr(line, "ENTER LANGUAGE") == NULL && strncmp(line, "%!", 2))
if ((len = (ssize_t)cupsFileGetLine(inputfp, line, sizeof(line))) == 0)
* Yes, filter the document...
*/
- copy_dsc(&doc, data->ppd, line, len, sizeof(line));
+ copy_dsc(&doc, filter_data_ext->ppd, line, len, sizeof(line));
}
else
{
* a single page...
*/
- copy_non_dsc(&doc, data->ppd, line, len, sizeof(line));
+ copy_non_dsc(&doc, filter_data_ext->ppd, line, len, sizeof(line));
}
/*
if (doc.emit_jcl)
{
- if (data->ppd && data->ppd->jcl_end)
- ppdEmitJCLEnd(data->ppd, doc.outputfp);
+ if (filter_data_ext->ppd && filter_data_ext->ppd->jcl_end)
+ ppdEmitJCLEnd(filter_data_ext->ppd, doc.outputfp);
else
doc_putc(&doc, 0x04);
}
if (errno == EINTR)
goto retry_wait;
if (log) log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterPSToPS: Error while waiting for input_page_ranges to finish - %s.",
+ "ppdFilterPSToPS: Error while waiting for input_page_ranges to finish - %s.",
strerror(errno));
}
/* How did the sub-process terminate */
if (WIFEXITED(childStatus)) {
/* Via exit() anywhere or return() in the main() function */
if (log) log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterPSToPS: input-page-ranges filter (PID %d) stopped with status %d",
+ "ppdFilterPSToPS: input-page-ranges filter (PID %d) stopped with status %d",
pstops_pid, WEXITSTATUS(childStatus));
} else {
/* Via signal */
if (log) log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterPSToPS: imput-page-ranges filter (PID %d) crashed on signal %d",
+ "ppdFilterPSToPS: imput-page-ranges filter (PID %d) crashed on signal %d",
pstops_pid, WTERMSIG(childStatus));
}
status=1;
} else {
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPSToPS: input-page-ranges-filter (PID %d) exited with no errors.",
+ "ppdFilterPSToPS: input-page-ranges-filter (PID %d) exited with no errors.",
pstops_pid);
}
}
/*
- * 'cfFilterImageToPS()' - Filter function to convert many common image file
+ * 'ppdFilterImageToPS()' - Filter function to convert many common image file
* formats into PostScript
*/
int /* O - Error status */
-cfFilterImageToPS(int inputfd, /* I - File descriptor input stream */
+ppdFilterImageToPS(int inputfd, /* I - File descriptor input stream */
int outputfd, /* I - File descriptor output stream*/
int inputseekable, /* I - Is input stream seekable?
(unused) */
void *parameters) /* I - Filter-specific parameters
(unused) */
{
+ ppd_filter_data_ext_t *filter_data_ext =
+ (ppd_filter_data_ext_t *)cfFilterDataGetExt(data,
+ PPD_FILTER_DATA_EXT);
pstops_doc_t doc; /* Document information */
cf_image_t *img; /* Image to print */
float xprint, /* Printable area */
int fd; /* File descriptor for temp file */
char buf[BUFSIZ];
int bytes;
+ cups_cspace_t cspace = (cups_cspace_t)(-1);
cf_logfunc_t log = data->logfunc;
void *ld = data->logdata;
cf_filter_iscanceledfunc_t iscanceled = data->iscanceledfunc;
if (!iscanceled || !iscanceled(icd))
{
if (log) log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterImageToPS: Unable to open input data stream.");
+ "ppdFilterImageToPS: Unable to open input data stream.");
}
return (1);
if ((fd = cupsTempFd(tempfile, sizeof(tempfile))) < 0)
{
if (log) log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterImageToPS: Unable to copy input: %s",
+ "ppdFilterImageToPS: Unable to copy input: %s",
strerror(errno));
return (1);
}
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterImageToPS: Copying input to temp file \"%s\"",
+ "ppdFilterImageToPS: Copying input to temp file \"%s\"",
tempfile);
while ((bytes = fread(buf, 1, sizeof(buf), inputfp)) > 0)
if (!iscanceled || !iscanceled(icd))
{
if (log) log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterImageToPS: Unable to open temporary file.");
+ "ppdFilterImageToPS: Unable to open temporary file.");
}
unlink(tempfile);
if (!iscanceled || !iscanceled(icd))
{
if (log) log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterImageToPS: Unable to open output data stream.");
+ "ppdFilterImageToPS: Unable to open output data stream.");
}
fclose(inputfp);
* Process job options...
*/
- ppd = data->ppd;
- cfFilterSetCommonOptions(ppd, num_options, options, 0,
+ ppd = filter_data_ext->ppd;
+ ppdFilterSetCommonOptions(ppd, num_options, options, 0,
&doc.Orientation, &doc.Duplex,
&doc.LanguageLevel, &doc.Color,
&doc.PageLeft, &doc.PageRight,
&doc.PageWidth, &doc.PageLength,
log, ld);
- /* The cfFilterSetCommonOptions() does not set doc.Color
+ /* The ppdFilterSetCommonOptions() does not set doc.Color
according to option settings (user's demand for color/gray),
so we parse the options and set the mode here */
- cfRasterParseIPPOptions(&h, data, 0, 1);
+ cfRasterPrepareHeader(&h, data, CF_FILTER_OUT_FORMAT_CUPS_RASTER,
+ CF_FILTER_OUT_FORMAT_CUPS_RASTER, 0, &cspace);
if (doc.Color)
doc.Color = h.cupsNumColors <= 1 ? 0 : 1;
if (!ppd) {
if (img == NULL)
{
if (log) log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterImageToPS: The print file could not be opened - %s",
+ "ppdFilterImageToPS: The print file could not be opened - %s",
strerror(errno));
return (1);
}
yppi = xppi;
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterImageToPS: Before scaling: xppi=%d, yppi=%d, zoom=%.2f",
+ "ppdFilterImageToPS: Before scaling: xppi=%d, yppi=%d, zoom=%.2f",
xppi, yppi, zoom);
if (xppi > 0)
}
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterImageToPS: Before scaling: xprint=%.1f, yprint=%.1f",
+ "ppdFilterImageToPS: Before scaling: xprint=%.1f, yprint=%.1f",
xprint, yprint);
xinches = (float)cfImageGetWidth(img) / (float)xppi;
yinches = (float)cfImageGetHeight(img) / (float)yppi;
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterImageToPS: Image size is %.1f x %.1f inches...",
+ "ppdFilterImageToPS: Image size is %.1f x %.1f inches...",
xinches, yinches);
if ((val = cupsGetOption("natural-scaling", num_options, options)) != NULL)
*/
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterImageToPS: Auto orientation...");
+ "ppdFilterImageToPS: Auto orientation...");
if ((xinches > xprint || yinches > yprint) &&
xinches <= yprint && yinches <= xprint)
*/
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterImageToPS: Using landscape orientation...");
+ "ppdFilterImageToPS: Using landscape orientation...");
doc.Orientation = (doc.Orientation + 1) & 3;
xsize = yprint;
aspect = (float)cfImageGetYPPI(img) / (float)cfImageGetXPPI(img);
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterImageToPS: Before scaling: xprint=%.1f, yprint=%.1f",
+ "ppdFilterImageToPS: Before scaling: xprint=%.1f, yprint=%.1f",
xprint, yprint);
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterImageToPS: cfImageGetXPPI(img) = %d, "
+ "ppdFilterImageToPS: cfImageGetXPPI(img) = %d, "
"cfImageGetYPPI(img) = %d, aspect = %f",
cfImageGetXPPI(img), cfImageGetYPPI(img), aspect);
}
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterImageToPS: Portrait size is %.2f x %.2f inches",
+ "ppdFilterImageToPS: Portrait size is %.2f x %.2f inches",
xsize, ysize);
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterImageToPS: Landscape size is %.2f x %.2f inches",
+ "ppdFilterImageToPS: Landscape size is %.2f x %.2f inches",
xsize2, ysize2);
if (cupsGetOption("orientation-requested", num_options, options) == NULL &&
*/
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterImageToPS: Auto orientation...");
+ "ppdFilterImageToPS: Auto orientation...");
if ((xsize * ysize) < (xsize2 * xsize2))
{
*/
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterImageToPS: Using landscape orientation...");
+ "ppdFilterImageToPS: Using landscape orientation...");
doc.Orientation = 1;
xinches = xsize2;
*/
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterImageToPS: Using portrait orientation...");
+ "ppdFilterImageToPS: Using portrait orientation...");
doc.Orientation = 0;
xinches = xsize;
else if (doc.Orientation & 1)
{
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterImageToPS: Using landscape orientation...");
+ "ppdFilterImageToPS: Using landscape orientation...");
xinches = xsize2;
yinches = ysize2;
else
{
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterImageToPS: Using portrait orientation...");
+ "ppdFilterImageToPS: Using portrait orientation...");
xinches = xsize;
yinches = ysize;
yprint = yinches / ypages;
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterImageToPS: xpages = %dx%.2fin, ypages = %dx%.2fin",
+ "ppdFilterImageToPS: xpages = %dx%.2fin, ypages = %dx%.2fin",
xpages, xprint, ypages, yprint);
/*
length = ppd->custom_min[1];
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterImageToPS: Updated custom page size to %.2f x %.2f inches...",
+ "ppdFilterImageToPS: Updated custom page size to %.2f x %.2f inches...",
width / 72.0, length / 72.0);
/*
if (row == NULL)
{
log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterImageToPS: Could not allocate memory.");
+ "ppdFilterImageToPS: Could not allocate memory.");
cfImageClose(img);
return (2);
}
if (log)
{
log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterImageToPS: XPosition=%d, YPosition=%d, Orientation=%d",
+ "ppdFilterImageToPS: XPosition=%d, YPosition=%d, Orientation=%d",
XPosition, YPosition, doc.Orientation);
log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterImageToPS: xprint=%.1f, yprint=%.1f", xprint, yprint);
+ "ppdFilterImageToPS: xprint=%.1f, yprint=%.1f", xprint, yprint);
log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterImageToPS: PageLeft=%.0f, PageRight=%.0f, PageWidth=%.0f",
+ "ppdFilterImageToPS: PageLeft=%.0f, PageRight=%.0f, PageWidth=%.0f",
doc.PageLeft, doc.PageRight, doc.PageWidth);
log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterImageToPS: PageBottom=%.0f, PageTop=%.0f, PageLength=%.0f",
+ "ppdFilterImageToPS: PageBottom=%.0f, PageTop=%.0f, PageLength=%.0f",
doc.PageBottom, doc.PageTop, doc.PageLength);
}
}
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterImageToPS: left=%.2f, top=%.2f", left, top);
+ "ppdFilterImageToPS: left=%.2f, top=%.2f", left, top);
for (page = 1; Copies > 0; Copies --)
for (xpage = 0; xpage < xpages; xpage ++)
if (iscanceled && iscanceled(icd))
{
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterImageToPS: Job canceled");
+ "ppdFilterImageToPS: Job canceled");
goto canceled;
}
"PAGE: %d %d", page, realcopies);
if (log) log(ld, CF_LOGLEVEL_INFO,
- "cfFilterImageToPS: Printing page %d.", page);
+ "ppdFilterImageToPS: Printing page %d.", page);
doc_printf(&doc, "%%%%Page: %d %d\n", page, page);
}
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterImageToPS: Printing completed.", page);
+ "ppdFilterImageToPS: Printing completed.", page);
/*
* Close files...
if (!doc->pages)
{
if (log) log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterPSToPS: Unable to allocate memory for pages array");
+ "ppdFilterPSToPS: Unable to allocate memory for pages array");
return (NULL);
}
if ((pageinfo = calloc(1, sizeof(pstops_page_t))) == NULL)
{
if (log) log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterPSToPS: Unable to allocate memory for page info");
+ "ppdFilterPSToPS: Unable to allocate memory for page info");
return (NULL);
}
*/
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPSToPS: %s", line);
+ "ppdFilterPSToPS: %s", line);
/*
* Pull the headers out...
if (saw_pages && log)
log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPSToPS: A duplicate %%Pages: comment was seen.");
+ "ppdFilterPSToPS: A duplicate %%Pages: comment was seen.");
saw_pages = 1;
if (saw_bounding_box)
{
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPSToPS: A duplicate %%BoundingBox: comment was seen.");
+ "ppdFilterPSToPS: A duplicate %%BoundingBox: comment was seen.");
}
else if (strstr(line + 14, "(atend)"))
{
doc->bounding_box + 3) != 4)
{
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPSToPS: A bad %%BoundingBox: comment was seen.");
+ "ppdFilterPSToPS: A bad %%BoundingBox: comment was seen.");
doc->bounding_box[0] = (int)(doc->PageLeft);
doc->bounding_box[1] = (int)(doc->PageBottom);
*/
doc->Orientation = (4 - doc->Orientation + orient) & 3;
- cfFilterUpdatePageVars(doc->Orientation,
+ ppdFilterUpdatePageVars(doc->Orientation,
&doc->PageLeft, &doc->PageRight,
&doc->PageTop, &doc->PageBottom,
&doc->PageWidth, &doc->PageLength);
if (!saw_bounding_box && log)
log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPSToPS: There wasn't a %%BoundingBox: comment in the header.");
+ "ppdFilterPSToPS: There wasn't a %%BoundingBox: comment in the header.");
if (!saw_pages && log)
log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPSToPS: There wasn't a %%Pages: comment in the header.");
+ "ppdFilterPSToPS: There wasn't a %%Pages: comment in the header.");
if (!saw_for)
write_text_comment(doc, "For", doc->user);
*/
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPSToPS: Before copy_comments - %s", line);
+ "ppdFilterPSToPS: Before copy_comments - %s", line);
linelen = copy_comments(doc, ppd, line, linelen, linesize);
/*
*/
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPSToPS: Before copy_prolog - %s", line);
+ "ppdFilterPSToPS: Before copy_prolog - %s", line);
linelen = copy_prolog(doc, ppd, line, linelen, linesize);
/*
*/
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPSToPS: Before copy_setup - %s", line);
+ "ppdFilterPSToPS: Before copy_setup - %s", line);
linelen = copy_setup(doc, ppd, line, linelen, linesize);
/*
number = 0;
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPSToPS: Before page loop - %s", line);
+ "ppdFilterPSToPS: Before page loop - %s", line);
while (!strncmp(line, "%%Page:", 7))
{
if (iscanceled && iscanceled(icd))
{
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPSToPS: Job canceled");
+ "ppdFilterPSToPS: Job canceled");
break;
}
if (check_range((number - 1) / doc->number_up + 1,doc->page_ranges,doc->page_set))
{
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPSToPS: Copying page %d...", number);
+ "ppdFilterPSToPS: Copying page %d...", number);
linelen = copy_page(doc, ppd, number, line, linelen, linesize);
}
else
{
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPSToPS: Skipping page %d...", number);
+ "ppdFilterPSToPS: Skipping page %d...", number);
linelen = skip_page(doc, line, linelen, linesize);
}
}
if (iscanceled && iscanceled(icd))
{
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPSToPS: Job canceled");
+ "ppdFilterPSToPS: Job canceled");
break;
}
if (iscanceled && iscanceled(icd))
{
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPSToPS: Job canceled");
+ "ppdFilterPSToPS: Job canceled");
break;
}
*/
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPSToPS: This document does not conform to the Adobe Document "
+ "ppdFilterPSToPS: This document does not conform to the Adobe Document "
"Structuring Conventions and may not print correctly.");
/*
if (iscanceled && iscanceled(icd))
{
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPSToPS: Job canceled");
+ "ppdFilterPSToPS: Job canceled");
break;
}
if (!parse_text(line + 7, &ptr, label, sizeof(label)))
{
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPSToPS: There was a bad %%Page: comment in the file.");
+ "ppdFilterPSToPS: There was a bad %%Page: comment in the file.");
label[0] = '\0';
number = doc->page;
}
else if (strtol(ptr, &ptr, 10) == LONG_MAX || !isspace(*ptr & 255))
{
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPSToPS: There was a bad %%Page: comment in the file.");
+ "ppdFilterPSToPS: There was a bad %%Page: comment in the file.");
number = doc->page;
}
{
if (log)
log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPSToPS: There was a bad %%PageBoundingBox: comment in the "
+ "ppdFilterPSToPS: There was a bad %%PageBoundingBox: comment in the "
"file.");
memcpy(bounding_box, doc->bounding_box,
sizeof(bounding_box));
if (log)
{
log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPSToPS: Orientation = %d", doc->Orientation);
+ "ppdFilterPSToPS: Orientation = %d", doc->Orientation);
log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPSToPS: original bounding_box = [ %d %d %d %d ]",
+ "ppdFilterPSToPS: original bounding_box = [ %d %d %d %d ]",
bounding_box[0], bounding_box[1],
bounding_box[2], bounding_box[3]);
log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPSToPS: PageWidth = %.1f, PageLength = %.1f",
+ "ppdFilterPSToPS: PageWidth = %.1f, PageLength = %.1f",
doc->PageWidth, doc->PageLength);
}
}
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPSToPS: updated bounding_box = [ %d %d %d %d ]",
+ "ppdFilterPSToPS: updated bounding_box = [ %d %d %d %d ]",
bounding_box[0], bounding_box[1],
bounding_box[2], bounding_box[3]);
}
line[0] = '\0';
if (log)
log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterPSToPS: Early end-of-file while reading binary data: %s",
+ "ppdFilterPSToPS: Early end-of-file while reading binary data: %s",
strerror(errno));
return (0);
}
linelen = (ssize_t)cupsFileGetLine(doc->inputfp, line, linesize);
else
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPSToPS: The %%EndProlog comment is missing.");
+ "ppdFilterPSToPS: The %%EndProlog comment is missing.");
}
doc_puts(doc, "%%EndProlog\n");
linelen = (ssize_t)cupsFileGetLine(doc->inputfp, line, linesize);
else
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPSToPS: The %%EndSetup comment is missing.");
+ "ppdFilterPSToPS: The %%EndSetup comment is missing.");
}
if (num_options > 0)
}
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPSToPS: Wrote %d pages...", number);
+ "ppdFilterPSToPS: Wrote %d pages...", number);
doc_printf(doc, "%%%%Pages: %d\n", number);
if (doc->number_up > 1 || doc->fit_to_page)
if ((size_t)bytes > sizeof(buffer))
{
if (log) log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterPSToPS: Buffer overflow detected, truncating.");
+ "ppdFilterPSToPS: Buffer overflow detected, truncating.");
bytes = sizeof(buffer);
}
if (sscanf(line + 17, "%254s%254s", name, value) != 2)
{
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPSToPS: The %%IncludeFeature: comment is not valid.");
+ "ppdFilterPSToPS: The %%IncludeFeature: comment is not valid.");
return (num_options);
}
if ((option = ppdFindOption(ppd, name + 1)) == NULL)
{
if (log) log(ld, CF_LOGLEVEL_WARN,
- "cfFilterPSToPS: Unknown option \"%s\".", name + 1);
+ "ppdFilterPSToPS: Unknown option \"%s\".", name + 1);
return (num_options);
}
option->section == PPD_ORDER_JCL)
{
if (log) log(ld, CF_LOGLEVEL_WARN,
- "cfFilterPSToPS: Option \"%s\" cannot be included via "
+ "ppdFilterPSToPS: Option \"%s\" cannot be included via "
"%%%%IncludeFeature.", name + 1);
return (num_options);
}
if (!ppdFindChoice(option, value))
{
if (log) log(ld, CF_LOGLEVEL_WARN,
- "cfFilterPSToPS: Unknown choice \"%s\" for option \"%s\".",
+ "ppdFilterPSToPS: Unknown choice \"%s\" for option \"%s\".",
value, name + 1);
return (num_options);
}
doc->iscanceleddata = icd;
/* Set some common values */
- cfFilterSetCommonOptions(ppd, num_options, options, 1,
+ ppdFilterSetCommonOptions(ppd, num_options, options, 1,
&doc->Orientation, &doc->Duplex,
&doc->LanguageLevel, &doc->Color,
&doc->PageLeft, &doc->PageRight,
break;
default :
if (log) log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterPSToPS: Unsupported number-up value %d, using "
+ "ppdFilterPSToPS: Unsupported number-up value %d, using "
"number-up=1.", intval);
doc->number_up = 1;
break;
else
{
if (log) log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterPSToPS: Unsupported number-up-layout value %s, using "
+ "ppdFilterPSToPS: Unsupported number-up-layout value %s, using "
"number-up-layout=lrtb.", val);
doc->number_up_layout = PSTOPS_LAYOUT_LRTB;
}
else
{
if (log) log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterPSToPS: Unsupported page-border value %s, using "
+ "ppdFilterPSToPS: Unsupported page-border value %s, using "
"page-border=none.", val);
doc->page_border = PSTOPS_BORDERNONE;
}
sizeof(doc->tempfile))) == NULL)
{
if (log) log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterPSToPS: Unable to create temporary file: %s",
+ "ppdFilterPSToPS: Unable to create temporary file: %s",
strerror(errno));
return (1);
}
}
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPSToPS: slow_collate=%d, slow_duplex=%d, slow_order=%d",
+ "ppdFilterPSToPS: slow_collate=%d, slow_duplex=%d, slow_order=%d",
doc->slow_collate, doc->slow_duplex, doc->slow_order);
return(0);
line[0] = '\0';
if (log)
log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterPSToPS: Early end-of-file while reading binary data: %s",
+ "ppdFilterPSToPS: Early end-of-file while reading binary data: %s",
strerror(errno));
return (0);
}
if (log)
{
log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPSToPS: pagew = %.1f, pagel = %.1f", pagew, pagel);
+ "ppdFilterPSToPS: pagew = %.1f, pagel = %.1f", pagew, pagel);
log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPSToPS: bboxx = %d, bboxy = %d, bboxw = %d, bboxl = %d",
+ "ppdFilterPSToPS: bboxx = %d, bboxy = %d, bboxw = %d, bboxl = %d",
bboxx, bboxy, bboxw, bboxl);
log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPSToPS: PageLeft = %.1f, PageRight = %.1f",
+ "ppdFilterPSToPS: PageLeft = %.1f, PageRight = %.1f",
doc->PageLeft, doc->PageRight);
log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPSToPS: PageTop = %.1f, PageBottom = %.1f",
+ "ppdFilterPSToPS: PageTop = %.1f, PageBottom = %.1f",
doc->PageTop, doc->PageBottom);
log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPSToPS: PageWidth = %.1f, PageLength = %.1f",
+ "ppdFilterPSToPS: PageWidth = %.1f, PageLength = %.1f",
doc->PageWidth, doc->PageLength);
}
/*
- * PDF-to-PostScript filter function for cups-filters.
+ * PDF-to-PostScript filter function for libppd.
*
* Copyright 2011-2020 by Till Kamppeter
* Copyright 2007-2011 by Apple Inc.
* parsePDFTOPDFComment() - Check whether we are executed after pdftopdf
* remove_options() - Remove unwished entries from an option list
* log_command_line() - Log the command line of a program which we call
- * cfFilterPDFToPS() - pdftops filter function
+ * ppdFilterPDFToPS() - pdftops filter function
*/
/*
* Include necessary headers...
*/
-#include "filter.h"
-#include "raster.h"
-#include "pdf.h"
#include <config.h>
#include <cups/cups.h>
-#include <ppd/ppd.h>
#include <cups/file.h>
#include <signal.h>
#include <sys/wait.h>
#include <string.h>
#include <ctype.h>
#include <cupsfilters/filter.h>
+#include <cupsfilters/raster.h>
+#include <cupsfilters/pdf.h>
#include <cupsfilters/image-private.h>
+#include "ppd.h"
+#include "ppd-filter.h"
#define MAX_CHECK_COMMENT_LINES 20
const char *pstops_exclude_page_management[] = {
"brightness",
"Collate",
- "cupsEvenDuplex",
+ "even-duplex",
"gamma",
"hue",
"ipp-attribute-fidelity",
if ((fp = fopen(filename,"rb")) == NULL) {
if (log) log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterPDFToPS: Cannot open input file \"%s\"",
+ "ppdFilterPDFToPS: Cannot open input file \"%s\"",
filename);
return;
}
if (fp == NULL)
{
if (log) log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterPDFToPS: Cannot open input file \"%s\"",
+ "ppdFilterPDFToPS: Cannot open input file \"%s\"",
filename);
return 1;
}
if (fread(buf, 1, 1, fp) == 0) {
fclose(fp);
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPDFToPS: Input is empty, outputting empty file.");
+ "ppdFilterPDFToPS: Input is empty, outputting empty file.");
return 1;
}
fclose(fp);
int pages = cfPDFPages(filename);
if (pages == 0) {
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPDFToPS: No pages left, outputting empty file.");
+ "ppdFilterPDFToPS: No pages left, outputting empty file.");
return 1;
}
if (pages > 0)
return;
/* Debug output: Full command line of program to be called */
- snprintf(buf, sizeof(buf) - 1, "cfFilterPDFToPS: Running command line for %s:",
+ snprintf(buf, sizeof(buf) - 1, "ppdFilterPDFToPS: Running command line for %s:",
(file ? file : argv[0]));
if (file)
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf) - 1,
/*
- * 'cfFilterPDFToPS()' - Filter function to convert PDF input into
+ * 'ppdFilterPDFToPS()' - Filter function to convert PDF input into
* PostScript to be printed on PostScript printers
*/
int /* O - Error status */
-cfFilterPDFToPS(int inputfd, /* I - File descriptor input stream */
+ppdFilterPDFToPS(int inputfd, /* I - File descriptor input stream */
int outputfd, /* I - File descriptor output stream */
int inputseekable, /* I - Is input stream seekable? (unused) */
cf_filter_data_t *data, /* I - Job and printer data */
void *parameters) /* I - Filter-specific parameters (unused) */
{
+ ppd_filter_data_ext_t *filter_data_ext =
+ (ppd_filter_data_ext_t *)cfFilterDataGetExt(data,
+ PPD_FILTER_DATA_EXT);
renderer_t renderer = CUPS_PDFTOPS_RENDERER; /* Renderer: gs or pdftops
or acroread or pdftocairo
or hybrid */
*ptr; /* Pointer into value */
int duplex, tumble; /* Duplex settings for PPD-less
printing */
+ cups_cspace_t cspace = (cups_cspace_t)(-1);
cf_logfunc_t log = data->logfunc;
void *ld = data->logdata;
cf_filter_iscanceledfunc_t iscanceled = data->iscanceledfunc;
if (!iscanceled || !iscanceled(icd))
{
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPDFToPS: Unable to open input data stream.");
+ "ppdFilterPDFToPS: Unable to open input data stream.");
}
return (1);
if ((fd = cupsTempFd(tempfile, sizeof(tempfile))) < 0)
{
if (log) log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterPDFToPS: Unable to copy PDF file: %s", strerror(errno));
+ "ppdFilterPDFToPS: Unable to copy PDF file: %s", strerror(errno));
return (1);
}
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPDFToPS: Copying input to temp file \"%s\"",
+ "ppdFilterPDFToPS: Copying input to temp file \"%s\"",
tempfile);
while ((bytes = fread(buffer, 1, sizeof(buffer), inputfp)) > 0)
num_options = cfJoinJobOptionsAndAttrs(data, num_options, &options);
- ppd = data->ppd;
+ ppd = filter_data_ext->ppd;
/*
* Process job options...
make_model[strlen(make_model) - 1] = '\0';
}
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPDFToPS: Printer make and model: %s", make_model);
+ "ppdFilterPDFToPS: Printer make and model: %s", make_model);
/*
* Select the PDF renderer: Ghostscript (gs), Poppler (pdftops),
renderer = HYBRID;
else
if (log) log(ld, CF_LOGLEVEL_WARN,
- "cfFilterPDFToPS: Invalid value for \"pdftops-renderer\": \"%s\"",
+ "ppdFilterPDFToPS: Invalid value for \"pdftops-renderer\": \"%s\"",
val);
}
(ptr = strcasestr(make_model, "LaserWriter")))))
{
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPDFToPS: Switching to Poppler's pdftops instead of "
+ "ppdFilterPDFToPS: Switching to Poppler's pdftops instead of "
"Ghostscript for Brother, Minolta, Konica Minolta, Dell, "
"and Apple LaserWriter printers to work around bugs in the "
"printer's PS interpreters");
if (!*ptr) /* End of string, no further word */
{
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPDFToPS: Switching to Poppler's pdftops instead of "
+ "ppdFilterPDFToPS: Switching to Poppler's pdftops instead of "
"Ghostscript for old HP LaserJet (\"LaserJet "
"<number>\", no letters before <number>, no "
"additional words after <number>) printers to "
pstops_filter_data.printer_attrs = NULL;
pstops_filter_data.num_options = num_pstops_options;
pstops_filter_data.options = pstops_options;
- pstops_filter_data.ppdfile = NULL;
- pstops_filter_data.ppd = ppd;
+ pstops_filter_data.extension = data->extension;
pstops_filter_data.logfunc = log;
pstops_filter_data.logdata = ld;
pstops_filter_data.iscanceledfunc = iscanceled;
}
/*
- * Build the command-line for the cfFilterPDFToPS, gs, mutool, pdftocairo, or
+ * Build the command-line for the ppdFilterPDFToPS, gs, mutool, pdftocairo, or
* acroread filter...
*/
else if (renderer == PDFTOCAIRO)
{
if (log) log(ld, CF_LOGLEVEL_WARN,
- "cfFilterPDFToPS: Level 1 PostScript not supported by "
+ "ppdFilterPDFToPS: Level 1 PostScript not supported by "
"pdftocairo.");
}
else if (renderer == ACROREAD)
{
if (log) log(ld, CF_LOGLEVEL_WARN,
- "cfFilterPDFToPS: Level 1 PostScript not supported by acroread.");
+ "ppdFilterPDFToPS: Level 1 PostScript not supported by acroread.");
}
else if (renderer == MUPDF)
{
if (log) log(ld, CF_LOGLEVEL_WARN,
- "cfFilterPDFToPS: Level 1 PostScript not supported by mutool.");
+ "ppdFilterPDFToPS: Level 1 PostScript not supported by mutool.");
}
}
else if (ppd->language_level == 2)
else if (renderer == MUPDF)
{
if (log) log(ld, CF_LOGLEVEL_WARN,
- "cfFilterPDFToPS: Level 3 PostScript not supported by mutool.");
+ "ppdFilterPDFToPS: Level 3 PostScript not supported by mutool.");
}
else /* PDFTOCAIRO || ACROREAD */
pdf_argv[pdf_argc++] = (char *)"-level3";
if ((xres == 0) && (yres == 0) &&
((numvalues = sscanf(resolution, "%dx%d", &xres, &yres)) <= 0))
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPDFToPS: No resolution information found in the PPD file.");
+ "ppdFilterPDFToPS: No resolution information found in the PPD file.");
}
else{
- cfRasterParseIPPOptions(&header, data, 0, 1);
+ cfRasterPrepareHeader(&header, data, CF_FILTER_OUT_FORMAT_CUPS_RASTER,
+ CF_FILTER_OUT_FORMAT_CUPS_RASTER, 0, &cspace);
if (header.HWResolution[0] > 100 && header.HWResolution[1] > 100)
{
xres = header.HWResolution[0];
strcasecmp(ptr, "dpcm")))
{
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPDFToPS: Bad resolution value \"%s\".", val);
+ "ppdFilterPDFToPS: Bad resolution value \"%s\".", val);
}
else
{
maxres = mres;
else
if (log) log(ld, CF_LOGLEVEL_WARN,
- "cfFilterPDFToPS: Invalid value for "
+ "ppdFilterPDFToPS: Invalid value for "
"\"pdftops-max-image-resolution\": \"%s\"",
val);
}
snprintf(resolution, sizeof(resolution), "%d", res);
pdf_argv[pdf_argc++] = resolution;
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPDFToPS: Using image rendering resolution %d dpi", res);
+ "ppdFilterPDFToPS: Using image rendering resolution %d dpi", res);
#endif /* HAVE_POPPLER_PDFTOPS_WITH_RESOLUTION */
if (gray_output == 1) /* Checking for monochrome/grayscale PostScript
output */
pdf_argv[pdf_argc++] = (char *)"-optimizecolorspace"; */
/* Issue a warning message when printing a grayscale job with Poppler */
if (log) log(ld, CF_LOGLEVEL_WARN,
- "cfFilterPDFToPS: Grayscale/monochrome printing requested for this "
+ "ppdFilterPDFToPS: Grayscale/monochrome printing requested for this "
"job but Poppler is not able to convert to "
"grayscale/monochrome PostScript.");
if (log) log(ld, CF_LOGLEVEL_WARN,
- "cfFilterPDFToPS: Use \"pdftops-renderer\" option (see "
+ "ppdFilterPDFToPS: Use \"pdftops-renderer\" option (see "
"cups-filters README file) to use Ghostscript or MuPDF for "
"the PDF -> PostScript conversion.");
}
snprintf(resolution, 127, "-r%d", res);
pdf_argv[pdf_argc++] = resolution;
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPDFToPS: Using image rendering resolution %d dpi", res);
+ "ppdFilterPDFToPS: Using image rendering resolution %d dpi", res);
/*
* PostScript debug mode: If you send a job with "lpr -o psdebug" Ghostscript
* will not compress the pages, so that the PostScript code can get
!strncasecmp(make_model, "Utax", 4))))
{
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPDFToPS: Deactivated compression of pages in "
+ "ppdFilterPDFToPS: Deactivated compression of pages in "
"Ghostscript's PostScript output (\"psdebug\" debug mode "
"or Kyocera/Utax printer)");
pdf_argv[pdf_argc++] = (char *)"-dCompressPages=false";
!strncasecmp(make_model, "Brother", 7))
{
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPDFToPS: Deactivation of Ghostscript's image compression "
+ "ppdFilterPDFToPS: Deactivation of Ghostscript's image compression "
"for Brother printers to workarounmd PS interpreter bug");
pdf_argv[pdf_argc++] = (char *)"-dEncodeMonoImages=false";
pdf_argv[pdf_argc++] = (char *)"-dEncodeColorImages=false";
!strncasecmp(make_model, "Toshiba", 7))
{
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPDFToPS: To work around a bug in Toshiba's PS "
+ "ppdFilterPDFToPS: To work around a bug in Toshiba's PS "
"interpreters turn TTF font glyphs into bitmaps, usually "
"Type 3 PS fonts, or images for large characters");
pdf_argv[pdf_argc++] = (char *)"-dHaveTrueTypes=false";
if (pipe(pstops_pipe))
{
if (log) log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterPDFToPS: Unable to create pipe for cfFilterPSToPS: %s",
+ "ppdFilterPDFToPS: Unable to create pipe for ppdFilterPSToPS: %s",
strerror(errno));
exit_status = 1;
if (pipe(post_proc_pipe))
{
if (log) log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterPDFToPS: Unable to create pipe for post-processing: %s",
+ "ppdFilterPDFToPS: Unable to create pipe for post-processing: %s",
strerror(errno));
exit_status = 1;
{
execvp(CUPS_POPPLER_PDFTOPS, pdf_argv);
if (log) log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterPDFToPS: Unable to execute pdftops program: %s",
+ "ppdFilterPDFToPS: Unable to execute pdftops program: %s",
strerror(errno));
}
else if (renderer == GS)
{
execvp(CUPS_GHOSTSCRIPT, pdf_argv);
if (log) log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterPDFToPS: Unable to execute gs program: %s",
+ "ppdFilterPDFToPS: Unable to execute gs program: %s",
strerror(errno));
}
else if (renderer == PDFTOCAIRO)
{
execvp(CUPS_POPPLER_PDFTOCAIRO, pdf_argv);
if (log) log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterPDFToPS: Unable to execute pdftocairo program: %s",
+ "ppdFilterPDFToPS: Unable to execute pdftocairo program: %s",
strerror(errno));
}
else if (renderer == ACROREAD)
execvp(CUPS_ACROREAD, pdf_argv);
if (log) log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterPDFToPS: Unable to execute acroread program: %s",
+ "ppdFilterPDFToPS: Unable to execute acroread program: %s",
strerror(errno));
}
else if (renderer == MUPDF)
{
execvp(CUPS_MUTOOL, pdf_argv);
if (log) log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterPDFToPS: Unable to execute mutool program: %s",
+ "ppdFilterPDFToPS: Unable to execute mutool program: %s",
strerror(errno));
}
{
if (renderer == PDFTOPS)
log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterPDFToPS: Unable to execute pdftops program: %s",
+ "ppdFilterPDFToPS: Unable to execute pdftops program: %s",
strerror(errno));
else if (renderer == GS)
log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterPDFToPS: Unable to execute gs program: %s",
+ "ppdFilterPDFToPS: Unable to execute gs program: %s",
strerror(errno));
else if (renderer == PDFTOCAIRO)
log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterPDFToPS: Unable to execute pdftocairo program: %s",
+ "ppdFilterPDFToPS: Unable to execute pdftocairo program: %s",
strerror(errno));
else if (renderer == ACROREAD)
log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterPDFToPS: Unable to execute acroread program: %s",
+ "ppdFilterPDFToPS: Unable to execute acroread program: %s",
strerror(errno));
else if (renderer == MUPDF)
log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterPDFToPS: Unable to execute mutool program: %s",
+ "ppdFilterPDFToPS: Unable to execute mutool program: %s",
strerror(errno));
}
}
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPDFToPS: Started filter %s (PID %d)", pdf_argv[0], pdf_pid);
+ "ppdFilterPDFToPS: Started filter %s (PID %d)", pdf_argv[0], pdf_pid);
if (need_post_proc)
{
{
/* No Prolog section, create one */
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPDFToPS: Adding Prolog section for workaround "
+ "ppdFilterPDFToPS: Adding Prolog section for workaround "
"PostScript code");
puts("%%BeginProlog");
}
!strncasecmp(make_model, "Utax", 4))
{
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPDFToPS: Inserted workaround PostScript code for "
+ "ppdFilterPDFToPS: Inserted workaround PostScript code for "
"Kyocera and Utax printers");
puts("% ===== Workaround insertion by pdftops CUPS filter =====");
puts("% Kyocera's/Utax's PostScript interpreter crashes on "
else if (!strncasecmp(make_model, "Brother", 7))
{
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPDFToPS: Inserted workaround PostScript code for "
+ "ppdFilterPDFToPS: Inserted workaround PostScript code for "
"Brother printers");
puts("% ===== Workaround insertion by pdftops CUPS filter =====");
puts("% Brother's PostScript interpreter spits out the current "
{
/* No Setup section, create one */
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPDFToPS: Adding Setup section for option "
+ "ppdFilterPDFToPS: Adding Setup section for option "
"PostScript code");
puts("%%BeginSetup");
}
*/
if (log) log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterPDFToPS: Unable to execute post-processing process: %s",
+ "ppdFilterPDFToPS: Unable to execute post-processing process: %s",
strerror(errno));
exit_status = 1;
}
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPDFToPS: Started post-processing (PID %d)", post_proc_pid);
+ "ppdFilterPDFToPS: Started post-processing (PID %d)", post_proc_pid);
}
if (ppd)
close(post_proc_pipe[1]);
}
- ret = cfFilterPSToPS(pstops_pipe[0], outputfd, 0, &pstops_filter_data, NULL);
+ ret = ppdFilterPSToPS(pstops_pipe[0], outputfd, 0, &pstops_filter_data, NULL);
close(pstops_pipe[0]);
if (ret && log) log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterPDFToPS: pstops filter function failed.");
+ "ppdFilterPDFToPS: pstops filter function failed.");
close(outputfd);
exit(ret);
*/
if (log) log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterPDFToPS: Unable to execute pstops program: %s",
+ "ppdFilterPDFToPS: Unable to execute pstops program: %s",
strerror(errno));
exit_status = 1;
}
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPDFToPS: Started filter pstops (PID %d)", pstops_pid);
+ "ppdFilterPDFToPS: Started filter pstops (PID %d)", pstops_pid);
close(pstops_pipe[0]);
close(pstops_pipe[1]);
exit_status = WEXITSTATUS(wait_status);
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPDFToPS: PID %d (%s) stopped with status %d!",
+ "ppdFilterPDFToPS: PID %d (%s) stopped with status %d!",
wait_pid,
wait_pid == pdf_pid ?
(renderer == PDFTOPS ? "pdftops" :
else if (WTERMSIG(wait_status) == SIGTERM)
{
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPDFToPS: PID %d (%s) was terminated normally with "
+ "ppdFilterPDFToPS: PID %d (%s) was terminated normally with "
"signal %d!",
wait_pid,
wait_pid == pdf_pid ?
exit_status = WTERMSIG(wait_status);
if (log) log(ld, CF_LOGLEVEL_ERROR,
- "cfFilterPDFToPS: PID %d (%s) crashed on signal %d!",
+ "ppdFilterPDFToPS: PID %d (%s) crashed on signal %d!",
wait_pid,
wait_pid == pdf_pid ?
(renderer == PDFTOPS ? "pdftops" :
else
{
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPDFToPS: PID %d (%s) exited with no errors.",
+ "ppdFilterPDFToPS: PID %d (%s) exited with no errors.",
wait_pid,
wait_pid == pdf_pid ?
(renderer == PDFTOPS ? "pdftops" :
error:
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterPDFToPS: Closing files ...");
+ "ppdFilterPDFToPS: Closing files ...");
close(outputfd);
# include <unistd.h>
#endif /* _WIN32 || __EMX__ */
#include <errno.h>
+#include <ctype.h>
+#include <string.h>
/*
*/
static int ppd_compare_cparams(ppd_cparam_t *a, ppd_cparam_t *b);
-static void ppd_handle_media(ppd_file_t *ppd);
/*
/*
- * 'ppdEmitJCL()' - Emit code for JCL options to a file.
+ * 'ppdEmitJCL()' - Emit code for JCL options to a file (for PostScript
+ * output).
*/
int /* O - 0 on success, -1 on failure */
const char *user, /* I - Username */
const char *title) /* I - Title */
{
+ return ppdEmitJCLPDF(ppd, fp, job_id, user, title, -1, false);
+}
+
+
+/*
+ * 'ppdEmitJCLPDF()' - Emit code for JCL options to a file (for PDF output).
+ */
+
+int /* O - 0 on success, -1 on failure */
+ppdEmitJCLPDF(ppd_file_t *ppd, /* I - PPD file record */
+ FILE *fp, /* I - File to write to */
+ int job_id, /* I - Job ID */
+ const char *user, /* I - Username */
+ const char *title, /* I - Title */
+ int hw_copies, /* I - Number of hardware (device)
+ copies, -1: PS mode */
+ bool hw_collate) /* I - Do we have hardware (device)
+ collate? */
+{
+ ppd_attr_t *attr; /* PPD attribute */
+ const char *jcl_pdf = NULL;
char *ptr; /* Pointer into JCL string */
char temp[65], /* Local title string */
displaymsg[33]; /* Local display string */
* Range check the input...
*/
- if (!ppd || !ppd->jcl_begin || !ppd->jcl_ps)
+
+ if (!ppd || !ppd->jcl_begin)
+ return (0);
+
+#if HAVE_CUPS_3_X
+ jcl_pdf = ppd->jcl_pdf;
+#else
+ if ((attr = ppdFindAttr(ppd, "JCLToPDFInterpreter", NULL)) != NULL)
+ jcl_pdf = attr->value;
+#endif
+
+ if ((!ppd->jcl_ps && hw_copies < 0) ||
+ (!jcl_pdf && hw_copies >= 0))
return (0);
/*
fputs(ppd->jcl_begin, fp);
ppdEmit(ppd, fp, PPD_ORDER_JCL);
- fputs(ppd->jcl_ps, fp);
+
+ if (hw_copies < 0)
+ /* PostScript output */
+ fputs(ppd->jcl_ps, fp);
+ else
+ {
+ /* PDF output */
+
+ int hw_copies_done = 0;
+
+ /* There is a "Copies" option in the PPD file, so this option setting
+ always takes care of correct implementation of the copies */
+ if (ppdFindOption(ppd,"Copies") != NULL &&
+ hw_copies > 1)
+ hw_copies_done = 1;
+
+ if (hw_copies > 1 && hw_copies_done == 0 && // HW copies
+ strncmp(ppd->jcl_begin, "\033%-12345X@", 10) == 0) // PJL
+ /* Add a PJL command to implement the hardware copies */
+ fprintf(fp, "@PJL SET %s=%d\n", hw_collate ? "QTY" : "COPIES",
+ hw_copies);
+
+ fputs(jcl_pdf, fp);
+ }
return (0);
}
* Use PageSize or PageRegion as required...
*/
- ppd_handle_media(ppd);
+ ppdHandleMedia(ppd);
/*
* Collect the options we need to emit...
/*
- * 'ppd_compare_cparams()' - Compare the order of two custom parameters.
- */
-
-static int /* O - Result of comparison */
-ppd_compare_cparams(ppd_cparam_t *a, /* I - First parameter */
- ppd_cparam_t *b) /* I - Second parameter */
-{
- return (a->order - b->order);
-}
-
-
-/*
- * 'ppd_handle_media()' - Handle media selection...
+ * 'ppdHandleMedia()' - Handle media selection...
*/
-static void
-ppd_handle_media(ppd_file_t *ppd) /* I - PPD file */
+void
+ppdHandleMedia(ppd_file_t *ppd) /* I - PPD file */
{
ppd_choice_t *manual_feed, /* ManualFeed choice, if any */
*input_slot; /* InputSlot choice, if any */
}
}
}
+
+
+/*
+ * 'ppd_compare_cparams()' - Compare the order of two custom parameters.
+ */
+
+static int /* O - Result of comparison */
+ppd_compare_cparams(ppd_cparam_t *a, /* I - First parameter */
+ ppd_cparam_t *b) /* I - Second parameter */
+{
+ return (a->order - b->order);
+}
--- /dev/null
+/*
+ * Filter functions support for libppd.
+ *
+ * Copyright © 2020-2022 by Till Kamppeter.
+ *
+ * Licensed under Apache License v2.0. See the file "LICENSE" for more
+ * information.
+ */
+
+/*
+ * Include necessary headers...
+ */
+
+#include "config.h"
+#include "ppd-filter.h"
+#include "ppd.h"
+#include <limits.h>
+#include <math.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <ctype.h>
+#include <sys/wait.h>
+#include <cups/file.h>
+#include <cups/array.h>
+
+extern char **environ;
+
+/*
+ * 'ppdFilterCUPSWrapper()' - Wrapper function to use a filter function as
+ * classic CUPS filter
+ */
+
+int /* O - Exit status */
+ppdFilterCUPSWrapper(
+ int argc, /* I - Number of command-line args */
+ char *argv[], /* I - Command-line arguments */
+ cf_filter_function_t filter, /* I - Filter function */
+ void *parameters, /* I - Filter function parameters */
+ int *JobCanceled) /* I - Var set to 1 when job canceled */
+{
+ int inputfd; /* Print file descriptor*/
+ int inputseekable; /* Is the input seekable (actual file
+ not stdin)? */
+ int num_options; /* Number of print options */
+ cups_option_t *options; /* Print options */
+ cf_filter_data_t filter_data;
+ const char *val;
+ char buf[256];
+ int retval = 0;
+
+
+ /*
+ * Make sure status messages are not buffered...
+ */
+
+ setbuf(stderr, NULL);
+
+ /*
+ * Ignore broken pipe signals...
+ */
+
+ signal(SIGPIPE, SIG_IGN);
+
+ /*
+ * Check command-line...
+ */
+
+ if (argc < 6 || argc > 7)
+ {
+ fprintf(stderr, "Usage: %s job-id user title copies options [file]\n",
+ argv[0]);
+ return (1);
+ }
+
+ /*
+ * If we have 7 arguments, print the file named on the command-line.
+ * Otherwise, send stdin instead...
+ */
+
+ if (argc == 6)
+ {
+ inputfd = 0; /* stdin */
+ inputseekable = 0;
+ }
+ else
+ {
+ /*
+ * Try to open the print file...
+ */
+
+ if ((inputfd = open(argv[6], O_RDONLY)) < 0)
+ {
+ if (!JobCanceled)
+ {
+ fprintf(stderr, "DEBUG: Unable to open \"%s\": %s\n", argv[6],
+ strerror(errno));
+ fprintf(stderr, "ERROR: Unable to open print file");
+ }
+
+ return (1);
+ }
+
+ inputseekable = 1;
+ }
+
+ /*
+ * Process command-line options...
+ */
+
+ options = NULL;
+ num_options = cupsParseOptions(argv[5], 0, &options);
+
+ if ((filter_data.printer = getenv("PRINTER")) == NULL)
+ filter_data.printer = argv[0];
+ filter_data.job_id = atoi(argv[1]);
+ filter_data.job_user = argv[2];
+ filter_data.job_title = argv[3];
+ filter_data.copies = atoi(argv[4]);
+ filter_data.content_type = getenv("CONTENT_TYPE");
+ filter_data.final_content_type = getenv("FINAL_CONTENT_TYPE");
+ filter_data.job_attrs = NULL; /* We use command line options */
+ /* The following two will get populated by ppdFilterLoadPPD() */
+ filter_data.printer_attrs = NULL; /* We use the queue's PPD file */
+ filter_data.header = NULL; /* CUPS Raster header of queue's PPD */
+ filter_data.num_options = num_options;
+ filter_data.options = options; /* Command line options from 5th arg */
+ filter_data.back_pipe[0] = 3; /* CUPS uses file descriptor 3 for */
+ filter_data.back_pipe[1] = 3; /* the back channel */
+ filter_data.side_pipe[0] = 4; /* CUPS uses file descriptor 4 for */
+ filter_data.side_pipe[1] = 4; /* the side channel */
+ filter_data.extension = NULL;
+ filter_data.logfunc = cfCUPSLogFunc; /* Logging scheme of CUPS */
+ filter_data.logdata = NULL;
+ filter_data.iscanceledfunc = cfCUPSIsCanceledFunc; /* Job-is-canceled
+ function */
+ filter_data.iscanceleddata = JobCanceled;
+
+ /*
+ * CUPS_FONTPATH (Usually /usr/share/cups/fonts)
+ */
+
+ if (cupsGetOption("cups-fontpath",
+ filter_data.num_options, filter_data.options) == NULL)
+ {
+ if ((val = getenv("CUPS_FONTPATH")) == NULL)
+ {
+ val = CUPS_DATADIR;
+ snprintf(buf, sizeof(buf), "%s/fonts", val);
+ val = buf;
+ }
+ if (val[0] != '\0')
+ filter_data.num_options =
+ cupsAddOption("cups-fontpath", val,
+ filter_data.num_options, &(filter_data.options));
+ }
+
+ /*
+ * Load and prepare the PPD file, also attach it as extension "libppd"
+ * to the filter_data structure
+ */
+
+ retval = ppdFilterLoadPPDFile(&filter_data, getenv("PPD"));
+
+ /*
+ * Fire up the filter function (output to stdout, file descriptor 1)
+ */
+
+ if (!retval)
+ retval = filter(inputfd, 1, inputseekable, &filter_data, parameters);
+
+ /*
+ * Clean up
+ */
+
+ cupsFreeOptions(filter_data.num_options, filter_data.options);
+ ppdFilterFreePPDFile(&filter_data);
+
+ return retval;
+}
+
+
+/*
+ * 'ppdFilterLoadPPDFile()' - When preparing the filter data structure
+ * for calling one or more filter
+ * functions, load the PPD file specified
+ * by its file name. If the file name is
+ * NULL or empty, do nothing. If the PPD
+ * got successfully loaded add its data to
+ * the filter data structure as extension
+ * named "libppd", so that filters
+ * functions designed for using PPDs can
+ * access it. Then read out all the
+ * relevant data with the
+ * ppdFilterLoadPPD() function.
+ */
+
+int /* O - Error status */
+ppdFilterLoadPPDFile(cf_filter_data_t *data, /* I/O - Job and printer data */
+ const char *ppdfile) /* I - PPD file name */
+{
+ ppd_filter_data_ext_t *filter_data_ext; /* Record for "libppd" extension */
+ ppd_file_t *ppd; /* PPD data */
+ cf_logfunc_t log = data->logfunc; /* Log function */
+ void *ld = data->logdata; /* log function data */
+
+ if (!ppdfile || !ppdfile[0])
+ return (-1);
+
+ if ((ppd = ppdOpenFile(ppdfile)) == NULL)
+ {
+ if (log) log(ld, CF_LOGLEVEL_ERROR,
+ "ppdFilterLoadPPDFile: Could not load PPD file %s: %s",
+ ppdfile, strerror(errno));
+ return (-1);
+ }
+
+ filter_data_ext =
+ (ppd_filter_data_ext_t *)calloc(1, sizeof(ppd_filter_data_ext_t));
+
+ filter_data_ext->ppdfile = strdup(ppdfile); /* PPD file name */
+ filter_data_ext->ppd = ppd; /* PPD data */
+ cfFilterDataAddExt(data, PPD_FILTER_DATA_EXT, filter_data_ext);
+
+ return ppdFilterLoadPPD(data);
+}
+
+
+/*
+ * 'ppdFilterLoadPPD()' - When preparing the filter data structure for
+ * calling one or more filter functions, and a
+ * PPD file is attached as "libppd" extension,
+ * set up the PPD's cache, mark default
+ * settings and if supplied in the data
+ * structure, also option settings. Then
+ * convert the capability and option info in
+ * the PPD file into printer IPP attributes and
+ * what cannot be represented in IPP as option
+ * settings and add these results to the filter
+ * data structure. This allows to use the (by
+ * itself not PPD-supporting) filter function
+ * to do its work for the printer represented
+ * by the PPD file. Add the CUPS PPD file data
+ * structure with embedded CUPS PPD cache data
+ * structure (including PPD option setting
+ * presets for all possible print-color-mode,
+ * print-quality, and print-content-optimize
+ * settings) to the filter data structure for
+ * use by libppd's PPD-requiring filter
+ * functions.
+ */
+
+int /* O - Error status */
+ppdFilterLoadPPD(cf_filter_data_t *data) /* I/O - Job and printer data */
+{
+ int i;
+ ppd_filter_data_ext_t *filter_data_ext =
+ (ppd_filter_data_ext_t *)cfFilterDataGetExt(data,
+ PPD_FILTER_DATA_EXT);
+ ppd_file_t *ppd;
+ int num_job_attr_options = 0;
+ cups_option_t *job_attr_options = NULL;
+ cups_option_t *opt;
+ ppd_attr_t *ppd_attr;
+ ppd_choice_t *choice;
+ ipp_attribute_t *attr;
+ ipp_t *col;
+ const char *val;
+ char *lastfilter = NULL;
+ bool hw_copies = false,
+ hw_collate = false;
+ const char *page_size, *media;
+ const char *q1_choice, *q2_choice, *q3_choice;
+ char buf[1024];
+ char cm_qualifier_tmp[1024];
+ const char *cm_profile_key;
+ char *resolution, /* Output resolution */
+ *media_type; /* Media type */
+ ppd_profile_t *profile; /* Color profile */
+ cf_logfunc_t log = data->logfunc; /* Log function */
+ void *ld = data->logdata; /* log function data */
+
+ if (!filter_data_ext || !filter_data_ext->ppd)
+ return (-1);
+
+ /*
+ * Prepare PPD file and mark options
+ */
+
+ ppd = filter_data_ext->ppd;
+ ppd->cache = ppdCacheCreateWithPPD(ppd);
+ ppdMarkDefaults(ppd);
+ ppdMarkOptions(ppd, data->num_options, data->options);
+ num_job_attr_options = ppdGetOptions(&job_attr_options, data->printer_attrs,
+ data->job_attrs, ppd);
+ for(i = 0, opt = job_attr_options; i < num_job_attr_options; i++, opt++)
+ data->num_options = cupsAddOption(opt->name, opt->value,
+ data->num_options, &(data->options));
+ cupsFreeOptions(num_job_attr_options, job_attr_options);
+ ppdMarkOptions(ppd, data->num_options, data->options);
+ ppdHandleMedia(ppd);
+
+ /*
+ * Pass on PPD attributes
+ */
+
+ /* Pass on "PWGRaster" PPD attribute (for PWG Raster output) */
+ if ((ppd_attr = ppdFindAttr(ppd, "PWGRaster", 0)) != 0 &&
+ (!strcasecmp(ppd_attr->value, "true") ||
+ !strcasecmp(ppd_attr->value, "on") ||
+ !strcasecmp(ppd_attr->value, "yes")))
+ data->num_options = cupsAddOption("media-class", "PwgRaster",
+ data->num_options, &(data->options));
+
+ /* Pass on "cupsEvenDuplex" PPD attribute */
+ if ((ppd_attr = ppdFindAttr(ppd, "cupsEvenDuplex", 0)) != NULL)
+ data->num_options = cupsAddOption("even-duplex", ppd_attr->value,
+ data->num_options, &(data->options));
+
+ /* Pass on "cupsBackSide" (or "cupsFlipDuplex") PPD attribute */
+ if ((ppd_attr = ppdFindAttr(ppd, "cupsBackSide", 0)) != NULL)
+ {
+ ppd->flip_duplex = 0; /* "cupsBackSide" has priority */
+ data->num_options = cupsAddOption("back-side-orientation", ppd_attr->value,
+ data->num_options, &(data->options));
+ }
+ else if (ppd->flip_duplex) /* "cupsFlipDuplex" same as "Rotated" */
+ data->num_options = cupsAddOption("back-side-orientation", "Rotated",
+ data->num_options, &(data->options));
+
+ /* Pass on "APDuplexRequiresFlippedMargin" PPD attribute */
+ if ((ppd_attr = ppdFindAttr(ppd, "APDuplexRequiresFlippedMargin", 0)) != NULL)
+ data->num_options = cupsAddOption("duplex-requires-flipped-margin",
+ ppd_attr->value,
+ data->num_options, &(data->options));
+
+ /* Pass on "cupsRasterVersion" PPD attribute */
+ if ((ppd_attr = ppdFindAttr(ppd,"cupsRasterVersion", 0)) != NULL)
+ data->num_options = cupsAddOption("cups-raster-version",
+ ppd_attr->value,
+ data->num_options, &(data->options));
+
+ /* Pass on "DefaultCenterOfPixel" PPD attribute (for Ghostscript) */
+ if ((ppd_attr = ppdFindAttr(ppd,"DefaultCenterOfPixel", 0)) != NULL)
+ data->num_options = cupsAddOption("center-of-pixel",
+ ppd_attr->value,
+ data->num_options, &(data->options));
+
+ /* Set short-edge Duplex when booklet printing is selected */
+ if ((val = cupsGetOption("booklet",
+ data->num_options, data->options)) != NULL &&
+ (!strcasecmp(val, "on") || !strcasecmp(val, "yes") ||
+ !strcasecmp(val, "true")) &&
+ ppd->cache->sides_option &&
+ ppd->cache->sides_2sided_short &&
+ ppdFindOption(ppd, ppd->cache->sides_option))
+ ppdMarkOption(ppd, ppd->cache->sides_option,
+ ppd->cache->sides_2sided_short);
+
+ /* Let the PDF filter do mirrored printing */
+ if ((choice = ppdFindMarkedChoice(ppd, "MirrorPrint")) != NULL)
+ {
+ choice->marked = 0;
+ data->num_options = cupsAddOption("mirror", "true",
+ data->num_options, &(data->options));
+ }
+
+ /*
+ * Find out whether we can do hardware copies/collate
+ */
+
+ if (data->copies == 1)
+ {
+ /* 1 copy, hardware copies/collate do not make difference */
+ hw_copies = false;
+ hw_collate = false;
+ }
+ else if (!ppd->manual_copies)
+ {
+ /* Hardware copy generation available */
+ hw_copies = true;
+ /* Check output format (FINAL_CONTENT_TYPE env variable) whether it is
+ of a driverless IPP printer (PDF, Apple Raster, PWG Raster, PCLm).
+ These printers do always hardware collate if they do hardware copies.
+ https://github.com/apple/cups/issues/5433
+ This also assumes that if a classic PDF printer (non-IPP printer printing
+ with JCL/PJL-controlled PDF) supports hardware copies that it also does
+ hardware collate */
+ if (data->final_content_type &&
+ (strcasestr(data->final_content_type, "/pdf") ||
+ strcasestr(data->final_content_type, "/vnd.cups-pdf") ||
+ strcasestr(data->final_content_type, "/pwg-raster") ||
+ strcasestr(data->final_content_type, "/urf") ||
+ strcasestr(data->final_content_type, "/PCLm")))
+ {
+ /* If PPD has "Collate" option set to not collate, do not set
+ hw_collate, especially important to set correct JCL/PJL on
+ "classic" PDF printers (they will always collate otherwise) */
+ if ((choice = ppdFindMarkedChoice(ppd, "Collate")) != NULL &&
+ (!strcasecmp(choice->choice, "off") ||
+ !strcasecmp(choice->choice, "no") ||
+ !strcasecmp(choice->choice, "false")))
+ hw_collate = false;
+ else
+ hw_collate = true;
+ }
+ else
+ {
+ /* Check whether printer hardware-collates with current PPD settings */
+ if ((choice = ppdFindMarkedChoice(ppd, "Collate")) != NULL &&
+ (!strcasecmp(choice->choice, "on") ||
+ !strcasecmp(choice->choice, "yes") ||
+ !strcasecmp(choice->choice, "true")))
+ {
+ /* Printer can collate, but also for the currently marked PPD
+ features? */
+ ppd_option_t *opt = ppdFindOption(ppd, "Collate");
+ hw_collate = (opt && !opt->conflicted);
+ }
+ else
+ hw_collate = false;
+ }
+ }
+ else
+ {
+ /* We have "*cupsManualCopies: True" =>
+ Software copies/collate */
+ hw_copies = false;
+ hw_collate = false;
+ }
+
+ if (!hw_copies)
+ {
+ /* Software copies */
+ /* Make sure any hardware copying is disabled */
+ ppdMarkOption(ppd, "Copies", "1");
+ ppdMarkOption(ppd, "JCLCopies", "1");
+ }
+ else
+ {
+ /* Hardware copies */
+ /* If there is a "Copies" option in the PPD file, assure that hardware
+ copies are implemented as described by this option */
+ snprintf(buf, sizeof(buf), "%d", hw_copies);
+ ppdMarkOption(ppd, "Copies", buf);
+ }
+
+ /* Software collate */
+ if (!hw_collate)
+ /* Disable any hardware collate (in JCL) */
+ ppdMarkOption(ppd, "Collate", "False");
+
+ /* Add options telling whether we want hardware copies/collate or not */
+ data->num_options = cupsAddOption("hardware-copies",
+ (hw_copies ? "true" : "false"),
+ data->num_options, &(data->options));
+ data->num_options = cupsAddOption("hardware-collate",
+ (hw_collate ? "true" : "false"),
+ data->num_options, &(data->options));
+
+ /*
+ * Pass on color management attributes
+ */
+
+ /* Get color space */
+ if ((ppd_attr = ppdFindAttr (ppd, "cupsICCQualifier1", NULL)) != NULL &&
+ ppd_attr->value && ppd_attr->value[0])
+ choice = ppdFindMarkedChoice(ppd, ppd_attr->value);
+ else if ((choice = ppdFindMarkedChoice(ppd, "ColorModel")) == NULL)
+ choice = ppdFindMarkedChoice(ppd, "ColorSpace");
+ if (choice && choice->choice && choice->choice[0])
+ q1_choice = choice->choice;
+ else
+ q1_choice = "";
+
+ /* Get media type */
+ if ((ppd_attr = ppdFindAttr(ppd, "cupsICCQualifier2", NULL)) != NULL &&
+ ppd_attr->value && ppd_attr->value[0])
+ choice = ppdFindMarkedChoice(ppd, ppd_attr->value);
+ else
+ choice = ppdFindMarkedChoice(ppd, "MediaType");
+ if (choice && choice->choice && choice->choice[0])
+ q2_choice = choice->choice;
+ else
+ q2_choice = "";
+
+ /* Get resolution */
+ if ((ppd_attr = ppdFindAttr(ppd, "cupsICCQualifier3", NULL)) != NULL &&
+ ppd_attr->value && ppd_attr->value[0])
+ choice = ppdFindMarkedChoice(ppd, ppd_attr->value);
+ else
+ choice = ppdFindMarkedChoice(ppd, "Resolution");
+ if (choice && choice->choice && choice->choice[0])
+ q3_choice = choice->choice;
+ else
+ {
+ ppd_attr = ppdFindAttr(ppd, "DefaultResolution", NULL);
+ if (ppd_attr && ppd_attr->value && ppd_attr->value[0])
+ q3_choice = ppd_attr->value;
+ else
+ q3_choice = "";
+ }
+
+ /* create a string for the option */
+ snprintf(cm_qualifier_tmp, sizeof(cm_qualifier_tmp),
+ "%s.%s.%s", q1_choice, q2_choice, q3_choice);
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "ppdFilterLoadPPD: Color profile qualifier determined from job and PPD data '%s'",
+ cm_qualifier_tmp);
+
+ /* Supply qualifier as option */
+ data->num_options = cupsAddOption("cm-profile-qualifier", cm_qualifier_tmp,
+ data->num_options, &(data->options));
+
+ /* get profile attr, falling back to CUPS */
+ cm_profile_key = "APTiogaProfile";
+ ppd_attr = ppdFindAttr(ppd, cm_profile_key, NULL);
+ if (ppd_attr == NULL)
+ {
+ cm_profile_key = "cupsICCProfile";
+ ppd_attr = ppdFindAttr(ppd, cm_profile_key, NULL);
+ }
+
+ if (ppd_attr == NULL)
+ {
+ /* neither */
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "ppdFilterLoadPPD: No ICC profiles specified in PPD");
+ }
+ else
+ {
+ /* Try to find a profile that matches the qualifier exactly */
+ for (;ppd_attr != NULL;
+ ppd_attr = ppdFindNextAttr(ppd, cm_profile_key, NULL))
+ {
+ /* Invalid entry */
+ if (ppd_attr->spec == NULL || ppd_attr->value == NULL)
+ continue;
+
+ /* Matches the qualifier */
+ if (strcmp(cm_qualifier_tmp, ppd_attr->spec) == 0)
+ {
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "ppdFilterLoadPPD: Found ICC profile %s in PPD for qualifier '%s'",
+ ppd_attr->value, ppd_attr->spec);
+ break;
+ }
+ }
+
+ /* No match */
+ if (ppd_attr == NULL)
+ {
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "ppdFilterLoadPPD: No ICC profile in PPD for qualifier '%s'",
+ cm_qualifier_tmp);
+ }
+ else
+ {
+ /* expand to a full path if not already specified */
+ if (ppd_attr->value[0] != '/')
+ {
+ if ((val = getenv("CUPS_DATADIR")) == NULL)
+ val = CUPS_DATADIR;
+ snprintf(buf, sizeof(buf),
+ "%s/profiles/%s", val, ppd_attr->value);
+ }
+ else
+ {
+ strncpy(buf, ppd_attr->value, sizeof(buf) - 1);
+ if (strlen(ppd_attr->value) > 1023)
+ buf[1023] = '\0';
+ }
+
+ /* check the file exists */
+ if (access(buf, 0))
+ {
+ if (log) log(ld, CF_LOGLEVEL_ERROR,
+ "ppdFilterLoadPPD: ICC profile %s in PPD does not exist",
+ buf);
+ }
+ else
+ {
+ /* Supply path as fallback profile option */
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "ppdFilterLoadPPD: Using ICC profile %s as fallback if colord does not supply another one",
+ buf);
+ data->num_options =
+ cupsAddOption("cm-fallback-profile", buf,
+ data->num_options, &(data->options));
+ }
+ }
+ }
+
+ /*
+ * Find a color profile matching the current options...
+ */
+
+ if (cupsGetOption("profile", data->num_options, data->options) == NULL)
+ {
+ if ((choice = ppdFindMarkedChoice(ppd, "Resolution")) != NULL)
+ resolution = choice->choice;
+ else
+ resolution = "-";
+ if ((choice = ppdFindMarkedChoice(ppd, "MediaType")) != NULL)
+ media_type = choice->choice;
+ else
+ media_type = "-";
+
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "ppdFilterLoadPPD: Searching for profile \"%s/%s\"...",
+ resolution, media_type);
+
+ for (i = 0, profile = ppd->profiles; i < ppd->num_profiles;
+ i ++, profile ++)
+ {
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "ppdFilterLoadPPD: \"%s/%s\" = ", profile->resolution,
+ profile->media_type);
+
+ if ((strcmp(profile->resolution, resolution) == 0 ||
+ profile->resolution[0] == '-') &&
+ (strcmp(profile->media_type, media_type) == 0 ||
+ profile->media_type[0] == '-'))
+ {
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "ppdFilterLoadPPD: MATCH");
+ break;
+ }
+ else
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "ppdFilterLoadPPD: no.");
+ }
+
+ /*
+ * If we found a color profile, use it!
+ */
+
+ if (i >= ppd->num_profiles)
+ profile = NULL;
+ }
+ else
+ profile = NULL;
+
+ if (profile)
+ {
+ snprintf(buf, sizeof(buf),
+ "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
+ (int)(profile->density * 1000.0),
+ (int)(profile->gamma * 1000.0),
+ (int)(profile->matrix[0][0] * 1000.0),
+ (int)(profile->matrix[0][1] * 1000.0),
+ (int)(profile->matrix[0][2] * 1000.0),
+ (int)(profile->matrix[1][0] * 1000.0),
+ (int)(profile->matrix[1][1] * 1000.0),
+ (int)(profile->matrix[1][2] * 1000.0),
+ (int)(profile->matrix[2][0] * 1000.0),
+ (int)(profile->matrix[2][1] * 1000.0),
+ (int)(profile->matrix[2][2] * 1000.0));
+ data->num_options = cupsAddOption("profile", buf,
+ data->num_options, &(data->options));
+ }
+
+ /*
+ * Convert the settings and properties in the PPD into printer IPP
+ * attributes
+ */
+
+ data->printer_attrs = ppdLoadAttributes(ppd);
+
+ /*
+ * Generate a CUPS Raster sample header, some filters can easily take
+ * data from it or make it the base for actual Raster headers. The
+ * header is based on the pseudo-PostScript code at the option
+ * settings in the PPD file, this is especially a more reliable way
+ * to obtain the correct resolution.
+ *
+ * This only works if the PPD file is actually for a CUPS Raster
+ * driver, as other PPD files do not contain all resolution, page
+ * geometry and color space/depth info in pseudo-PostScript code and
+ * the ppdRasterInterpretPPD() function only parses the
+ * pseudo-PostScript code not the names of the options and choices.
+ *
+ * Therefore we create the sample header only if the PPD is actually
+ * for a CUPS Raster driver.
+ */
+
+ data->header = NULL;
+ for (i = 0; i < ppd->num_filters; i ++)
+ {
+ if (!strncasecmp(ppd->filters[i], "application/vnd.cups-raster", 27))
+ {
+ // We have a CUPS Raster driver PPD file
+ data->header =
+ (cups_page_header2_t *)calloc(1, sizeof(cups_page_header2_t));
+ if (ppdRasterInterpretPPD(data->header, ppd,
+ data->num_options, data->options, NULL) < 0)
+ {
+ if (log) log(ld, CF_LOGLEVEL_ERROR,
+ "ppdFilterLoadPPD: Unable to generate CUPS Raster sample header.");
+ free(data->header);
+ data->header = NULL;
+ }
+ break;
+ }
+ }
+
+ /*
+ * Replace the "PageSize" option by a media-col attribute, as this
+ * one selects the media much more reliably by numeric size
+ * dimensions and margins and not by name.
+ *
+ * PPDs have special page size names for page size variants (A4,
+ * A4.Borderless, A4.Duplex, A4.Transverse) which cannot get mapped
+ * into the printer IPP attributes (media-col-database) and so cannot
+ * get easily selected by the PPD-support-free core filter functions
+ * in libcupsfilters.
+ *
+ * Usually, the media-col attribute does not need to get copied from
+ * printer attributes to job attributes, but having it in the job
+ * attributes tells the filters that the user has requested a page
+ * size, as at least some filters overtake the sizes of the input
+ * pages when the user does not request a page size.
+ */
+
+ page_size = cupsGetOption("PageSize", data->num_options, data->options);
+ media = cupsGetOption("media", data->num_options, data->options);
+ if ((page_size || media) &&
+ (attr = ippFindAttribute(data->printer_attrs, "media-col-default",
+ IPP_TAG_ZERO)) != NULL)
+ {
+ /* We have already applied the settings of these options to the
+ PPD file and converted the PPD option settings into the printer
+ IPP attributes. The media size and margins corresponding to the
+ name supplied with these options is now included in the printer
+ IPP attributes as "media-col-default". Here we remove the
+ "PageSize" and "media" options and add "media-col" to the job
+ attributes as a copy of "media-col-default" in the printer
+ attributes. We do this only if the size specified by "PageSize"
+ or "media" is not a custom size ("Custom.XXxYYunit") as a
+ custom size cannot get marked in the PPD file and so not set as
+ default page size, so it does not make it into
+ media-col-default. In this case we only remove "media-col". */
+
+ int is_custom = 0;
+
+ if (page_size)
+ {
+ if (strncasecmp(page_size, "Custom.", 7) != 0)
+ data->num_options = cupsRemoveOption("PageSize", data->num_options,
+ &(data->options));
+ else
+ is_custom = 1;
+ }
+
+ if (media)
+ {
+ if ((val = strcasestr(media, "Custom.")) == NULL ||
+ (val != media && *(val - 1) != ','))
+ data->num_options = cupsRemoveOption("media", data->num_options,
+ &(data->options));
+ else
+ is_custom = 1;
+ }
+
+ data->num_options = cupsRemoveOption("media-col", data->num_options,
+ &(data->options));
+ ippDeleteAttribute(data->job_attrs,
+ ippFindAttribute(data->job_attrs, "media-col",
+ IPP_TAG_ZERO));
+
+ if (!is_custom)
+ {
+ /* String from IPP attribute for option list */
+ ippAttributeString(attr, buf, sizeof(buf));
+ data->num_options = cupsAddOption("media-col", buf,
+ data->num_options, &(data->options));
+
+ /* Copy the default media-col */
+ col = ippGetCollection(attr, 0);
+ ippAddCollection(data->job_attrs, IPP_TAG_PRINTER, "media-col", col);
+ }
+ }
+
+ /*
+ * Find out whether the PDF filter (cfFilterPDFToPDF() or
+ * cfFilterImageToPDF()) should log the pages or whether the last
+ * filter (usually the printer driver) should do it.
+ */
+
+ if ((val = cupsGetOption("pdf-filter-page-logging",
+ data->num_options, data->options)) == NULL ||
+ strcasecmp(val, "auto") == 0)
+ {
+ int page_logging = -1;
+ if (data->final_content_type == NULL)
+ {
+ /* Final data MIME type not known, we cannot determine
+ whether we have to log pages, so do not log. */
+ page_logging = 0;
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "ppdFilterLoadPPD: No final data MIME type known, so we "
+ "cannot determine whether the PDF filter has to log pages "
+ "or not, so turning off page logging for the PDF filter.");
+ }
+ /* Proceed depending on number of cupsFilter(2) lines in PPD */
+ else if (ppd->num_filters == 0)
+ {
+ /* No filter line, manufacturer-supplied PostScript PPD
+ In this case cfFilterPSToPS, called by cfFilterPDFToPS, does the
+ logging */
+ page_logging = 0;
+ }
+ else
+ {
+ /* Filter(s) specified by filter line(s), determine the one which got
+ actually used via final data MIME type */
+ bool cupsfilter2 = (ppdFindAttr(ppd, "cupsFilter2", NULL) != NULL);
+ for (lastfilter = (char *)cupsArrayFirst(ppd->cache->filters);
+ lastfilter;
+ lastfilter = (char *)cupsArrayNext(ppd->cache->filters))
+ {
+ char *p = lastfilter;
+ if (cupsfilter2)
+ {
+ /* Skip first word as the final content type is the second */
+ while (!isspace(*p)) p ++;
+ while (isspace(*p)) p ++;
+ }
+ if (!strncasecmp(data->final_content_type, p,
+ strlen(data->final_content_type))) {
+ break;
+ }
+ }
+ }
+ if (page_logging == -1)
+ {
+ if (lastfilter)
+ {
+ /* Get the name of the last filter, without mime type and cost */
+ char *p = lastfilter;
+ char *q = p + strlen(p) - 1;
+ while (!isspace(*q) && *q != '/') q --;
+ lastfilter = q + 1;
+ /* Check whether the PDF filter has to log */
+ if (!strcasecmp(lastfilter, "-"))
+ {
+ /* No filter defined in the PPD
+ If output data is PDF, cfFilterPDFToPDF() is last
+ filter (PDF printer) and has to log
+ If output data is Apple/PWG Raster or PCLm, cfFilter*ToRaster() is
+ last filter (Driverless IPP printer) and cfFilterPDFToPDF()
+ also has to log */
+ if (strcasestr(data->final_content_type, "/pdf") ||
+ strcasestr(data->final_content_type, "/vnd.cups-pdf") ||
+ strcasestr(data->final_content_type, "/pwg-raster") ||
+ strcasestr(data->final_content_type, "/urf") ||
+ strcasestr(data->final_content_type, "/pclm"))
+ page_logging = 1;
+ else
+ page_logging = 0;
+ }
+ else if (!strcasecmp(lastfilter, "pdftopdf") ||
+ !strcasecmp(lastfilter, "imagetopdf"))
+ {
+ /* cfFilterPDFToPDF() is last filter (PDF printer) */
+ page_logging = 1;
+ }
+ else if (!strcasecmp(lastfilter, "gstopxl"))
+ {
+ /* cfFilterGhostscript() with PCL-XL output is last filter,
+ this is a Ghostscript-based filter without access to the
+ pages of the file to be printed, so the PDF filter has to
+ log the pages */
+ page_logging = 1;
+ }
+ else if (!strcasecmp(lastfilter + strlen(lastfilter) - 8,
+ "toraster") ||
+ !strcasecmp(lastfilter + strlen(lastfilter) - 5,
+ "topwg"))
+ {
+ /* On IPP Everywhere printers which accept PWG Raster data one
+ of cfFilterGhostscript(), cfFilterPDFToRaster(), or
+ cfFilterMuPDFToPWG() is the last filter. These filters do not
+ log pages so the PDF filter has to do it */
+ page_logging = 1;
+ }
+ else if (!strcasecmp(lastfilter, "foomatic-rip"))
+ {
+ /* foomatic-rip is last filter, foomatic-rip is mainly used as
+ Ghostscript wrapper to use Ghostscript's built-in printer
+ drivers. Here there is also no access to the pages so that we
+ delegate the logging to the PDF filter */
+ page_logging = 1;
+ }
+ else if (!strcasecmp(lastfilter, "hpps"))
+ {
+ /* hpps is last filter, hpps is part of HPLIP and it is a bug that
+ it does not do the page logging. */
+ page_logging = 1;
+ }
+ else
+ {
+ /* All the other filters (printer drivers) log pages as expected. */
+ page_logging = 0;
+ }
+ }
+ else
+ {
+ if (log) log(ld, CF_LOGLEVEL_ERROR,
+ "ppdFilterLoadPPD: Last filter could not get determined, "
+ "page logging by the PDF filter turned off.");
+ page_logging = 0;
+ }
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "ppdFilterLoadPPD: Last filter determined by the PPD: %s; "
+ "Final data MIME type: %s => PDF filter will %slog pages in "
+ "page_log.",
+ (lastfilter ? lastfilter : "None"),
+ (data->final_content_type ? data->final_content_type :
+ "(not supplied)"),
+ (page_logging == 0 ? "not " : ""));
+ }
+
+ /* Pass on the result as "pdf-filter-page-logging" option */
+ data->num_options = cupsAddOption("pdf-filter-page-logging",
+ (page_logging == 1 ? "On" : "Off"),
+ data->num_options, &(data->options));
+ }
+
+ return (0);
+}
+
+
+/*
+ * 'ppdFilterFreePPDFile()' - After being done with the filter
+ * functions free the memory used by the
+ * PPD file data in the data structure. If
+ * the pointer to the "libppd" is NULL, do
+ * nothing.
+ */
+
+void
+ppdFilterFreePPDFile(cf_filter_data_t *data) /* I - Job and printer data */
+{
+ ppd_filter_data_ext_t *filter_data_ext =
+ (ppd_filter_data_ext_t *)cfFilterDataRemoveExt(data,
+ PPD_FILTER_DATA_EXT);
+
+ if (filter_data_ext)
+ {
+ if (filter_data_ext->ppd)
+ /* ppdClose() frees not only the main data structure but also the cache */
+ ppdClose(filter_data_ext->ppd);
+
+ if (filter_data_ext->ppdfile)
+ free(filter_data_ext->ppdfile);
+
+ free(filter_data_ext);
+
+ ppdFilterFreePPD(data);
+ }
+}
+
+
+/*
+ * 'ppdFilterFreePPD()' - After being done with the filter functions
+ * free the memory used by the PPD file data in
+ * the data structure. If the pointers to the
+ * data extracted from the PPD are NULL, do
+ * nothing.
+ */
+
+void
+ppdFilterFreePPD(cf_filter_data_t *data) /* I - Job and printer data */
+{
+ if (data->printer_attrs)
+ {
+ ippDelete(data->printer_attrs);
+ data->printer_attrs = NULL;
+ }
+
+ if (data->header)
+ {
+ free(data->header);
+ data->header = NULL;
+ }
+}
+
+
+/*
+ * 'get_env_var()' - Auxiliary function for ppdFilterExternalCUPS(), gets value of
+ * an environment variable in a list of environment variables
+ * as used by the execve() function
+ */
+
+static char * /* O - The value, NULL if variable is not in list */
+get_env_var(char *name, /* I - Name of environment variable to read */
+ char **env) /* I - List of environment variable serttings */
+{
+ int i = 0;
+
+
+ if (env)
+ for (i = 0; env[i]; i ++)
+ if (strncmp(env[i], name, strlen(name)) == 0 &&
+ strlen(env[i]) > strlen(name) &&
+ env[i][strlen(name)] == '=')
+ return (env[i] + strlen(name) + 1);
+
+ return (NULL);
+}
+
+
+/*
+ * 'add_env_var()' - Auxiliary function for ppdFilterExternalCUPS(), adds/sets
+ * an environment variable in a list of environment variables
+ * as used by the execve() function
+ */
+
+static int /* O - Index of where the new value got inserted in
+ the list */
+add_env_var(char *name, /* I - Name of environment variable to set */
+ char *value, /* I - Value of environment variable to set */
+ char ***env) /* I - List of environment variable serttings */
+{
+ char *p;
+ int i = 0,
+ name_len;
+
+
+ if (!name || !env || !name[0])
+ return (-1);
+
+ /* Assemble a "VAR=VALUE" string and the string length of "VAR" */
+ if ((p = strchr(name, '=')) != NULL)
+ {
+ /* User supplied "VAR=VALUE" as name and NULL as value */
+ if (value)
+ return (-1);
+ name_len = p - name;
+ p = strdup(name);
+ }
+ else
+ {
+ /* User supplied variable name and value as the name and as the value */
+ name_len = strlen(name);
+ p = (char *)calloc(strlen(name) + (value ? strlen(value) : 0) + 2,
+ sizeof(char));
+ sprintf(p, "%s=%s", name, (value ? value : ""));
+ }
+
+ /* Check whether we already have this variable in the list and update its
+ value if it is there */
+ if (*env)
+ for (i = 0; (*env)[i]; i ++)
+ if (strncmp((*env)[i], p, name_len) == 0 && (*env)[i][name_len] == '=')
+ {
+ free((*env)[i]);
+ (*env)[i] = p;
+ return (i);
+ }
+
+ /* Add the variable as new item to the list */
+ *env = (char **)realloc(*env, (i + 2) * sizeof(char *));
+ (*env)[i] = p;
+ (*env)[i + 1] = NULL;
+ return (i);
+}
+
+
+/*
+ * 'sanitize_device_uri()' - Remove authentication info from a device URI
+ */
+
+static char * /* O - Sanitized URI */
+sanitize_device_uri(const char *uri, /* I - Device URI */
+ char *buf, /* I - Buffer for output */
+ size_t bufsize) /* I - Size of buffer */
+{
+ char *start, /* Start of data after scheme */
+ *slash, /* First slash after scheme:// */
+ *ptr; /* Pointer into user@host:port part */
+
+
+ /* URI not supplied */
+ if (!uri)
+ return (NULL);
+
+ /* Copy the device URI to a temporary buffer so we can sanitize any auth
+ * info in it... */
+ strncpy(buf, uri, bufsize);
+
+ /* Find the end of the scheme:// part... */
+ if ((ptr = strchr(buf, ':')) != NULL)
+ {
+ for (start = ptr + 1; *start; start ++)
+ if (*start != '/')
+ break;
+
+ /* Find the next slash (/) in the URI... */
+ if ((slash = strchr(start, '/')) == NULL)
+ slash = start + strlen(start); /* No slash, point to the end */
+
+ /* Check for an @ sign before the slash... */
+ if ((ptr = strchr(start, '@')) != NULL && ptr < slash)
+ {
+ /* Found an @ sign and it is before the resource part, so we have
+ an authentication string. Copy the remaining URI over the
+ authentication string... */
+ memmove(start, ptr + 1, strlen(ptr + 1) + 1);
+ }
+ }
+
+ /* Return the sanitized URI... */
+ return (buf);
+}
+
+
+/*
+ * 'fcntl_add_cloexec()' - Add FD_CLOEXEC flag to the flags
+ * of a given file descriptor.
+ */
+
+static int /* Return value of fcntl() */
+fcntl_add_cloexec(int fd) /* File descriptor to add FD_CLOEXEC to */
+{
+ return fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
+}
+
+
+/*
+ * 'fcntl_add_nonblock()' - Add O_NONBLOCK flag to the flags
+ * of a given file descriptor.
+ */
+
+static int /* Return value of fcntl() */
+fcntl_add_nonblock(int fd) /* File descriptor to add O_NONBLOCK to */
+{
+ return fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
+}
+
+
+/*
+ * 'ppdFilterExternalCUPS()' - Filter function which calls an external,
+ * classic CUPS filter, for example a
+ * (proprietary) printer driver which cannot
+ * be converted to a filter function or is to
+ * awkward or risky to convert for example
+ * when the printer hardware is not available
+ * for testing
+ */
+
+int /* O - Error status */
+ppdFilterExternalCUPS(int inputfd, /* I - File descriptor input stream */
+ int outputfd, /* I - File descriptor output stream */
+ int inputseekable, /* I - Is input stream seekable? */
+ cf_filter_data_t *data, /* I - Job and printer data */
+ void *parameters) /* I - Filter-specific parameters */
+{
+ ppd_filter_data_ext_t *filter_data_ext =
+ (ppd_filter_data_ext_t *)cfFilterDataGetExt(data,
+ PPD_FILTER_DATA_EXT);
+ ppd_filter_external_cups_t *params = (ppd_filter_external_cups_t *)parameters;
+ int i;
+ int is_backend = 0; /* Do we call a CUPS backend? */
+ int pid, /* Process ID of filter */
+ stderrpid, /* Process ID for stderr logging process */
+ wpid; /* PID reported as terminated */
+ int fd; /* Temporary file descriptor */
+ int backfd, sidefd; /* file descriptors for back and side
+ channels */
+ int stderrpipe[2]; /* Pipe to log stderr */
+ cups_file_t *fp; /* File pointer to read log lines */
+ char buf[2048]; /* Log line buffer */
+ cf_loglevel_t log_level; /* Log level of filter's log message */
+ char *ptr1, *ptr2,
+ *msg, /* Filter log message */
+ *filter_name; /* Filter name for logging */
+ char filter_path[1024]; /* Full path of the filter */
+ char **argv, /* Command line args for filter */
+ **envp = NULL; /* Environment variables for filter */
+ int num_all_options = 0;
+ cups_option_t *all_options = NULL;
+ char job_id_str[16],
+ copies_str[16],
+ *options_str = NULL;
+ cups_option_t *opt;
+ int status = 65536;
+ int wstatus;
+ cf_logfunc_t log = data->logfunc;
+ void *ld = data->logdata;
+ cf_filter_iscanceledfunc_t iscanceled = data->iscanceledfunc;
+ void *icd = data->iscanceleddata;
+
+
+ if (!params->filter || !params->filter[0]) {
+ if (log) log(ld, CF_LOGLEVEL_ERROR,
+ "ppdFilterExternalCUPS: Filter executable path/command not specified");
+ return (1);
+ }
+
+ /* Check whether back/side channel FDs are valid and not all-zero
+ from calloc'ed filter_data */
+ if (data->back_pipe[0] == 0 && data->back_pipe[1] == 0)
+ data->back_pipe[0] = data->back_pipe[1] = -1;
+ if (data->side_pipe[0] == 0 && data->side_pipe[1] == 0)
+ data->side_pipe[0] = data->side_pipe[1] = -1;
+
+ /* Select the correct end of the back/side channel pipes:
+ [0] for filters, [1] for backends */
+ is_backend = (params->is_backend ? 1 : 0);
+ backfd = data->back_pipe[is_backend];
+ sidefd = data->side_pipe[is_backend];
+
+ /* Filter name for logging */
+ if ((filter_name = strrchr(params->filter, '/')) != NULL)
+ filter_name ++;
+ else
+ filter_name = (char *)params->filter;
+
+ /*
+ * Ignore broken pipe signals...
+ */
+
+ signal(SIGPIPE, SIG_IGN);
+
+ /*
+ * Copy the current environment variables and add some important ones
+ * needed for correct execution of the CUPS filter (which is not running
+ * out of CUPS here)
+ */
+
+ /* Some default environment variables from CUPS, will get overwritten
+ if also defined in the environment in which the caller is started
+ or in the parameters */
+ add_env_var("CUPS_DATADIR", CUPS_DATADIR, &envp);
+ add_env_var("CUPS_SERVERBIN", CUPS_SERVERBIN, &envp);
+ add_env_var("CUPS_SERVERROOT", CUPS_SERVERROOT, &envp);
+ add_env_var("CUPS_STATEDIR", CUPS_STATEDIR, &envp);
+ add_env_var("SOFTWARE", "CUPS/2.5.99", &envp); /* Last CUPS with PPDs */
+ if (data->content_type)
+ add_env_var("CONTENT_TYPE", data->content_type, &envp);
+ if (data->final_content_type)
+ add_env_var("FINAL_CONTENT_TYPE", data->final_content_type, &envp);
+
+ /* Copy the environment in which the caller got started */
+ if (environ)
+ for (i = 0; environ[i]; i ++)
+ add_env_var(environ[i], NULL, &envp);
+
+ /* Set the environment variables given by the parameters */
+ if (params->envp)
+ for (i = 0; params->envp[i]; i ++)
+ add_env_var(params->envp[i], NULL, &envp);
+
+ /* Add CUPS_SERVERBIN to the beginning of PATH */
+ ptr1 = get_env_var("PATH", envp);
+ ptr2 = get_env_var("CUPS_SERVERBIN", envp);
+ if (ptr2 && ptr2[0])
+ {
+ if (ptr1 && ptr1[0])
+ {
+ snprintf(buf, sizeof(buf), "%s/%s:%s",
+ ptr2, params->is_backend ? "backend" : "filter", ptr1);
+ ptr1 = buf;
+ }
+ else
+ ptr1 = ptr2;
+ add_env_var("PATH", ptr1, &envp);
+ }
+
+ if (params->is_backend < 2) /* Not needed in discovery mode of backend */
+ {
+ /* Print queue name from filter data */
+ if (data->printer)
+ add_env_var("PRINTER", data->printer, &envp);
+ else
+ add_env_var("PRINTER", "Unknown", &envp);
+
+ /* PPD file path/name from filter data, required for most CUPS filters */
+ if (filter_data_ext->ppdfile)
+ add_env_var("PPD", filter_data_ext->ppdfile, &envp);
+
+ /* Device URI from parameters */
+ if (params->is_backend && params->device_uri)
+ add_env_var("DEVICE_URI", (char *)params->device_uri, &envp);
+ }
+
+ /* Determine full path for the filter */
+ if (params->filter[0] == '/' ||
+ (ptr1 = get_env_var("CUPS_SERVERBIN", envp)) == NULL || !ptr1[0])
+ strncpy(filter_path, params->filter, sizeof(filter_path) - 1);
+ else
+ snprintf(filter_path, sizeof(filter_path), "%s/%s/%s", ptr1,
+ params->is_backend ? "backend" : "filter", params->filter);
+
+ /* Log the resulting list of environment variable settings
+ (with any authentication info removed)*/
+ if (log)
+ {
+ for (i = 0; envp[i]; i ++)
+ if (!strncmp(envp[i], "AUTH_", 5))
+ log(ld, CF_LOGLEVEL_DEBUG, "ppdFilterExternalCUPS (%s): envp[%d]: AUTH_%c****",
+ filter_name, i, envp[i][5]);
+ else if (!strncmp(envp[i], "DEVICE_URI=", 11))
+ log(ld, CF_LOGLEVEL_DEBUG, "ppdFilterExternalCUPS (%s): envp[%d]: DEVICE_URI=%s",
+ filter_name, i, sanitize_device_uri(envp[i] + 11,
+ buf, sizeof(buf)));
+ else
+ log(ld, CF_LOGLEVEL_DEBUG, "ppdFilterExternalCUPS (%s): envp[%d]: %s",
+ filter_name, i, envp[i]);
+ }
+
+ if (params->is_backend < 2) {
+ /*
+ * Filter or backend for job execution
+ */
+
+ /*
+ * Join the options from the filter data and from the parameters
+ * If an option is present in both filter data and parameters, the
+ * value in the filter data has priority
+ */
+
+ for (i = 0, opt = params->options; i < params->num_options; i ++, opt ++)
+ num_all_options = cupsAddOption(opt->name, opt->value, num_all_options,
+ &all_options);
+ for (i = 0, opt = data->options; i < data->num_options; i ++, opt ++)
+ num_all_options = cupsAddOption(opt->name, opt->value, num_all_options,
+ &all_options);
+
+ /*
+ * Create command line arguments for the CUPS filter
+ */
+
+ argv = (char **)calloc(7, sizeof(char *));
+
+ /* Numeric parameters */
+ snprintf(job_id_str, sizeof(job_id_str) - 1, "%d",
+ data->job_id > 0 ? data->job_id : 1);
+ snprintf(copies_str, sizeof(copies_str) - 1, "%d",
+ data->copies > 0 ? data->copies : 1);
+
+ /* Options, build string of "Name1=Value1 Name2=Value2 ..." but use
+ "Name" and "noName" instead for boolean options */
+ for (i = 0, opt = all_options; i < num_all_options; i ++, opt ++) {
+ if (strcasecmp(opt->value, "true") == 0 ||
+ strcasecmp(opt->value, "false") == 0) {
+ options_str =
+ (char *)realloc(options_str,
+ ((options_str ? strlen(options_str) : 0) +
+ strlen(opt->name) +
+ (strcasecmp(opt->value, "false") == 0 ? 2 : 0) + 2) *
+ sizeof(char));
+ if (i == 0)
+ options_str[0] = '\0';
+ sprintf(options_str + strlen(options_str), " %s%s",
+ (strcasecmp(opt->value, "false") == 0 ? "no" : ""), opt->name);
+ } else {
+ options_str =
+ (char *)realloc(options_str,
+ ((options_str ? strlen(options_str) : 0) +
+ strlen(opt->name) + strlen(opt->value) + 3) *
+ sizeof(char));
+ if (i == 0)
+ options_str[0] = '\0';
+ sprintf(options_str + strlen(options_str), " %s=%s", opt->name, opt->value);
+ }
+ }
+
+ /* Find DEVICE_URI environment variable */
+ if (params->is_backend && !params->device_uri)
+ for (i = 0; envp[i]; i ++)
+ if (strncmp(envp[i], "DEVICE_URI=", 11) == 0)
+ break;
+
+ /* Add items to array */
+ argv[0] = strdup((params->is_backend && params->device_uri ?
+ (char *)sanitize_device_uri(params->device_uri,
+ buf, sizeof(buf)) :
+ (params->is_backend && envp[i] ?
+ (char *)sanitize_device_uri(envp[i] + 11,
+ buf, sizeof(buf)) :
+ (data->printer ? data->printer :
+ (char *)params->filter))));
+ argv[1] = job_id_str;
+ argv[2] = data->job_user ? data->job_user : "Unknown";
+ argv[3] = data->job_title ? data->job_title : "Untitled";
+ argv[4] = copies_str;
+ argv[5] = options_str ? options_str + 1 : "";
+ argv[6] = NULL;
+
+ /* Log the arguments */
+ if (log)
+ for (i = 0; argv[i]; i ++)
+ log(ld, CF_LOGLEVEL_DEBUG, "ppdFilterExternalCUPS (%s): argv[%d]: %s",
+ filter_name, i, argv[i]);
+ } else {
+ /*
+ * Backend in device discovery mode
+ */
+
+ argv = (char **)calloc(2, sizeof(char *));
+ argv[0] = strdup((char *)params->filter);
+ argv[1] = NULL;
+ }
+
+ /*
+ * Execute the filter
+ */
+
+ if (pipe(stderrpipe) < 0) {
+ if (log) log(ld, CF_LOGLEVEL_ERROR,
+ "ppdFilterExternalCUPS (%s): Could not create pipe for stderr: %s",
+ filter_name, strerror(errno));
+ return (1);
+ }
+
+ if ((pid = fork()) == 0) {
+ /*
+ * Child process goes here...
+ *
+ * Update stdin/stdout/stderr as needed...
+ */
+
+ if (inputfd != 0) {
+ if (inputfd < 0) {
+ inputfd = open("/dev/null", O_RDONLY);
+ if (log) log(ld, CF_LOGLEVEL_ERROR,
+ "ppdFilterExternalCUPS (%s): No input file descriptor supplied for CUPS filter - %s",
+ filter_name, strerror(errno));
+ }
+
+ if (inputfd > 0) {
+ fcntl_add_cloexec(inputfd);
+ if (dup2(inputfd, 0) < 0) {
+ if (log) log(ld, CF_LOGLEVEL_ERROR,
+ "ppdFilterExternalCUPS (%s): Failed to connect input file descriptor with CUPS filter's stdin - %s",
+ filter_name, strerror(errno));
+ goto fd_error;
+ } else
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "ppdFilterExternalCUPS (%s): Connected input file descriptor %d to CUPS filter's stdin.",
+ filter_name, inputfd);
+ close(inputfd);
+ }
+ } else
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "ppdFilterExternalCUPS (%s): Input comes from stdin, letting the filter grab stdin directly",
+ filter_name);
+
+ if (outputfd != 1) {
+ if (outputfd < 0)
+ outputfd = open("/dev/null", O_WRONLY);
+
+ if (outputfd > 1) {
+ fcntl_add_cloexec(outputfd);
+ dup2(outputfd, 1);
+ close(outputfd);
+ }
+ }
+
+ if (strcasestr(params->filter, "gziptoany")) {
+ /* Send stderr to the Nirwana if we are running gziptoany, as
+ gziptoany emits a false "PAGE: 1 1" */
+ if ((fd = open("/dev/null", O_RDWR)) > 2) {
+ fcntl_add_cloexec(fd);
+ dup2(fd, 2);
+ close(fd);
+ } else
+ close(fd);
+ } else {
+ /* Send stderr into pipe for logging */
+ fcntl_add_cloexec(stderrpipe[1]);
+ dup2(stderrpipe[1], 2);
+ fcntl_add_nonblock(2);
+ }
+ close(stderrpipe[0]);
+ close(stderrpipe[1]);
+
+ if (params->is_backend < 2) { /* Not needed in discovery mode of backend */
+ /* Back channel */
+ if (backfd != 3 && backfd >= 0) {
+ dup2(backfd, 3);
+ close(backfd);
+ fcntl_add_nonblock(3);
+ } else if (backfd < 0) {
+ if ((backfd = open("/dev/null", O_RDWR)) > 3) {
+ dup2(backfd, 3);
+ close(backfd);
+ } else
+ close(backfd);
+ fcntl_add_nonblock(3);
+ }
+
+ /* Side channel */
+ if (sidefd != 4 && sidefd >= 0) {
+ dup2(sidefd, 4);
+ close(sidefd);
+ fcntl_add_nonblock(4);
+ } else if (sidefd < 0) {
+ if ((sidefd = open("/dev/null", O_RDWR)) > 4) {
+ dup2(sidefd, 4);
+ close(sidefd);
+ } else
+ close(sidefd);
+ fcntl_add_nonblock(4);
+ }
+ }
+
+ /*
+ * Execute command...
+ */
+
+ execve(filter_path, argv, envp);
+
+ if (log) log(ld, CF_LOGLEVEL_ERROR,
+ "ppdFilterExternalCUPS (%s): Execution of %s %s failed - %s",
+ filter_name, params->is_backend ? "backend" : "filter",
+ filter_path, strerror(errno));
+
+ fd_error:
+ exit(errno);
+ } else if (pid > 0) {
+ if (log) log(ld, CF_LOGLEVEL_INFO,
+ "ppdFilterExternalCUPS (%s): %s (PID %d) started.",
+ filter_name, filter_path, pid);
+ } else {
+ if (log) log(ld, CF_LOGLEVEL_ERROR,
+ "ppdFilterExternalCUPS (%s): Unable to fork process for %s %s",
+ filter_name, params->is_backend ? "backend" : "filter",
+ filter_path);
+ close(stderrpipe[0]);
+ close(stderrpipe[1]);
+ status = 1;
+ goto out;
+ }
+ if (inputfd >= 0)
+ close(inputfd);
+ if (outputfd >= 0)
+ close(outputfd);
+
+ /*
+ * Log the filter's stderr
+ */
+
+ if ((stderrpid = fork()) == 0) {
+ /*
+ * Child process goes here...
+ */
+
+ close(stderrpipe[1]);
+ fp = cupsFileOpenFd(stderrpipe[0], "r");
+ while (cupsFileGets(fp, buf, sizeof(buf)))
+ if (log) {
+ if (strncmp(buf, "DEBUG: ", 7) == 0) {
+ log_level = CF_LOGLEVEL_DEBUG;
+ msg = buf + 7;
+ } else if (strncmp(buf, "DEBUG2: ", 8) == 0) {
+ log_level = CF_LOGLEVEL_DEBUG;
+ msg = buf + 8;
+ } else if (strncmp(buf, "INFO: ", 6) == 0) {
+ log_level = CF_LOGLEVEL_INFO;
+ msg = buf + 6;
+ } else if (strncmp(buf, "WARNING: ", 9) == 0) {
+ log_level = CF_LOGLEVEL_WARN;
+ msg = buf + 9;
+ } else if (strncmp(buf, "ERROR: ", 7) == 0) {
+ log_level = CF_LOGLEVEL_ERROR;
+ msg = buf + 7;
+ } else if (strncmp(buf, "PAGE: ", 6) == 0 ||
+ strncmp(buf, "ATTR: ", 6) == 0 ||
+ strncmp(buf, "STATE: ", 7) == 0 ||
+ strncmp(buf, "PPD: ", 5) == 0) {
+ log_level = CF_LOGLEVEL_CONTROL;
+ msg = buf;
+ } else {
+ log_level = CF_LOGLEVEL_DEBUG;
+ msg = buf;
+ }
+ if (log_level == CF_LOGLEVEL_CONTROL)
+ log(ld, log_level, msg);
+ else
+ log(ld, log_level, "ppdFilterExternalCUPS (%s): %s", filter_name, msg);
+ }
+ cupsFileClose(fp);
+ /* No need to close the fd stderrpipe[0], as cupsFileClose(fp) does this
+ already */
+ /* Ignore errors of the logging process */
+ exit(0);
+ } else if (stderrpid > 0) {
+ if (log) log(ld, CF_LOGLEVEL_INFO,
+ "ppdFilterExternalCUPS (%s): Logging (PID %d) started.",
+ filter_name, stderrpid);
+ } else {
+ if (log) log(ld, CF_LOGLEVEL_ERROR,
+ "ppdFilterExternalCUPS (%s): Unable to fork process for logging",
+ filter_name);
+ close(stderrpipe[0]);
+ close(stderrpipe[1]);
+ status = 1;
+ goto out;
+ }
+
+ close(stderrpipe[0]);
+ close(stderrpipe[1]);
+
+ /*
+ * Wait for filter and logging processes to finish
+ */
+
+ status = 0;
+
+ while (pid > 0 || stderrpid > 0) {
+ if ((wpid = wait(&wstatus)) < 0) {
+ if (errno == EINTR && iscanceled && iscanceled(icd)) {
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "ppdFilterExternalCUPS (%s): Job canceled, killing %s ...",
+ filter_name, params->is_backend ? "backend" : "filter");
+ kill(pid, SIGTERM);
+ pid = -1;
+ kill(stderrpid, SIGTERM);
+ stderrpid = -1;
+ break;
+ } else
+ continue;
+ }
+
+ /* How did the filter terminate */
+ if (wstatus) {
+ if (WIFEXITED(wstatus)) {
+ /* Via exit() anywhere or return() in the main() function */
+ if (log) log(ld, CF_LOGLEVEL_ERROR,
+ "ppdFilterExternalCUPS (%s): %s (PID %d) stopped with status %d",
+ filter_name,
+ (wpid == pid ?
+ (params->is_backend ? "Backend" : "Filter") :
+ "Logging"),
+ wpid, WEXITSTATUS(wstatus));
+ } else {
+ /* Via signal */
+ if (log) log(ld, CF_LOGLEVEL_ERROR,
+ "ppdFilterExternalCUPS (%s): %s (PID %d) crashed on signal %d",
+ filter_name,
+ (wpid == pid ?
+ (params->is_backend ? "Backend" : "Filter") :
+ "Logging"),
+ wpid, WTERMSIG(wstatus));
+ }
+ status = 1;
+ } else {
+ if (log) log(ld, CF_LOGLEVEL_INFO,
+ "ppdFilterExternalCUPS (%s): %s (PID %d) exited with no errors.",
+ filter_name,
+ (wpid == pid ?
+ (params->is_backend ? "Backend" : "Filter") : "Logging"),
+ wpid);
+ }
+ if (wpid == pid)
+ pid = -1;
+ else if (wpid == stderrpid)
+ stderrpid = -1;
+ }
+
+ /*
+ * Clean up
+ */
+
+ out:
+ cupsFreeOptions(num_all_options, all_options);
+ if (options_str)
+ free(options_str);
+ free(argv[0]);
+ free(argv);
+ for (i = 0; envp[i]; i ++)
+ free(envp[i]);
+ free(envp);
+
+ return (status);
+}
+
+
+/*
+ * 'ppdFilterEmitJCL()' - Wrapper for the PDF-generating filter
+ * functions to emit JCL (PJL) before and after
+ * the PDF output.
+ */
+
+int /* O - Error status */
+ppdFilterEmitJCL(int inputfd, /* I - File descriptor input stream */
+ int outputfd, /* I - File descriptor output stream */
+ int inputseekable, /* I - Is input stream seekable? */
+ cf_filter_data_t *data, /* I - Job and printer data */
+ void *parameters, /* I - Filter-specific parameters */
+ cf_filter_function_t orig_filter)
+{
+ ppd_filter_data_ext_t *filter_data_ext =
+ (ppd_filter_data_ext_t *)cfFilterDataGetExt(data,
+ PPD_FILTER_DATA_EXT);
+ const char *val;
+ int streaming = 0;
+ int ret = 1;
+ size_t bytes;
+ char buf[8192];
+ int outfds[2], pid = -1;
+ FILE *fp;
+ int hw_copies = 1;
+ bool hw_collate = false;
+ int status, /* Exit status */
+ retval = 1; /* Return value */
+ cf_logfunc_t log = data->logfunc;
+ void *ld = data->logdata;
+
+
+ /*
+ * Check whether we are in streaming mode (cfFilterPDFToPDF() only)
+ *
+ * If we are in streaming mode of cfFilterPDFToPDF() we only apply
+ * JCL and do not run the job through cfFilterPDFToPDF() itself (so
+ * no page management, form flattening, page size/orientation
+ * adjustment, ...)
+ */
+
+ if (orig_filter == cfFilterPDFToPDF &&
+ (val = cupsGetOption("filter-streaming-mode",
+ data->num_options, data->options)) != NULL &&
+ (strcasecmp(val, "false") && strcasecmp(val, "off") &
+ strcasecmp(val, "no")))
+ {
+ streaming = 1;
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "ppdFilterEmitJCL: Streaming mode: No PDF processing, only adding of JCL");
+ }
+
+ /*
+ * Call the original filter function without forking if we suppress
+ * JCL output via option...
+ */
+
+ if ((val = cupsGetOption("emit-jcl",
+ data->num_options, data->options)) != NULL &&
+ (strcasecmp(val, "false") == 0 || strcasecmp(val, "off") == 0 ||
+ strcasecmp(val, "no") == 0))
+ {
+ if (!streaming)
+ /* Call actual filter function from libcupsfilters */
+ ret = orig_filter(inputfd, outputfd, inputseekable, data, parameters);
+ else
+ {
+ /* Just pass through the data unchanged... */
+ fp = fdopen(outputfd, "w");
+ while ((bytes = read(inputfd, buf, sizeof(buf))) > 0)
+ fwrite(buf, 1, bytes, fp);
+ close(inputfd);
+ fclose(fp);
+ ret = 0;
+ }
+ return (ret);
+ }
+
+ if (!streaming)
+ {
+ /*
+ * Create pipe for output of original filter function...
+ */
+
+ if (pipe(outfds) < 0)
+ {
+ if (log) log(ld, CF_LOGLEVEL_ERROR,
+ "ppdFilterEmitJCL: Could not create pipe for ouput: %s",
+ strerror(errno));
+ return (1);
+ }
+
+ /*
+ * Fork child process for original filter function...
+ */
+
+ if ((pid = fork()) == 0)
+ {
+ /* Send output into pipe for adding JCL */
+ fcntl_add_cloexec(outfds[1]);
+ close(outfds[0]);
+
+ /* Call actual filter function from libcupsfilters */
+ ret = orig_filter(inputfd, outfds[1], inputseekable, data, parameters);
+
+ exit(ret);
+ }
+ else if (pid > 0)
+ {
+ if (log) log(ld, CF_LOGLEVEL_INFO,
+ "ppdFilterEmitJCL: Filter function (PID %d) started.",
+ pid);
+ }
+ else
+ {
+ if (log) log(ld, CF_LOGLEVEL_ERROR,
+ "ppdFilterEmitJCL: Unable to fork process for filter function.");
+ close(outfds[0]);
+ close(outfds[1]);
+ retval = 1;
+ goto out;
+ }
+
+ if (inputfd >= 0)
+ close(inputfd);
+ close(outfds[1]);
+ }
+ else
+
+ /*
+ * In Streaming mode we simply copy the input
+ */
+
+ outfds[0] = inputfd;
+
+ /*
+ * Check options for caller's instructions about hardware copies/collate
+ */
+
+ hw_copies =
+ ((val = cupsGetOption("hardware-copies",
+ data->num_options, data->options)) != NULL &&
+ (strcasecmp(val, "true") == 0 || strcasecmp(val, "on") == 0 ||
+ strcasecmp(val, "yes") == 0)) ?
+ data->copies : 1;
+
+ hw_collate =
+ (hw_copies > 1 &&
+ (val = cupsGetOption("hardware-collate",
+ data->num_options, data->options)) != NULL &&
+ (strcasecmp(val, "true") == 0 || strcasecmp(val, "on") == 0 ||
+ strcasecmp(val, "yes") == 0));
+
+ /*
+ * Assemble the output: Exit server, JCL preamble, PDF output, JCL postamble
+ */
+
+ fp = fdopen(outputfd, "w");
+ ppdEmit(filter_data_ext->ppd, fp, PPD_ORDER_EXIT);
+ ppdEmitJCLPDF(filter_data_ext->ppd, fp,
+ data->job_id, data->job_user, data->job_title,
+ hw_copies, hw_collate);
+ while ((bytes = read(outfds[0], buf, sizeof(buf))) > 0)
+ fwrite(buf, 1, bytes, fp);
+ close(outfds[0]);
+ ppdEmitJCLEnd(filter_data_ext->ppd, fp);
+ fclose(fp);
+
+ if (!streaming)
+ {
+ /*
+ * Wait for filter process to finish
+ */
+
+ retry_wait:
+ if (waitpid (pid, &status, 0) == -1)
+ {
+ if (errno == EINTR)
+ goto retry_wait;
+ if (log)
+ log(ld, CF_LOGLEVEL_DEBUG,
+ "ppdFilterEmitJCL: Filter function (PID %d) stopped with an error: %s!",
+ pid, strerror(errno));
+ goto out;
+ }
+
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "ppdFilterEmitJCL: Filter function (PID %d) exited with no errors.",
+ pid);
+
+ /* How did the filter function terminate */
+ if (WIFEXITED(status))
+ /* Via exit() anywhere or return() in the main() function */
+ retval = WEXITSTATUS(status);
+ else if (WIFSIGNALED(status))
+ /* Via signal */
+ retval = 256 * WTERMSIG(status);
+ }
+ else
+ retval = 0;
+
+ out:
+ return (retval);
+}
+
+
+/*
+ * 'ppdFilterImageToPDF()' - Wrapper for the filter function
+ * cfFilterImageToPDF() to add PPD file
+ * support to it.
+ */
+
+int /* O - Error status */
+ppdFilterImageToPDF(int inputfd, /* I - File descriptor input stream */
+ int outputfd, /* I - File descriptor output stream*/
+ int inputseekable, /* I - Is input stream seekable? */
+ cf_filter_data_t *data, /* I - Job and printer data */
+ void *parameters) /* I - Filter-specific parameters */
+{
+ return ppdFilterEmitJCL(inputfd, outputfd, inputseekable, data,
+ parameters, cfFilterImageToPDF);
+}
+
+
+/*
+ * 'ppdFilterPDFtoPDF()' - Wrapper for the filter function
+ * cfFilterPDFtoPDF() to add PPD file
+ * support to it.
+ */
+
+int /* O - Error status */
+ppdFilterPDFToPDF(int inputfd, /* I - File descriptor input stream */
+ int outputfd, /* I - File descriptor output stream */
+ int inputseekable, /* I - Is input stream seekable? */
+ cf_filter_data_t *data, /* I - Job and printer data */
+ void *parameters) /* I - Filter-specific parameters */
+{
+ return ppdFilterEmitJCL(inputfd, outputfd, inputseekable, data,
+ parameters, cfFilterPDFToPDF);
+}
+
+
+/*
+ * 'ppdFilterUniversal()' - Wrapper for the filter function
+ * cfFilterUniversal() to add PPD file
+ * support to it.
+ */
+
+int /* O - Error status */
+ppdFilterUniversal(int inputfd, /* I - File descriptor input stream */
+ int outputfd, /* I - File descriptor output stream*/
+ int inputseekable, /* I - Is input stream seekable? */
+ cf_filter_data_t *data, /* I - Job and printer data */
+ void *parameters) /* I - Filter-specific parameters */
+{
+ ppd_filter_data_ext_t *filter_data_ext =
+ (ppd_filter_data_ext_t *)cfFilterDataGetExt(data,
+ PPD_FILTER_DATA_EXT);
+ char *input;
+ char *final_output;
+ char output[256];
+ cf_filter_universal_parameter_t universal_parameters;
+ ppd_file_t *ppd;
+ ppd_cache_t *cache;
+ cups_array_t *filter_chain;
+ cf_filter_filter_in_chain_t extra_filter, universal_filter;
+ int ret;
+ cf_logfunc_t log = data->logfunc;
+ void *ld = data->logdata;
+
+
+ universal_parameters = *(cf_filter_universal_parameter_t *)parameters;
+ input = data->content_type;
+ if (input == NULL)
+ {
+ if (log) log(ld, CF_LOGLEVEL_ERROR,
+ "ppdFilterUniversal: No input data format supplied.");
+ return (1);
+ }
+
+ final_output = data->final_content_type;
+ if (final_output == NULL)
+ {
+ final_output = universal_parameters.actual_output_type;
+ if (final_output == NULL)
+ {
+ if (log) log(ld, CF_LOGLEVEL_ERROR,
+ "ppdFilterUniversal: No output data format supplied.");
+ return (1);
+ }
+ }
+
+ ppd = filter_data_ext->ppd;
+
+ if (universal_parameters.actual_output_type)
+ strncpy(output, universal_parameters.actual_output_type,
+ sizeof(output) - 1);
+ else if(ppd)
+ {
+ strncpy(output, data->final_content_type, sizeof(output) - 1);
+
+ cache = ppd ? ppd->cache : NULL;
+
+ /* Check whether our output format (under CUPS it is taken from
+ the FINAL_CONTENT_TYPE env variable) is the destination format
+ (2nd word) of a "*cupsFilter2: ..." line (string has 4 words),
+ in this case the specified filter (4th word) does the last
+ step, converting from the input format (1st word) of the line
+ to the destination format and so we only need to convert to the
+ input format. In this case we need to correct our output
+ format.
+
+ If there is more than one line with the given output format and
+ an inpout format we can produce, we select the one with the
+ lowest cost value (3rd word) as this is the one which CUPS
+ should have chosen for this job.
+
+ If we have "*cupsFilter: ..." lines (without "2", string with 3
+ words) we do not need to do anything special, as the input
+ format specified is the FIMAL_CONTENT_TYPE which CUPS supplies
+ to us and into which we have to convert. So we quit parsing if
+ the first line has only 3 words, as if CUPS uses the
+ "*cupsFilter: ..." lines only if there is no "*cupsFilter2:
+ ..." line min the PPD, so if we encounter a line with only 3
+ words the other lines will have only 3 words, too and nothing
+ has to be done. */
+
+ if (ppd && ppd->num_filters && cache)
+ {
+ int lowest_cost = INT_MAX;
+ char *filter;
+
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "ppdFilterUniversal: \"*cupsFilter(2): ...\" lines in the PPD file:");
+
+ for (filter = (char *)cupsArrayFirst(cache->filters);
+ filter;
+ filter = (char *)cupsArrayNext(cache->filters))
+ {
+ char buf[256];
+ char *ptr,
+ *in = NULL,
+ *out = NULL,
+ *coststr = NULL;
+ int cost;
+
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "ppdFilterUniversal: %s", filter);
+
+ /* String of the "*cupsfilter:" or "*cupsfilter2:" line */
+ strncpy(buf, filter, sizeof(buf) - 1);
+
+ /* Separate the words */
+ in = ptr = buf;
+ while (*ptr && !isspace(*ptr)) ptr ++;
+ if (!*ptr) goto error;
+ *ptr = '\0';
+ ptr ++;
+ while (*ptr && isspace(*ptr)) ptr ++;
+ if (!*ptr) goto error;
+ out = ptr;
+ while (*ptr && !isspace(*ptr)) ptr ++;
+ if (!*ptr) goto error;
+ *ptr = '\0';
+ ptr ++;
+ while (*ptr && isspace(*ptr)) ptr ++;
+ if (!*ptr) goto error;
+ coststr = ptr;
+ if (!isdigit(*ptr)) goto error;
+ while (*ptr && !isspace(*ptr)) ptr ++;
+ if (!*ptr) goto error;
+ *ptr = '\0';
+ ptr ++;
+ while (*ptr && isspace(*ptr)) ptr ++;
+ if (!*ptr) goto error;
+ cost = atoi(coststr);
+
+ /* Valid "*cupsFilter2: ..." line ... */
+ if (/* Must be of lower cost than what we selected before */
+ cost < lowest_cost &&
+ /* Must have our FINAL_CONTENT_TYPE as output */
+ strcasecmp(out, final_output) == 0 &&
+ /* Must have as input a format we are able to produce */
+ (strcasecmp(in, "application/vnd.cups-raster") == 0 ||
+ strcasecmp(in, "application/vnd.cups-pdf") == 0 ||
+ strcasecmp(in, "application/vnd.cups-postscript") == 0 ||
+ strcasecmp(in, "application/pdf") == 0 ||
+ strcasecmp(in, "image/pwg-raster") == 0 ||
+ strcasecmp(in, "image/urf") == 0 ||
+ strcasecmp(in, "application/PCLm") == 0 ||
+ strcasecmp(in, "application/postscript") == 0))
+ {
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "ppdFilterUniversal: --> Selecting this line");
+ /* Take the input format of the line as output format for us */
+ strncpy(output, in, sizeof(output));
+ /* Update the minimum cost found */
+ lowest_cost = cost;
+ /* We cannot find a "better" solution ... */
+ if (lowest_cost == 0)
+ {
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "ppdFilterUniversal: Cost value is down to zero, stopping reading further lines");
+ break;
+ }
+ }
+
+ continue;
+
+ error:
+ if (lowest_cost == INT_MAX && coststr)
+ {
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "ppdFilterUniversal: PPD uses \"*cupsFilter: ...\" lines, so we always convert to format given by FINAL_CONTENT_TYPE");
+ break;
+ }
+ if (log) log(ld, CF_LOGLEVEL_ERROR,
+ "ppdFilterUniversal: Invalid \"*cupsFilter2: ...\" line in PPD: %s",
+ filter);
+ }
+
+ }
+ }
+
+ if (strcasecmp(output, final_output) != 0)
+ {
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "ppdFilterUniversal: Converting from %s to %s, final output will be %s",
+ input, output, final_output);
+ universal_parameters.actual_output_type = output;
+ }
+ else
+ {
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "ppdFilterUniversal: Converting from %s to %s", input, output);
+ }
+
+ if (strstr(output, "postscript"))
+ {
+ /* PostScript output, we need to add libppd's ppdFilterPDFToPS() to
+ the end of the chain */
+ universal_parameters.actual_output_type = "application/vnd.cups-pdf";
+ extra_filter.function = ppdFilterPDFToPS;
+ extra_filter.parameters = NULL;
+ extra_filter.name = "pdftops";
+ }
+#if HAVE_CUPS_3_X
+ else if (ppd && ppd->jcl_pdf && strstr(output, "pdf"))
+#else
+ else if (ppd && ppdFindAttr(ppd, "JCLToPDFInterpreter", NULL) &&
+ strstr(output, "pdf"))
+#endif
+ {
+ /* Classic PDF printer, with job control via JCL/PJL, needs
+ libppd's ppdFilterPDFToPDF() filter function which adds PPD's JCL/PJL*/
+ if (!strncmp(input, "image/", 6) &&
+ strcmp(input + 6, "urf") && strcmp(input + 6, "pwg-raster"))
+ /* Input is an image file: call only ppdFilterImageToPDF() as
+ cfFilterImageToPDF() + ppdFilterPDFToPDF() would apply the margins
+ twice */
+ return ppdFilterImageToPDF(inputfd, outputfd, inputseekable, data, NULL);
+ else
+ {
+ /* Any other input format: Replace the cfFilterPDFToPDF() call by
+ cfFilterUniversal() with a call of ppdFilterPDFToPDF(), so that
+ JCL/PJL from the PPD gets added. */
+ universal_parameters.actual_output_type = "application/pdf";
+ extra_filter.function = ppdFilterPDFToPDF;
+ extra_filter.parameters = NULL;
+ extra_filter.name = "pdftopdf+JCL";
+ }
+ }
+ else
+ /* No extra filter needed, cfFilterUniversal() does the job
+ correctly with only the filter functions of libcupsfilters */
+ extra_filter.function = NULL;
+
+ if (extra_filter.function)
+ {
+ /* Chain cfFilterUniversal() with the extra filter function */
+ universal_filter.function = cfFilterUniversal;
+ universal_filter.parameters = &universal_parameters;
+ universal_filter.name = "universal";
+ filter_chain = cupsArrayNew(NULL, NULL);
+ cupsArrayAdd(filter_chain, &universal_filter);
+ cupsArrayAdd(filter_chain, &extra_filter);
+ ret = cfFilterChain(inputfd, outputfd, inputseekable, data,
+ filter_chain);
+ cupsArrayDelete(filter_chain);
+ }
+ else
+ ret = cfFilterUniversal(inputfd, outputfd, inputseekable, data,
+ &universal_parameters);
+
+ return (ret);
+}
+
+
+/*
+ * 'ppdFilterSetCommonOptions()' - Set common filter options for media size,
+ * etc. based on PPD file
+ */
+
+void
+ppdFilterSetCommonOptions(
+ ppd_file_t *ppd, /* I - PPD file */
+ int num_options, /* I - Number of options */
+ cups_option_t *options, /* I - Options */
+ int change_size, /* I - Change page size? */
+ int *Orientation, /* I/O - Basic page parameters */
+ int *Duplex,
+ int *LanguageLevel,
+ int *ColorDevice,
+ float *PageLeft,
+ float *PageRight,
+ float *PageTop,
+ float *PageBottom,
+ float *PageWidth,
+ float *PageLength,
+ cf_logfunc_t log, /* I - Logging function,
+ NULL for no logging */
+ void *ld) /* I - User data for logging function,
+ can be NULL */
+{
+ ppd_size_t *pagesize; /* Current page size */
+ const char *val; /* Option value */
+
+
+ *Orientation = 0; /* 0 = portrait, 1 = landscape, etc. */
+ *Duplex = 0; /* Duplexed? */
+ *LanguageLevel = 1; /* Language level of printer */
+ *ColorDevice = 1; /* Color printer? */
+ *PageLeft = 18.0f; /* Left margin */
+ *PageRight = 594.0f; /* Right margin */
+ *PageBottom = 36.0f; /* Bottom margin */
+ *PageTop = 756.0f; /* Top margin */
+ *PageWidth = 612.0f; /* Total page width */
+ *PageLength = 792.0f; /* Total page length */
+
+ if ((pagesize = ppdPageSize(ppd, NULL)) != NULL)
+ {
+ int corrected = 0;
+ if (pagesize->width > 0)
+ *PageWidth = pagesize->width;
+ else
+ {
+ if (log) log(ld, CF_LOGLEVEL_ERROR,
+ "Invalid value for page width: %.0f",
+ pagesize->width);
+ corrected = 1;
+ }
+ if (pagesize->length > 0)
+ *PageLength = pagesize->length;
+ else
+ {
+ if (log) log(ld, CF_LOGLEVEL_ERROR,
+ "Invalid value for page length: %.0f",
+ pagesize->length);
+ corrected = 1;
+ }
+ if (pagesize->top >= 0 && pagesize->top <= *PageLength)
+ *PageTop = pagesize->top;
+ else
+ {
+ if (log) log(ld, CF_LOGLEVEL_ERROR,
+ "Invalid value for page top margin: %.0f",
+ pagesize->top);
+ if (*PageLength >= *PageBottom)
+ *PageTop = *PageLength - *PageBottom;
+ else
+ *PageTop = *PageLength;
+ corrected = 1;
+ }
+ if (pagesize->bottom >= 0 && pagesize->bottom <= *PageLength)
+ *PageBottom = pagesize->bottom;
+ else
+ {
+ if (log) log(ld, CF_LOGLEVEL_ERROR,
+ "Invalid value for page bottom margin: %.0f",
+ pagesize->bottom);
+ if (*PageLength <= *PageBottom)
+ *PageBottom = 0.0f;
+ corrected = 1;
+ }
+ if (*PageBottom == *PageTop)
+ {
+ if (log) log(ld, CF_LOGLEVEL_ERROR,
+ "Invalid values for page margins: Bottom: %.0f; Top: %.0f",
+ *PageBottom, *PageTop);
+ *PageTop = *PageLength - *PageBottom;
+ if (*PageBottom == *PageTop)
+ {
+ *PageBottom = 0.0f;
+ *PageTop = *PageLength;
+ }
+ corrected = 1;
+ }
+ if (*PageBottom > *PageTop)
+ {
+ if (log) log(ld, CF_LOGLEVEL_ERROR,
+ "Invalid values for page margins: Bottom: %.0f; Top: %.0f",
+ *PageBottom, *PageTop);
+ float swap = *PageBottom;
+ *PageBottom = *PageTop;
+ *PageTop = swap;
+ corrected = 1;
+ }
+
+ if (pagesize->left >= 0 && pagesize->left <= *PageWidth)
+ *PageLeft = pagesize->left;
+ else
+ {
+ if (log) log(ld, CF_LOGLEVEL_ERROR,
+ "Invalid value for page left margin: %.0f",
+ pagesize->left);
+ if (*PageWidth <= *PageLeft)
+ *PageLeft = 0.0f;
+ corrected = 1;
+ }
+ if (pagesize->right >= 0 && pagesize->right <= *PageWidth)
+ *PageRight = pagesize->right;
+ else
+ {
+ if (log) log(ld, CF_LOGLEVEL_ERROR,
+ "Invalid value for page right margin: %.0f",
+ pagesize->right);
+ if (*PageWidth >= *PageLeft)
+ *PageRight = *PageWidth - *PageLeft;
+ else
+ *PageRight = *PageWidth;
+ corrected = 1;
+ }
+ if (*PageLeft == *PageRight)
+ {
+ if (log) log(ld, CF_LOGLEVEL_ERROR,
+ "Invalid values for page margins: Left: %.0f; Right: %.0f",
+ *PageLeft, *PageRight);
+ *PageRight = *PageWidth - *PageLeft;
+ if (*PageLeft == *PageRight)
+ {
+ *PageLeft = 0.0f;
+ *PageRight = *PageWidth;
+ }
+ corrected = 1;
+ }
+ if (*PageLeft > *PageRight)
+ {
+ if (log) log(ld, CF_LOGLEVEL_ERROR,
+ "Invalid values for page margins: Left: %.0f; Right: %.0f",
+ *PageLeft, *PageRight);
+ float swap = *PageLeft;
+ *PageLeft = *PageRight;
+ *PageRight = swap;
+ corrected = 1;
+ }
+
+ if (corrected)
+ {
+ if (log) log(ld, CF_LOGLEVEL_ERROR,
+ "PPD Page = %.0fx%.0f; %.0f,%.0f to %.0f,%.0f",
+ pagesize->width, pagesize->length, pagesize->left,
+ pagesize->bottom, pagesize->right, pagesize->top);
+ if (log) log(ld, CF_LOGLEVEL_ERROR,
+ "Corrected Page = %.0fx%.0f; %.0f,%.0f to %.0f,%.0f",
+ *PageWidth, *PageLength, *PageLeft,
+ *PageBottom, *PageRight, *PageTop);
+ }
+ else
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "Page = %.0fx%.0f; %.0f,%.0f to %.0f,%.0f",
+ pagesize->width, pagesize->length, pagesize->left,
+ pagesize->bottom, pagesize->right, pagesize->top);
+ }
+
+ if (ppd != NULL)
+ {
+ *ColorDevice = ppd->color_device;
+ *LanguageLevel = ppd->language_level;
+ }
+
+ if ((val = cupsGetOption("landscape", num_options, options)) != NULL)
+ {
+ if (strcasecmp(val, "no") != 0 && strcasecmp(val, "off") != 0 &&
+ strcasecmp(val, "false") != 0)
+ {
+ if (ppd && ppd->landscape > 0)
+ *Orientation = 1;
+ else
+ *Orientation = 3;
+ }
+ }
+ else if ((val = cupsGetOption("orientation-requested",
+ num_options, options)) != NULL)
+ {
+ /*
+ * Map IPP orientation values to 0 to 3:
+ *
+ * 3 = 0 degrees = 0
+ * 4 = 90 degrees = 1
+ * 5 = -90 degrees = 3
+ * 6 = 180 degrees = 2
+ */
+
+ *Orientation = atoi(val) - 3;
+ if (*Orientation >= 2)
+ *Orientation ^= 1;
+ }
+
+ if ((val = cupsGetOption("page-left", num_options, options)) != NULL)
+ {
+ switch (*Orientation & 3)
+ {
+ case 0 :
+ *PageLeft = (float)atof(val);
+ break;
+ case 1 :
+ *PageBottom = (float)atof(val);
+ break;
+ case 2 :
+ *PageRight = *PageWidth - (float)atof(val);
+ break;
+ case 3 :
+ *PageTop = *PageLength - (float)atof(val);
+ break;
+ }
+ }
+
+ if ((val = cupsGetOption("page-right", num_options, options)) != NULL)
+ {
+ switch (*Orientation & 3)
+ {
+ case 0 :
+ *PageRight = *PageWidth - (float)atof(val);
+ break;
+ case 1 :
+ *PageTop = *PageLength - (float)atof(val);
+ break;
+ case 2 :
+ *PageLeft = (float)atof(val);
+ break;
+ case 3 :
+ *PageBottom = (float)atof(val);
+ break;
+ }
+ }
+
+ if ((val = cupsGetOption("page-bottom", num_options, options)) != NULL)
+ {
+ switch (*Orientation & 3)
+ {
+ case 0 :
+ *PageBottom = (float)atof(val);
+ break;
+ case 1 :
+ *PageLeft = (float)atof(val);
+ break;
+ case 2 :
+ *PageTop = *PageLength - (float)atof(val);
+ break;
+ case 3 :
+ *PageRight = *PageWidth - (float)atof(val);
+ break;
+ }
+ }
+
+ if ((val = cupsGetOption("page-top", num_options, options)) != NULL)
+ {
+ switch (*Orientation & 3)
+ {
+ case 0 :
+ *PageTop = *PageLength - (float)atof(val);
+ break;
+ case 1 :
+ *PageRight = *PageWidth - (float)atof(val);
+ break;
+ case 2 :
+ *PageBottom = (float)atof(val);
+ break;
+ case 3 :
+ *PageLeft = (float)atof(val);
+ break;
+ }
+ }
+
+ if (change_size)
+ ppdFilterUpdatePageVars(*Orientation, PageLeft, PageRight,
+ PageTop, PageBottom, PageWidth, PageLength);
+
+ if (ppdIsMarked(ppd, "Duplex", "DuplexNoTumble") ||
+ ppdIsMarked(ppd, "Duplex", "DuplexTumble") ||
+ ppdIsMarked(ppd, "JCLDuplex", "DuplexNoTumble") ||
+ ppdIsMarked(ppd, "JCLDuplex", "DuplexTumble") ||
+ ppdIsMarked(ppd, "EFDuplex", "DuplexNoTumble") ||
+ ppdIsMarked(ppd, "EFDuplex", "DuplexTumble") ||
+ ppdIsMarked(ppd, "EFDuplexing", "DuplexNoTumble") ||
+ ppdIsMarked(ppd, "EFDuplexing", "DuplexTumble") ||
+ ppdIsMarked(ppd, "ARDuplex", "DuplexNoTumble") ||
+ ppdIsMarked(ppd, "ARDuplex", "DuplexTumble") ||
+ ppdIsMarked(ppd, "KD03Duplex", "DuplexNoTumble") ||
+ ppdIsMarked(ppd, "KD03Duplex", "DuplexTumble"))
+ *Duplex = 1;
+
+ return;
+}
+
+
+/*
+ * 'ppdFilterUpdatePageVars()' - Update the page variables for the orientation.
+ */
+
+void
+ppdFilterUpdatePageVars(int Orientation,
+ float *PageLeft, float *PageRight,
+ float *PageTop, float *PageBottom,
+ float *PageWidth, float *PageLength)
+{
+ float temp; /* Swapping variable */
+
+
+ switch (Orientation & 3)
+ {
+ case 0 : /* Portait */
+ break;
+
+ case 1 : /* Landscape */
+ temp = *PageLeft;
+ *PageLeft = *PageBottom;
+ *PageBottom = temp;
+
+ temp = *PageRight;
+ *PageRight = *PageTop;
+ *PageTop = temp;
+
+ temp = *PageWidth;
+ *PageWidth = *PageLength;
+ *PageLength = temp;
+ break;
+
+ case 2 : /* Reverse Portrait */
+ temp = *PageWidth - *PageLeft;
+ *PageLeft = *PageWidth - *PageRight;
+ *PageRight = temp;
+
+ temp = *PageLength - *PageBottom;
+ *PageBottom = *PageLength - *PageTop;
+ *PageTop = temp;
+ break;
+
+ case 3 : /* Reverse Landscape */
+ temp = *PageWidth - *PageLeft;
+ *PageLeft = *PageWidth - *PageRight;
+ *PageRight = temp;
+
+ temp = *PageLength - *PageBottom;
+ *PageBottom = *PageLength - *PageTop;
+ *PageTop = temp;
+
+ temp = *PageLeft;
+ *PageLeft = *PageBottom;
+ *PageBottom = temp;
+
+ temp = *PageRight;
+ *PageRight = *PageTop;
+ *PageTop = temp;
+
+ temp = *PageWidth;
+ *PageWidth = *PageLength;
+ *PageLength = temp;
+ break;
+ }
+}
--- /dev/null
+/*
+ * Filter functions header file for libppd.
+ *
+ * Copyright © 2020-2022 by Till Kamppeter.
+ *
+ * Licensed under Apache License v2.0. See the file "LICENSE" for more
+ * information.
+ */
+
+#ifndef _PPD_PPD_FILTER_H_
+# define _PPD_PPD_FILTER_H_
+
+# ifdef __cplusplus
+extern "C" {
+# endif /* __cplusplus */
+
+
+/*
+ * Include necessary headers...
+ */
+
+# include <cupsfilters/log.h>
+# include <cupsfilters/filter.h>
+
+# include <stdio.h>
+# include <stdlib.h>
+# include <time.h>
+# include <math.h>
+
+# if defined(WIN32) || defined(__EMX__)
+# include <io.h>
+# else
+# include <unistd.h>
+# include <fcntl.h>
+# endif /* WIN32 || __EMX__ */
+
+# include <cups/cups.h>
+# include <cups/raster.h>
+# include <ppd/ppd.h>
+
+# define PPD_FILTER_DATA_EXT "libppd"
+
+
+/*
+ * Types and structures...
+ */
+
+typedef struct ppd_filter_data_ext_s {
+ char *ppdfile; /* PPD file name */
+ ppd_file_t *ppd; /* PPD file data */
+} ppd_filter_data_ext_t;
+
+typedef struct ppd_filter_external_cups_s { /* Parameters for the
+ ppdFilterExternalCUPS() filter
+ function */
+ const char *filter; /* Path/Name of the CUPS filter to be called by
+ this filter function, required */
+ int is_backend; /* 0 if we call a filter, 1 if we call a CUPS
+ backend, 2 if we call a CUPS backend in
+ device discovery mode */
+ const char *device_uri; /* Device URI when calling a CUPS Backend for
+ processing a job, optional, alternatively
+ DEVICE_URI environment variable can get set
+ in envp */
+ int num_options; /* Extra options for the 5th command line */
+ cups_option_t *options; /* argument, options of filter_data have
+ priority, 0/NULL if none */
+ char **envp; /* Additional environment variables, the already
+ defined ones stay valid but can be overwritten
+ by these ones, NULL if none */
+} ppd_filter_external_cups_t;
+
+
+/*
+ * Prototypes...
+ */
+
+extern int ppdFilterCUPSWrapper(int argc,
+ char *argv[],
+ cf_filter_function_t filter,
+ void *parameters,
+ int *JobCanceled);
+
+
+extern int ppdFilterLoadPPDFile(cf_filter_data_t *data, const char *ppdfile);
+
+
+extern int ppdFilterLoadPPD(cf_filter_data_t *data);
+
+
+extern void ppdFilterFreePPDFile(cf_filter_data_t *data);
+
+
+extern void ppdFilterFreePPD(cf_filter_data_t *data);
+
+
+extern int ppdFilterExternalCUPS(int inputfd,
+ int outputfd,
+ int inputseekable,
+ cf_filter_data_t *data,
+ void *parameters);
+
+/* Parameters: ppd_filter_external_cups_t*
+ Path/Name of the CUPS filter to be called by this filter function,
+ specification whether we call a filter or a backend, an in case of
+ backend, whether in job processing or discovery mode, extra options
+ for the 5th command line argument, and extra environment
+ variables */
+
+
+extern int ppdFilterEmitJCL(int inputfd,
+ int outputfd,
+ int inputseekable,
+ cf_filter_data_t *data,
+ void *parameters,
+ cf_filter_function_t orig_filter);
+
+
+extern int ppdFilterImageToPDF(int inputfd,
+ int outputfd,
+ int inputseekable,
+ cf_filter_data_t *data,
+ void *parameters);
+
+
+extern int ppdFilterImageToPS(int inputfd,
+ int outputfd,
+ int inputseekable,
+ cf_filter_data_t *data,
+ void *parameters);
+
+
+extern int ppdFilterPDFToPDF(int inputfd,
+ int outputfd,
+ int inputseekable,
+ cf_filter_data_t *data,
+ void *parameters);
+
+/* (Optional) Specification of output format via
+ data->final_content_type is used for determining whether this
+ filter function does page logging for CUPS (output of "PAGE: XX YY"
+ log messages) or not and also to determine whether the printer or
+ driver generates copies or whether we have to send the pages
+ repeatedly.
+
+ Alternatively, the options "pdf-filter-page-logging",
+ "hardware-copies", and "hardware-collate" can be used to manually
+ do these selections. */
+
+
+
+extern int ppdFilterPDFToPS(int inputfd,
+ int outputfd,
+ int inputseekable,
+ cf_filter_data_t *data,
+ void *parameters);
+
+
+extern int ppdFilterPSToPS(int inputfd,
+ int outputfd,
+ int inputseekable,
+ cf_filter_data_t *data,
+ void *parameters);
+
+
+extern int ppdFilterRasterToPS(int inputfd,
+ int outputfd,
+ int inputseekable,
+ cf_filter_data_t *data,
+ void *parameters);
+
+
+extern int ppdFilterUniversal(int inputfd,
+ int outputfd,
+ int inputseekable,
+ cf_filter_data_t *data,
+ void *parameters);
+
+/* Requires specification of input format via data->content_type and
+ job's final output format via data->final_content_type
+
+ Parameters: cf_filter_universal_parameter_t
+
+ Contains: actual_output_type: Format which the filter should
+ actually produce if different from job's final output
+ format, or NULL to auto-determine the needed output
+ format from the PPDs "cupsFilter2: ..." lines. Default
+ is the job's final output format.
+ texttopdf_params: parameters for texttopdf */
+
+
+extern void ppdFilterSetCommonOptions(ppd_file_t *ppd,
+ int num_options,
+ cups_option_t *options,
+ int change_size,
+ int *Orientation,
+ int *Duplex,
+ int *LanguageLevel,
+ int *ColorDevice,
+ float *PageLeft,
+ float *PageRight,
+ float *PageTop,
+ float *PageBottom,
+ float *PageWidth,
+ float *PageLength,
+ cf_logfunc_t log,
+ void *ld);
+
+
+extern void ppdFilterUpdatePageVars(int Orientation,
+ float *PageLeft, float *PageRight,
+ float *PageTop, float *PageBottom,
+ float *PageWidth, float *PageLength);
+
+
+# ifdef __cplusplus
+}
+# endif /* __cplusplus */
+
+#endif /* !_PPD_PPD_FILTER_H_ */
#include <cups/cups.h>
#include <cups/dir.h>
#include <ppd/ppd.h>
-#include <cupsfilters/ppdgenerator.h>
-#if (CUPS_VERSION_MAJOR > 1) || (CUPS_VERSION_MINOR > 5)
-#define HAVE_CUPS_1_6 1
-#endif
-#if (CUPS_VERSION_MAJOR > 1) || (CUPS_VERSION_MINOR > 6)
-#define HAVE_CUPS_1_7 1
-#endif
+#include <ppd/string-private.h>
+#include <cupsfilters/ipp.h>
+#include <cupsfilters/catalog.h>
/*
#include <errno.h>
#include <string.h>
#include <ctype.h>
-#ifdef HAVE_CUPS_1_7
#include <cups/pwg.h>
-#endif /* HAVE_CUPS_1_7 */
/*
#endif
-#ifdef HAVE_CUPS_1_6
-/*
- * Local types...
- */
-
-/* Data structure for IPP choice name and human-readable string */
-typedef struct ipp_choice_strings_s {
- char *name, *human_readable;
-} ipp_choice_strings_t;
-
-/* Data structure for IPP option name, human-readable string, and choice list */
-typedef struct ipp_opt_strings_s {
- char *name, *human_readable;
- cups_array_t *choices;
-} ipp_opt_strings_t;
-
-/* The following code uses a lot of CUPS >= 1.6 specific stuff.
- It needed for create_local_queue() in cups-browsed
- to set up local queues for non-CUPS printer broadcasts
- that is disabled in create_local_queue() for older CUPS <= 1.5.4.
- Accordingly the following code is also disabled here for CUPS < 1.6. */
-
/*
* The code below is borrowed from the CUPS 2.2.x upstream repository
* (via patches attached to https://www.cups.org/str.php?L4258). This
*/
-cups_array_t *opt_strings_catalog = NULL;
char ppdgenerator_msg[1024];
-typedef struct _pwg_finishings_s /**** PWG finishings mapping data ****/
-{
- ipp_finishings_t value; /* finishings value */
- int num_options; /* Number of options to apply */
- cups_option_t *options; /* Options to apply */
-} _pwg_finishings_t;
-
-#define _PWG_EQUIVALENT(x, y) (abs((x)-(y)) < 2)
-
-#ifndef HAVE_STRLCPY
-/*
- * 'strlcpy()' - Safely copy two strings.
- */
-
-size_t /* O - Length of string */
-strlcpy(char *dst, /* O - Destination string */
- const char *src, /* I - Source string */
- size_t size) /* I - Size of destination string buffer */
-{
- size_t srclen; /* Length of source string */
-
-
- /*
- * Figure out how much room is needed...
- */
-
- size --;
-
- srclen = strlen(src);
-
- /*
- * Copy the appropriate amount...
- */
-
- if (srclen > size)
- srclen = size;
-
- memmove(dst, src, srclen);
- dst[srclen] = '\0';
-
- return (srclen);
-}
-#endif /* !HAVE_STRLCPY */
-
-/*
- * 'cfStrFormatd()' - Format a floating-point number.
- */
-
-char * /* O - Pointer to end of string */
-cfStrFormatd(char *buf, /* I - String */
- char *bufend, /* I - End of string buffer */
- double number, /* I - Number to format */
- struct lconv *loc) /* I - Locale data */
-{
- char *bufptr, /* Pointer into buffer */
- temp[1024], /* Temporary string */
- *tempdec, /* Pointer to decimal point */
- *tempptr; /* Pointer into temporary string */
- const char *dec; /* Decimal point */
- int declen; /* Length of decimal point */
-
-
- /*
- * Format the number using the "%.12f" format and then eliminate
- * unnecessary trailing 0's.
- */
-
- snprintf(temp, sizeof(temp), "%.12f", number);
- for (tempptr = temp + strlen(temp) - 1;
- tempptr > temp && *tempptr == '0';
- *tempptr-- = '\0');
-
- /*
- * Next, find the decimal point...
- */
-
- if (loc && loc->decimal_point) {
- dec = loc->decimal_point;
- declen = (int)strlen(dec);
- } else {
- dec = ".";
- declen = 1;
- }
-
- if (declen == 1)
- tempdec = strchr(temp, *dec);
- else
- tempdec = strstr(temp, dec);
-
- /*
- * Copy everything up to the decimal point...
- */
-
- if (tempdec) {
- for (tempptr = temp, bufptr = buf;
- tempptr < tempdec && bufptr < bufend;
- *bufptr++ = *tempptr++);
-
- tempptr += declen;
-
- if (*tempptr && bufptr < bufend) {
- *bufptr++ = '.';
-
- while (*tempptr && bufptr < bufend)
- *bufptr++ = *tempptr++;
- }
-
- *bufptr = '\0';
- } else {
- strlcpy(buf, temp, (size_t)(bufend - buf + 1));
- bufptr = buf + strlen(buf);
- }
-
- return (bufptr);
-}
-
-
-/*
- * 'pwg_compare_sizes()' - Compare two media sizes...
- */
-
-static int /* O - Result of comparison */
-pwg_compare_sizes(cups_size_t *a, /* I - First media size */
- cups_size_t *b) /* I - Second media size */
-{
- return (strcmp(a->media, b->media));
-}
-
-
-/*
- * 'pwg_copy_size()' - Copy a media size.
- */
-
-static cups_size_t * /* O - New media size */
-pwg_copy_size(cups_size_t *size) /* I - Media size to copy */
-{
- cups_size_t *newsize = (cups_size_t *)calloc(1, sizeof(cups_size_t));
- /* New media size */
-
- if (newsize)
- memcpy(newsize, size, sizeof(cups_size_t));
-
- return (newsize);
-}
-
-static int /* O - 1 on success, 0 on failure */
-get_url(const char *url, /* I - URL to get */
- char *name, /* I - Temporary filename */
- size_t namesize) /* I - Size of temporary filename
- buffer */
-{
- http_t *http = NULL;
- char scheme[32], /* URL scheme */
- userpass[256], /* URL username:password */
- host[256], /* URL host */
- resource[256]; /* URL resource */
- int port; /* URL port */
- http_encryption_t encryption; /* Type of encryption to use */
- http_status_t status; /* Status of GET request */
- int fd; /* Temporary file */
-
-
- if (httpSeparateURI(HTTP_URI_CODING_ALL, url, scheme, sizeof(scheme),
- userpass, sizeof(userpass), host, sizeof(host), &port,
- resource, sizeof(resource)) < HTTP_URI_STATUS_OK)
- return (0);
-
- if (port == 443 || !strcmp(scheme, "https"))
- encryption = HTTP_ENCRYPTION_ALWAYS;
- else
- encryption = HTTP_ENCRYPTION_IF_REQUESTED;
-
- http = httpConnect2(host, port, NULL, AF_UNSPEC, encryption, 1, 5000, NULL);
-
- if (!http)
- return (0);
-
- if ((fd = cupsTempFd(name, (int)namesize)) < 0)
- return (0);
-
- status = cupsGetFd(http, resource, fd);
-
- close(fd);
- httpClose(http);
-
- if (status != HTTP_STATUS_OK) {
- unlink(name);
- *name = '\0';
- return (0);
- }
-
- return (1);
-}
-
-
-
-/*
- * 'find_cups_message_catalog()' - Find a CUPS message catalog file
- * containing human-readable standard
- * option and choice names for IPP
- * printers
- */
-
-static const char *
-search_dir_for_catalog(const char *dirname)
-{
- const char *catalog = NULL, *c1, *c2;
- cups_dir_t *dir = NULL, *subdir;
- cups_dentry_t *subdirentry, *catalogentry;
- char subdirpath[1024], catalogpath[2048], lang[8];
- int i;
-
- if (dirname == NULL)
- return NULL;
-
- /* Check first whether we have an English file and prefer this */
- snprintf(catalogpath, sizeof(catalogpath), "%s/en/cups_en.po", dirname);
- if (access(catalogpath, R_OK) == 0) {
- /* Found */
- catalog = strdup(catalogpath);
- return catalog;
- }
-
- if ((dir = cupsDirOpen(dirname)) == NULL)
- return NULL;
-
- while ((subdirentry = cupsDirRead(dir)) != NULL) {
- /* Do we actually have a subdir? */
- if (!S_ISDIR(subdirentry->fileinfo.st_mode))
- continue;
- /* Check format of subdir name */
- c1 = subdirentry->filename;
- if (c1[0] < 'a' || c1[0] > 'z' || c1[1] < 'a' || c1[1] > 'z')
- continue;
- if (c1[2] >= 'a' && c1[2] <= 'z')
- i = 3;
- else
- i = 2;
- if (c1[i] == '_') {
- i ++;
- if (c1[i] < 'A' || c1[i] > 'Z' || c1[i+1] < 'A' || c1[i+1] > 'Z')
- continue;
- i += 2;
- if (c1[i] >= 'A' && c1[i] <= 'Z')
- i ++;
- }
- if (c1[i] != '\0' && c1[i] != '@')
- continue;
- strncpy(lang, c1, i);
- lang[i] = '\0';
- snprintf(subdirpath, sizeof(subdirpath), "%s/%s", dirname, c1);
- if ((subdir = cupsDirOpen(subdirpath)) != NULL) {
- while ((catalogentry = cupsDirRead(subdir)) != NULL) {
- /* Do we actually have a regular file? */
- if (!S_ISREG(catalogentry->fileinfo.st_mode))
- continue;
- /* Check format of catalog name */
- c2 = catalogentry->filename;
- if (strlen(c2) < 10 || strncmp(c2, "cups_", 5) != 0 ||
- strncmp(c2 + 5, lang, i) != 0 ||
- strcmp(c2 + strlen(c2) - 3, ".po"))
- continue;
- /* Is catalog readable ? */
- snprintf(catalogpath, sizeof(catalogpath), "%s/%s", subdirpath, c2);
- if (access(catalogpath, R_OK) != 0)
- continue;
- /* Found */
- catalog = strdup(catalogpath);
- break;
- }
- cupsDirClose(subdir);
- subdir = NULL;
- if (catalog != NULL)
- break;
- }
- }
-
- cupsDirClose(dir);
- return catalog;
-}
-
-static const char *
-find_cups_message_catalog(const char *preferreddir)
-{
- const char *catalog = NULL, *c;
- char buf[1024];
-
- /* Directory supplied by calling program, from config file,
- environment variable, ... */
- if ((catalog = search_dir_for_catalog(preferreddir)) != NULL)
- goto found;
-
- /* Directory supplied by environment variable CUPS_LOCALEDIR */
- if ((catalog = search_dir_for_catalog(getenv("CUPS_LOCALEDIR"))) != NULL)
- goto found;
-
- /* Determine CUPS datadir (usually /usr/share/cups) */
- if ((c = getenv("CUPS_DATADIR")) == NULL)
- c = CUPS_DATADIR;
-
- /* Search /usr/share/cups/locale/ (location which
- Debian/Ubuntu package of CUPS is using) */
- snprintf(buf, sizeof(buf), "%s/locale", c);
- if ((catalog = search_dir_for_catalog(buf)) != NULL)
- goto found;
-
- /* Search /usr/(local/)share/locale/ (standard location
- which CUPS is using on Linux) */
- snprintf(buf, sizeof(buf), "%s/../locale", c);
- if ((catalog = search_dir_for_catalog(buf)) != NULL)
- goto found;
-
- /* Search /usr/(local/)lib/locale/ (standard location
- which CUPS is using on many non-Linux systems) */
- snprintf(buf, sizeof(buf), "%s/../../lib/locale", c);
- if ((catalog = search_dir_for_catalog(buf)) != NULL)
- goto found;
-
- found:
- return catalog;
-}
-
-static int
-compare_choices(void *a,
- void *b,
- void *user_data)
-{
- return strcasecmp(((ipp_choice_strings_t *)a)->name,
- ((ipp_choice_strings_t *)b)->name);
-}
-
-static int
-compare_options(void *a,
- void *b,
- void *user_data)
-{
- return strcasecmp(((ipp_opt_strings_t *)a)->name,
- ((ipp_opt_strings_t *)b)->name);
-}
-
-static void
-free_choice_strings(void* entry, void* user_data)
-{
- ipp_choice_strings_t *entry_rec = (ipp_choice_strings_t *)entry;
-
- if (entry_rec) {
- if (entry_rec->name) free(entry_rec->name);
- if (entry_rec->human_readable) free(entry_rec->human_readable);
- free(entry_rec);
- }
-}
-
-static void
-free_opt_strings(void* entry,
- void* user_data)
-{
- ipp_opt_strings_t *entry_rec = (ipp_opt_strings_t *)entry;
-
- if (entry_rec) {
- if (entry_rec->name) free(entry_rec->name);
- if (entry_rec->human_readable) free(entry_rec->human_readable);
- if (entry_rec->choices) cupsArrayDelete(entry_rec->choices);
- free(entry_rec);
- }
-}
-
-static cups_array_t *
-opt_array_new()
-{
- return cupsArrayNew3(compare_options, NULL, NULL, 0,
- NULL, free_opt_strings);
-}
-
-static ipp_opt_strings_t *
-find_opt_in_array(cups_array_t *options,
- char *name)
-{
- ipp_opt_strings_t opt;
-
- if (!name || !options)
- return NULL;
-
- opt.name = name;
- return cupsArrayFind(options, &opt);
-}
-
-static ipp_choice_strings_t *
-find_choice_in_array(cups_array_t *choices,
- char *name)
-{
- ipp_choice_strings_t choice;
-
- if (!name || !choices)
- return NULL;
-
- choice.name = name;
- return cupsArrayFind(choices, &choice);
-}
-
-static ipp_opt_strings_t *
-add_opt_to_array(char *name,
- char *human_readable,
- cups_array_t *options)
-{
- ipp_opt_strings_t *opt = NULL;
-
- if (!name || !options)
- return NULL;
-
- if ((opt = find_opt_in_array(options, name)) == NULL) {
- opt = calloc(1, sizeof(ipp_opt_strings_t));
- if (!opt) return NULL;
- opt->human_readable = NULL;
- opt->choices = cupsArrayNew3(compare_choices, NULL, NULL, 0,
- NULL, free_choice_strings);
- if (!opt->choices) {
- free(opt);
- return NULL;
- }
- opt->name = strdup(name);
- if (!cupsArrayAdd(options, opt)) {
- free_opt_strings(opt, NULL);
- return NULL;
- }
- }
-
- if (human_readable)
- opt->human_readable = strdup(human_readable);
-
- return opt;
-}
-
-static ipp_choice_strings_t *
-add_choice_to_array(char *name,
- char *human_readable,
- char *opt_name,
- cups_array_t *options)
-{
- ipp_choice_strings_t *choice = NULL;
- ipp_opt_strings_t *opt;
-
- if (!name || !human_readable || !opt_name || !options)
- return NULL;
-
- opt = add_opt_to_array(opt_name, NULL, options);
- if (!opt) return NULL;
-
- if ((choice = find_choice_in_array(opt->choices, name)) == NULL) {
- choice = calloc(1, sizeof(ipp_choice_strings_t));
- if (!choice) return NULL;
- choice->human_readable = NULL;
- choice->name = strdup(name);
- if (!cupsArrayAdd(opt->choices, choice)) {
- free_choice_strings(choice, NULL);
- return NULL;
- }
- }
-
- if (human_readable)
- choice->human_readable = strdup(human_readable);
-
- return choice;
-
-}
-
-static char *
-lookup_option(char *name,
- cups_array_t *options,
- cups_array_t *printer_options)
-{
- ipp_opt_strings_t *opt = NULL;
-
- if (!name || !options)
- return NULL;
-
- if (printer_options &&
- (opt = find_opt_in_array(printer_options, name)) != NULL)
- return opt->human_readable;
- if ((opt = find_opt_in_array(options, name)) != NULL)
- return opt->human_readable;
- else
- return NULL;
-}
-
-static char *
-lookup_choice(char *name,
- char *opt_name,
- cups_array_t *options,
- cups_array_t *printer_options)
-{
- ipp_opt_strings_t *opt = NULL;
- ipp_choice_strings_t *choice = NULL;
-
- if (!name || !opt_name || !options)
- return NULL;
-
- if (printer_options &&
- (opt = find_opt_in_array(printer_options, opt_name)) != NULL &&
- (choice = find_choice_in_array(opt->choices, name)) != NULL)
- return choice->human_readable;
- else if ((opt = find_opt_in_array(options, opt_name)) != NULL &&
- (choice = find_choice_in_array(opt->choices, name)) != NULL)
- return choice->human_readable;
- else
- return NULL;
-}
-
-
-static void
-load_opt_strings_catalog(const char *location,
- cups_array_t *options)
-{
- char tmpfile[1024];
- const char *filename = NULL;
- struct stat statbuf;
- cups_file_t *fp;
- char line[65536];
- char *ptr, *start, *start2, *end, *end2, *sep;
- char *opt_name = NULL, *choice_name = NULL,
- *human_readable = NULL;
- int part = -1; /* -1: before first "msgid" or invalid
- line
- 0: "msgid"
- 1: "msgstr"
- 2: "..." = "..."
- 10: EOF, save last entry */
- int digit;
- int found_in_catalog = 0;
-
- if (location == NULL || (strncasecmp(location, "http:", 5) &&
- strncasecmp(location, "https:", 6))) {
- if (location == NULL ||
- (stat(location, &statbuf) == 0 &&
- S_ISDIR(statbuf.st_mode))) /* directory? */
- {
- filename = find_cups_message_catalog(location);
- if (filename)
- found_in_catalog = 1;
- }
- else
- filename = location;
- } else {
- if (get_url(location, tmpfile, sizeof(tmpfile)))
- filename = tmpfile;
- }
- if (!filename)
- return;
-
- if ((fp = cupsFileOpen(filename, "r")) == NULL)
- {
- if (filename == tmpfile)
- unlink(filename);
- return;
- }
-
- while (cupsFileGets(fp, line, sizeof(line)) || (part = 10)) {
- /* Find a pair of quotes delimiting a string in each line
- and optional "msgid" or "msgstr" keywords, or a
- "..." = "..." pair. Skip comments ('#') and empty lines. */
- if (part < 10) {
- ptr = line;
- while (isspace(*ptr)) ptr ++;
- if (*ptr == '#' || *ptr == '\0') continue;
- if ((start = strchr(ptr, '\"')) == NULL) continue;
- if ((end = strrchr(ptr, '\"')) == start) continue;
- if (*(end - 1) == '\\') continue;
- start2 = NULL;
- end2 = NULL;
- if (start > ptr) {
- if (*(start - 1) == '\\') continue;
- if (strncasecmp(ptr, "msgid", 5) == 0) part = 0;
- if (strncasecmp(ptr, "msgstr", 6) == 0) part = 1;
- } else {
- start2 = ptr;
- while ((start2 = strchr(start2 + 1, '\"')) < end &&
- *(start2 - 1) == '\\');
- if (start2 < end) {
- /* Line with "..." = "..." of text/strings format */
- end2 = end;
- end = start2;
- start2 ++;
- while (isspace(*start2)) start2 ++;
- if (*start2 != '=') continue;
- start2 ++;
- while (isspace(*start2)) start2 ++;
- if (*start2 != '\"') continue;
- start2 ++;
- *end2 = '\0';
- part = 2;
- } else
- /* Continuation line in message catalog file */
- start2 = NULL;
- }
- start ++;
- *end = '\0';
- }
- /* Read out the strings between the quotes and save entries */
- if (part == 0 || part == 2 || part == 10) {
- /* Save previous attribute */
- if (human_readable) {
- if (opt_name) {
- if (choice_name) {
- add_choice_to_array(choice_name, human_readable,
- opt_name, options);
- free(choice_name);
- } else
- add_opt_to_array(opt_name, human_readable, options);
- free(opt_name);
- }
- free(human_readable);
- opt_name = NULL;
- choice_name = NULL;
- human_readable = NULL;
- }
- /* Stop the loop after saving the last entry */
- if (part == 10)
- break;
- /* IPP attribute has to be defined with a single msgid line,
- no continuation lines */
- if (opt_name) {
- free (opt_name);
- opt_name = NULL;
- if (choice_name) {
- free (choice_name);
- choice_name = NULL;
- }
- part = -1;
- continue;
- }
- /* No continuation line in text/strings format */
- if (part == 2 && (start2 == NULL || end2 == NULL)) {
- part = -1;
- continue;
- }
- /* Check line if it is a valid IPP attribute:
- No spaces, only lowercase letters, digits, '-', '_',
- "option" or "option.choice" */
- for (ptr = start, sep = NULL; ptr < end; ptr ++)
- if (*ptr == '.') { /* Separator between option and choice */
- if (!sep) { /* Only the first '.' counts */
- sep = ptr + 1;
- *ptr = '\0';
- }
- } else if (!((*ptr >= 'a' && *ptr <= 'z') ||
- (*ptr >= '0' && *ptr <= '9') ||
- *ptr == '-' || *ptr == '_'))
- break;
- if (ptr < end) { /* Illegal character found */
- part = -1;
- continue;
- }
- if (strlen(start) > 0) /* Option name found */
- opt_name = strdup(start);
- else { /* Empty option name */
- part = -1;
- continue;
- }
- if (sep && strlen(sep) > 0) /* Choice name found */
- choice_name = strdup(sep);
- else /* Empty choice name */
- choice_name = NULL;
- if (part == 2) { /* Human-readable string in the same line */
- start = start2;
- end = end2;
- }
- }
- if (part == 1 || part == 2) {
- /* msgid was not for an IPP attribute, ignore this msgstr */
- if (!opt_name) continue;
- /* Empty string */
- if (start == end) continue;
- /* Unquote string */
- ptr = start;
- end = start;
- while (*ptr) {
- if (*ptr == '\\') {
- ptr ++;
- if (isdigit(*ptr)) {
- digit = 0;
- *end = 0;
- while (isdigit(*ptr) && digit < 3) {
- *end = *end * 8 + *ptr - '0';
- digit ++;
- ptr ++;
- }
- end ++;
- } else {
- if (*ptr == 'n')
- *end ++ = '\n';
- else if (*ptr == 'r')
- *end ++ = '\r';
- else if (*ptr == 't')
- *end ++ = '\t';
- else
- *end ++ = *ptr;
- ptr ++;
- }
- } else
- *end ++ = *ptr ++;
- }
- *end = '\0';
- /* Did the unquoting make the string empty? */
- if (strlen(start) == 0) continue;
- /* Add the string to our human-readable string */
- if (human_readable) { /* Continuation line */
- human_readable = realloc(human_readable,
- sizeof(char) *
- (strlen(human_readable) +
- strlen(start) + 2));
- ptr = human_readable + strlen(human_readable);
- *ptr = ' ';
- strlcpy(ptr + 1, start, strlen(start) + 1);
- } else { /* First line */
- human_readable = malloc(sizeof(char) *
- (strlen(start) + 1));
- strlcpy(human_readable, start, strlen(start) + 1);
- }
- }
- }
- cupsFileClose(fp);
- if (choice_name != NULL)
- free(choice_name);
- if (opt_name != NULL)
- free(opt_name);
- if (filename == tmpfile)
- unlink(filename);
- if (found_in_catalog)
- free((char *)filename);
-}
-
-
-int
-cfCompareResolutions(void *resolution_a,
- void *resolution_b,
- void *user_data)
-{
- cf_res_t *res_a = (cf_res_t *)resolution_a;
- cf_res_t *res_b = (cf_res_t *)resolution_b;
- int i, a, b;
-
- /* Compare the pixels per square inch */
- a = res_a->x * res_a->y;
- b = res_b->x * res_b->y;
- i = (a > b) - (a < b);
- if (i) return i;
-
- /* Compare how much the pixel shape deviates from a square, the
- more, the worse */
- a = 100 * res_a->y / res_a->x;
- if (a > 100) a = 10000 / a;
- b = 100 * res_b->y / res_b->x;
- if (b > 100) b = 10000 / b;
- return (a > b) - (a < b);
-}
-
-void *
-cfCopyResolution(void *resolution,
- void *user_data)
-{
- cf_res_t *res = (cf_res_t *)resolution;
- cf_res_t *copy;
-
- copy = (cf_res_t *)calloc(1, sizeof(cf_res_t));
- if (copy) {
- copy->x = res->x;
- copy->y = res->y;
- }
-
- return copy;
-}
-
-void
-cfFreeResolution(void *resolution,
- void *user_data)
-{
- cf_res_t *res = (cf_res_t *)resolution;
-
- if (res) free(res);
-}
-
-cups_array_t *
-cfNewResolutionArray()
-{
- return cupsArrayNew3(cfCompareResolutions, NULL, NULL, 0,
- cfCopyResolution, cfFreeResolution);
-}
-
-cf_res_t *
-cfNewResolution(int x,
- int y)
-{
- cf_res_t *res = (cf_res_t *)calloc(1, sizeof(cf_res_t));
- if (res) {
- res->x = x;
- res->y = y;
- }
- return res;
-}
-
-/* Read a single resolution from an IPP attribute, take care of
- obviously wrong entries (printer firmware bugs), ignoring
- resolutions of less than 60 dpi in at least one dimension and
- fixing Brother's "600x2dpi" resolutions. */
-cf_res_t *
-cfIPPResToResolution(ipp_attribute_t *attr,
- int index)
-{
- cf_res_t *res = NULL;
- int x = 0, y = 0;
-
- if (attr) {
- ipp_tag_t tag = ippGetValueTag(attr);
- int count = ippGetCount(attr);
-
- if (tag == IPP_TAG_RESOLUTION && index < count) {
- ppdPwgPpdizeResolution(attr, index, &x, &y, NULL, 0);
- if (y == 2) y = x; /* Brother quirk ("600x2dpi") */
- if (x >= 60 && y >= 60)
- res = cfNewResolution(x, y);
- }
- }
-
- return res;
-}
-
-cups_array_t *
-cfIPPAttrToResolutionArray(ipp_attribute_t *attr)
-{
- cups_array_t *res_array = NULL;
- cf_res_t *res;
- int i;
-
- if (attr) {
- ipp_tag_t tag = ippGetValueTag(attr);
- int count = ippGetCount(attr);
-
- if (tag == IPP_TAG_RESOLUTION && count > 0) {
- res_array = cfNewResolutionArray();
- if (res_array) {
- for (i = 0; i < count; i ++)
- if ((res = cfIPPResToResolution(attr, i)) != NULL) {
- if (cupsArrayFind(res_array, res) == NULL)
- cupsArrayAdd(res_array, res);
- cfFreeResolution(res, NULL);
- }
- }
- if (cupsArrayCount(res_array) == 0) {
- cupsArrayDelete(res_array);
- res_array = NULL;
- }
- }
- }
-
- return res_array;
-}
-
-/* Build up an array of common resolutions and most desirable default
- resolution from multiple arrays of resolutions with an optional
- default resolution.
- Call this function with each resolution array you find as "new", and
- in "current" an array of the common resolutions will be built up.
- You do not need to create an empty array for "current" before
- starting. Initialize it with NULL.
- "current_default" holds the default resolution of the array "current".
- It will get replaced by "new_default" if "current_default" is either
- NULL or a resolution which is not in "current" any more.
- "new" and "new_default" will be deleted/freed and set to NULL after
- each, successful or unsuccssful operation.
- Note that when calling this function the addresses of the pointers
- to the resolution arrays and default resolutions have to be given
- (call by reference) as all will get modified by the function. */
-
-int /* 1 on success, 0 on failure */
-cfJoinResolutionArrays(cups_array_t **current,
- cups_array_t **new_arr,
- cf_res_t **current_default,
- cf_res_t **new_default)
-{
- cf_res_t *res;
- int retval;
-
- if (current == NULL || new_arr == NULL || *new_arr == NULL ||
- cupsArrayCount(*new_arr) == 0) {
- retval = 0;
- goto finish;
- }
-
- if (*current == NULL) {
- /* We are adding the very first resolution array, simply make it
- our common resolutions array */
- *current = *new_arr;
- if (current_default) {
- if (*current_default)
- free(*current_default);
- *current_default = (new_default ? *new_default : NULL);
- }
- return 1;
- } else if (cupsArrayCount(*current) == 0) {
- retval = 1;
- goto finish;
- }
-
- /* Dry run: Check whether the two arrays have at least one resolution
- in common, if not, do not touch the original array */
- for (res = cupsArrayFirst(*current);
- res; res = cupsArrayNext(*current))
- if (cupsArrayFind(*new_arr, res))
- break;
-
- if (res) {
- /* Reduce the original array to the resolutions which are in both
- the original and the new array, at least one resolution will
- remain. */
- for (res = cupsArrayFirst(*current);
- res; res = cupsArrayNext(*current))
- if (!cupsArrayFind(*new_arr, res))
- cupsArrayRemove(*current, res);
- if (current_default) {
- /* Replace the current default by the new one if the current default
- is not in the array any more or if it is NULL. If the new default
- is not in the list or NULL in such a case, set the current default
- to NULL */
- if (*current_default && !cupsArrayFind(*current, *current_default)) {
- free(*current_default);
- *current_default = NULL;
- }
- if (*current_default == NULL && new_default && *new_default &&
- cupsArrayFind(*current, *new_default))
- *current_default = cfCopyResolution(*new_default, NULL);
- }
- retval = 1;
- } else
- retval = 0;
-
- finish:
- if (new_arr && *new_arr) {
- cupsArrayDelete(*new_arr);
- *new_arr = NULL;
- }
- if (new_default && *new_default) {
- free(*new_default);
- *new_default = NULL;
- }
- return retval;
-}
-
-cups_array_t*
-cfGenerateSizes(ipp_t *response,
- ipp_attribute_t **defattr,
- int* min_length,
- int* min_width,
- int* max_length,
- int* max_width,
- int* bottom,
- int* left,
- int* right,
- int* top,
- char* ppdname)
-{
- cups_array_t *sizes; /* Media sizes we've added */
- ipp_attribute_t *attr, /* xxx-supported */
- *x_dim, *y_dim; /* Media dimensions */
- ipp_t *media_col, /* Media collection */
- *media_size; /* Media size collection */
- int i, count = 0;
- pwg_media_t *pwg; /* PWG media size */
- int left_def, right_def, bottom_def, top_def;
- ipp_attribute_t *margin; /* media-xxx-margin attribute */
- const char *psname;
-
- if ((attr = ippFindAttribute(response, "media-bottom-margin-supported",
- IPP_TAG_INTEGER)) != NULL) {
- for (i = 1, *bottom = ippGetInteger(attr, 0), count = ippGetCount(attr);
- i < count; i ++)
- if (i == 1 || ippGetInteger(attr, i) < *bottom)
- *bottom = ippGetInteger(attr, i);
- } else
- *bottom = 1270;
-
- if ((attr = ippFindAttribute(response, "media-left-margin-supported",
- IPP_TAG_INTEGER)) != NULL) {
- for (i = 1, *left = ippGetInteger(attr, 0), count = ippGetCount(attr);
- i < count; i ++)
- if (i == 1 || ippGetInteger(attr, i) < *left)
- *left = ippGetInteger(attr, i);
- } else
- *left = 635;
-
- if ((attr = ippFindAttribute(response, "media-right-margin-supported",
- IPP_TAG_INTEGER)) != NULL) {
- for (i = 1, *right = ippGetInteger(attr, 0), count = ippGetCount(attr);
- i < count; i ++)
- if (i == 1 || ippGetInteger(attr, i) < *right)
- *right = ippGetInteger(attr, i);
- } else
- *right = 635;
-
- if ((attr = ippFindAttribute(response, "media-top-margin-supported",
- IPP_TAG_INTEGER)) != NULL) {
- for (i = 1, *top = ippGetInteger(attr, 0), count = ippGetCount(attr);
- i < count; i ++)
- if (i == 1 || ippGetInteger(attr, i) < *top)
- *top = ippGetInteger(attr, i);
- } else
- *top = 1270;
-
- if ((*defattr = ippFindAttribute(response, "media-col-default",
- IPP_TAG_BEGIN_COLLECTION)) != NULL) {
- if ((attr = ippFindAttribute(ippGetCollection(*defattr, 0), "media-size",
- IPP_TAG_BEGIN_COLLECTION)) != NULL) {
- media_size = ippGetCollection(attr, 0);
- x_dim = ippFindAttribute(media_size, "x-dimension", IPP_TAG_INTEGER);
- y_dim = ippFindAttribute(media_size, "y-dimension", IPP_TAG_INTEGER);
-
- if ((margin = ippFindAttribute(ippGetCollection(*defattr, 0),
- "media-bottom-margin", IPP_TAG_INTEGER))
- != NULL)
- bottom_def = ippGetInteger(margin, 0);
- else
- bottom_def = *bottom;
-
- if ((margin = ippFindAttribute(ippGetCollection(*defattr, 0),
- "media-left-margin", IPP_TAG_INTEGER))
- != NULL)
- left_def = ippGetInteger(margin, 0);
- else
- left_def = *left;
-
- if ((margin = ippFindAttribute(ippGetCollection(*defattr, 0),
- "media-right-margin", IPP_TAG_INTEGER))
- != NULL)
- right_def = ippGetInteger(margin, 0);
- else
- right_def = *right;
-
- if ((margin = ippFindAttribute(ippGetCollection(*defattr, 0),
- "media-top-margin", IPP_TAG_INTEGER))
- != NULL)
- top_def = ippGetInteger(margin, 0);
- else
- top_def = *top;
-
- if (x_dim && y_dim &&
- (pwg = pwgMediaForSize(ippGetInteger(x_dim, 0),
- ippGetInteger(y_dim, 0))) != NULL) {
- psname = (pwg->ppd != NULL ? pwg->ppd : pwg->pwg);
- if (bottom_def == 0 && left_def == 0 && right_def == 0 && top_def == 0)
- snprintf(ppdname, PPD_MAX_NAME, "%s.Borderless", psname);
- else
- strlcpy(ppdname, psname, PPD_MAX_NAME);
- } else
- strlcpy(ppdname, "Unknown", PPD_MAX_NAME);
- } else
- strlcpy(ppdname, "Unknown", PPD_MAX_NAME);
- } else if ((pwg =
- pwgMediaForPWG(ippGetString(ippFindAttribute(response,
- "media-default",
- IPP_TAG_ZERO), 0,
- NULL))) != NULL) {
- psname = (pwg->ppd != NULL ? pwg->ppd : pwg->pwg);
- strlcpy(ppdname, psname, PPD_MAX_NAME);
- } else
- strlcpy(ppdname, "Unknown", PPD_MAX_NAME);
-
- sizes = cupsArrayNew3((cups_array_func_t)pwg_compare_sizes, NULL, NULL, 0,
- (cups_acopy_func_t)pwg_copy_size,
- (cups_afree_func_t)free);
-
- if ((attr = ippFindAttribute(response, "media-col-database",
- IPP_TAG_BEGIN_COLLECTION)) != NULL) {
- for (i = 0, count = ippGetCount(attr); i < count; i ++) {
- cups_size_t temp; /* Current size */
-
- media_col = ippGetCollection(attr, i);
- media_size =
- ippGetCollection(ippFindAttribute(media_col, "media-size",
- IPP_TAG_BEGIN_COLLECTION), 0);
- x_dim = ippFindAttribute(media_size, "x-dimension", IPP_TAG_ZERO);
- y_dim = ippFindAttribute(media_size, "y-dimension", IPP_TAG_ZERO);
- pwg = pwgMediaForSize(ippGetInteger(x_dim, 0),
- ippGetInteger(y_dim, 0));
-
- if (pwg) {
- temp.width = pwg->width;
- temp.length = pwg->length;
-
- if ((margin = ippFindAttribute(media_col, "media-bottom-margin",
- IPP_TAG_INTEGER)) != NULL)
- temp.bottom = ippGetInteger(margin, 0);
- else
- temp.bottom = *bottom;
-
- if ((margin = ippFindAttribute(media_col, "media-left-margin",
- IPP_TAG_INTEGER)) != NULL)
- temp.left = ippGetInteger(margin, 0);
- else
- temp.left = *left;
-
- if ((margin = ippFindAttribute(media_col, "media-right-margin",
- IPP_TAG_INTEGER)) != NULL)
- temp.right = ippGetInteger(margin, 0);
- else
- temp.right = *right;
-
- if ((margin = ippFindAttribute(media_col, "media-top-margin",
- IPP_TAG_INTEGER)) != NULL)
- temp.top = ippGetInteger(margin, 0);
- else
- temp.top = *top;
-
- psname = (pwg->ppd != NULL ? pwg->ppd : pwg->pwg);
- if (temp.bottom == 0 && temp.left == 0 && temp.right == 0 &&
- temp.top == 0)
- snprintf(temp.media, sizeof(temp.media), "%s.Borderless", psname);
- else
- strlcpy(temp.media, psname, sizeof(temp.media));
-
- if (!cupsArrayFind(sizes, &temp))
- cupsArrayAdd(sizes, &temp);
- } else if (ippGetValueTag(x_dim) == IPP_TAG_RANGE ||
- ippGetValueTag(y_dim) == IPP_TAG_RANGE) {
- /*
- * Custom size - record the min/max values...
- */
-
- int lower, upper; /* Range values */
-
- if (ippGetValueTag(x_dim) == IPP_TAG_RANGE)
- lower = ippGetRange(x_dim, 0, &upper);
- else
- lower = upper = ippGetInteger(x_dim, 0);
-
- if (lower < *min_width)
- *min_width = lower;
- if (upper > *max_width)
- *max_width = upper;
-
- if (ippGetValueTag(y_dim) == IPP_TAG_RANGE)
- lower = ippGetRange(y_dim, 0, &upper);
- else
- lower = upper = ippGetInteger(y_dim, 0);
-
- if (lower < *min_length)
- *min_length = lower;
- if (upper > *max_length)
- *max_length = upper;
- }
- }
- }
- if ((attr = ippFindAttribute(response, "media-size-supported",
- IPP_TAG_BEGIN_COLLECTION)) != NULL) {
- for (i = 0, count = ippGetCount(attr); i < count; i ++) {
- cups_size_t temp; /* Current size */
-
- media_size = ippGetCollection(attr, i);
- x_dim = ippFindAttribute(media_size, "x-dimension", IPP_TAG_ZERO);
- y_dim = ippFindAttribute(media_size, "y-dimension", IPP_TAG_ZERO);
- pwg = pwgMediaForSize(ippGetInteger(x_dim, 0),
- ippGetInteger(y_dim, 0));
-
- if (pwg) {
- temp.width = pwg->width;
- temp.length = pwg->length;
- temp.bottom = *bottom;
- temp.left = *left;
- temp.right = *right;
- temp.top = *top;
-
- psname = (pwg->ppd != NULL ? pwg->ppd : pwg->pwg);
- if (temp.bottom == 0 && temp.left == 0 && temp.right == 0 &&
- temp.top == 0)
- snprintf(temp.media, sizeof(temp.media), "%s.Borderless", psname);
- else
- strlcpy(temp.media, psname, sizeof(temp.media));
-
- if (!cupsArrayFind(sizes, &temp))
- cupsArrayAdd(sizes, &temp);
- } else if (ippGetValueTag(x_dim) == IPP_TAG_RANGE ||
- ippGetValueTag(y_dim) == IPP_TAG_RANGE) {
- /*
- * Custom size - record the min/max values...
- */
-
- int lower, upper; /* Range values */
-
- if (ippGetValueTag(x_dim) == IPP_TAG_RANGE)
- lower = ippGetRange(x_dim, 0, &upper);
- else
- lower = upper = ippGetInteger(x_dim, 0);
-
- if (lower < *min_width)
- *min_width = lower;
- if (upper > *max_width)
- *max_width = upper;
-
- if (ippGetValueTag(y_dim) == IPP_TAG_RANGE)
- lower = ippGetRange(y_dim, 0, &upper);
- else
- lower = upper = ippGetInteger(y_dim, 0);
-
- if (lower < *min_length)
- *min_length = lower;
- if (upper > *max_length)
- *max_length = upper;
- }
- }
- }
- if ((attr = ippFindAttribute(response, "media-supported", IPP_TAG_ZERO))
- != NULL) {
- for (i = 0, count = ippGetCount(attr); i < count; i ++) {
- const char *pwg_size = ippGetString(attr, i, NULL);
- /* PWG size name */
- cups_size_t temp, *temp2; /* Current size, found size */
-
- if ((pwg = pwgMediaForPWG(pwg_size)) != NULL) {
- if (strstr(pwg_size, "_max_") || strstr(pwg_size, "_max.")) {
- if (pwg->width > *max_width)
- *max_width = pwg->width;
- if (pwg->length > *max_length)
- *max_length = pwg->length;
- } else if (strstr(pwg_size, "_min_") || strstr(pwg_size, "_min.")) {
- if (pwg->width < *min_width)
- *min_width = pwg->width;
- if (pwg->length < *min_length)
- *min_length = pwg->length;
- } else {
- temp.width = pwg->width;
- temp.length = pwg->length;
- temp.bottom = *bottom;
- temp.left = *left;
- temp.right = *right;
- temp.top = *top;
-
- psname = (pwg->ppd != NULL ? pwg->ppd : pwg->pwg);
- if (temp.bottom == 0 && temp.left == 0 && temp.right == 0 &&
- temp.top == 0)
- snprintf(temp.media, sizeof(temp.media), "%s.Borderless", psname);
- else
- strlcpy(temp.media, psname, sizeof(temp.media));
-
- /* Add the printer's original IPP name to an already found size */
- if ((temp2 = cupsArrayFind(sizes, &temp)) != NULL) {
- snprintf(temp2->media + strlen(temp2->media),
- sizeof(temp2->media) - strlen(temp2->media),
- " %s", pwg_size);
- /* Check if we have also a borderless version of the size and add
- the original IPP name also there */
- snprintf(temp.media, sizeof(temp.media), "%s.Borderless", psname);
- if ((temp2 = cupsArrayFind(sizes, &temp)) != NULL)
- snprintf(temp2->media + strlen(temp2->media),
- sizeof(temp2->media) - strlen(temp2->media),
- " %s", pwg_size);
- } else
- cupsArrayAdd(sizes, &temp);
- }
- }
- }
- }
- return sizes;
-}
-
-
/*
* Human-readable strings in the PPDs generated by the PPD generator for
* using driverless IPP printers with CUPS
*/
/*
- * 'cfCreatePPDFromIPP()' - Create a PPD file describing the capabilities
- * of an IPP printer, using info from DNS-SD record
- * as fallback (for poor IPP responses, especially
- * IPP 1.x legacy)
+ * 'ppdCreatePPDFromIPP()' - Create a PPD file describing the capabilities
+ * of an IPP printer, using info from DNS-SD record
+ * as fallback (for poor IPP responses, especially
+ * IPP 1.x legacy)
*/
-char * /* O - PPD filename or NULL on
- error */
-cfCreatePPDFromIPP (char *buffer, /* I - Filename buffer */
+char * /* O - PPD filename or NULL
+ on error */
+ppdCreatePPDFromIPP(char *buffer, /* I - Filename buffer */
size_t bufsize, /* I - Size of filename
buffer */
ipp_t *response, /* I - Get-Printer-Attributes
size_t status_msg_size) /* I - Size of status message
buffer */
{
- return cfCreatePPDFromIPP2(buffer, bufsize, response, make_model, pdl,
- color, duplex, NULL, NULL, NULL, NULL,
- status_msg, status_msg_size);
+ return ppdCreatePPDFromIPP2(buffer, bufsize, response, make_model, pdl,
+ color, duplex, NULL, NULL, NULL, NULL,
+ status_msg, status_msg_size);
}
/*
- * 'cfCreatePPDFromIPP2()' - Create a PPD file describing the capabilities
- * of an IPP printer, with extra parameters for
- * PPDs from a merged IPP record for printer
- * clusters
+ * 'ppdCreatePPDFromIPP2()' - Create a PPD file describing the
+ * capabilities of an IPP printer, with
+ * extra parameters for PPDs from a merged
+ * IPP record for printer clusters
*/
-char * /* O - PPD filename or NULL on
- error */
-cfCreatePPDFromIPP2(char *buffer, /* I - Filename buffer */
- size_t bufsize, /* I - Size of filename
- buffer */
- ipp_t *response, /* I - Get-Printer-Attributes
- response */
- const char *make_model, /* I - Make and model from
- DNS-SD */
- const char *pdl, /* I - List of PDLs from
- DNS-SD */
- int color, /* I - Color printer? (from
- DNS-SD) */
- int duplex, /* I - Duplex printer? (from
- DNS-SD) */
- cups_array_t *conflicts, /* I - Array of constraints*/
- cups_array_t *sizes, /* I - Media sizes we've
- added */
- char* default_pagesize, /* I - Default page size*/
- const char *default_cluster_color, /* I - cluster def
- color (if cluster's
- attributes are
- returned) */
- char *status_msg, /* I - Status message buffer,
- NULL to ignore
- message */
- size_t status_msg_size) /* I - Size of status message
- buffer */
+char * /* O - PPD filename or NULL
+ on error */
+ppdCreatePPDFromIPP2(char *buffer, /* I - Filename buffer */
+ size_t bufsize, /* I - Size of filename
+ buffer */
+ ipp_t *response, /* I - Get-Printer-
+ Attributes response*/
+ const char *make_model, /* I - Make and model from
+ DNS-SD */
+ const char *pdl, /* I - List of PDLs from
+ DNS-SD */
+ int color, /* I - Color printer? (from
+ DNS-SD) */
+ int duplex, /* I - Duplex printer? (from
+ DNS-SD) */
+ cups_array_t *conflicts, /* I - Array of
+ constraints */
+ cups_array_t *sizes, /* I - Media sizes we've
+ added */
+ char* default_pagesize, /* I - Default page size*/
+ const char *default_cluster_color, /* I - cluster def
+ color (if cluster's
+ attributes are
+ returned) */
+ char *status_msg, /* I - Status message
+ buffer, NULL to
+ ignore message */
+ size_t status_msg_size) /* I - Size of status
+ message buffer */
{
cups_file_t *fp; /* PPD file */
cups_array_t *printer_sizes; /* Media sizes we've added */
NULL));
/* Message catalogs for UI strings */
- if (opt_strings_catalog == NULL) {
- opt_strings_catalog = opt_array_new();
- load_opt_strings_catalog(NULL, opt_strings_catalog);
- }
+ opt_strings_catalog = cfCatalogOptionArrayNew();
+ cfCatalogLoad(NULL, opt_strings_catalog);
if ((attr = ippFindAttribute(response, "printer-strings-uri",
IPP_TAG_URI)) != NULL) {
- printer_opt_strings_catalog = opt_array_new();
- load_opt_strings_catalog(ippGetString(attr, 0, NULL),
- printer_opt_strings_catalog);
+ printer_opt_strings_catalog = cfCatalogOptionArrayNew();
+ cfCatalogLoad(ippGetString(attr, 0, NULL),
+ printer_opt_strings_catalog);
if (cupsArrayCount(printer_opt_strings_catalog) > 0)
cupsFilePrintf(fp, "*cupsStringsURI: \"%s\"\n", ippGetString(attr, 0,
NULL));
/*
* PageSize/PageRegion/ImageableArea/PaperDimension
*/
- printer_sizes = cfGenerateSizes(response, &defattr, &min_length, &min_width,
- &max_length, &max_width,
- &bottom, &left, &right, &top, ppdname);
+ cfGenerateSizes(response, CF_GEN_SIZES_DEFAULT, &printer_sizes, &defattr,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ &min_width, &min_length,
+ &max_width, &max_length,
+ &left, &bottom, &right, &top, ppdname, NULL);
if (sizes==NULL) {
sizes = printer_sizes;
} else
}
if (ippsizename)
- human_readable = lookup_choice(ippsizename, "media",
- opt_strings_catalog,
- printer_opt_strings_catalog);
+ human_readable = cfCatalogLookUpChoice(ippsizename, "media",
+ opt_strings_catalog,
+ printer_opt_strings_catalog);
else
human_readable = NULL;
if (!human_readable) {
pwg = pwgMediaForSize(size->width, size->length);
if (pwg)
- human_readable = lookup_choice((char *)pwg->pwg, "media",
- opt_strings_catalog,
- printer_opt_strings_catalog);
+ human_readable = cfCatalogLookUpChoice((char *)pwg->pwg, "media",
+ opt_strings_catalog,
+ printer_opt_strings_catalog);
}
if (all_borderless) {
}
if (ippsizename)
- human_readable = lookup_choice(ippsizename, "media",
- opt_strings_catalog,
- printer_opt_strings_catalog);
+ human_readable = cfCatalogLookUpChoice(ippsizename, "media",
+ opt_strings_catalog,
+ printer_opt_strings_catalog);
else
human_readable = NULL;
if (!human_readable) {
pwg = pwgMediaForSize(size->width, size->length);
if (pwg)
- human_readable = lookup_choice((char *)pwg->pwg, "media",
- opt_strings_catalog,
- printer_opt_strings_catalog);
+ human_readable = cfCatalogLookUpChoice((char *)pwg->pwg, "media",
+ opt_strings_catalog,
+ printer_opt_strings_catalog);
}
if (all_borderless) {
"roll-10"
};
- human_readable = lookup_option("media-source", opt_strings_catalog,
- printer_opt_strings_catalog);
+ human_readable = cfCatalogLookUpOption("media-source", opt_strings_catalog,
+ printer_opt_strings_catalog);
cupsFilePrintf(fp, "*OpenUI *InputSlot/%s: PickOne\n"
"*OrderDependency: 10 AnySetup *InputSlot\n",
(human_readable ? human_readable : "Media Source"));
if (i == 0 && !have_default)
cupsFilePrintf(fp, "*DefaultInputSlot: %s\n", ppdname);
- human_readable = lookup_choice((char *)keyword, "media-source",
- opt_strings_catalog,
- printer_opt_strings_catalog);
+ human_readable = cfCatalogLookUpChoice((char *)keyword, "media-source",
+ opt_strings_catalog,
+ printer_opt_strings_catalog);
for (j = (int)(sizeof(sources) / sizeof(sources[0])) - 1; j >= 0; j --)
if (!strcmp(sources[j], keyword))
break;
if ((attr = ippFindAttribute(response, "media-type-supported",
IPP_TAG_ZERO)) != NULL &&
(count = ippGetCount(attr)) > 1) {
- human_readable = lookup_option("media-type", opt_strings_catalog,
- printer_opt_strings_catalog);
+ human_readable = cfCatalogLookUpOption("media-type", opt_strings_catalog,
+ printer_opt_strings_catalog);
cupsFilePrintf(fp, "*OpenUI *MediaType/%s: PickOne\n"
"*OrderDependency: 10 AnySetup *MediaType\n"
"*DefaultMediaType: %s\n",
ppdPwgPpdizeName(keyword, ppdname, sizeof(ppdname));
- human_readable = lookup_choice((char *)keyword, "media-type",
- opt_strings_catalog,
- printer_opt_strings_catalog);
+ human_readable = cfCatalogLookUpChoice((char *)keyword, "media-type",
+ opt_strings_catalog,
+ printer_opt_strings_catalog);
cupsFilePrintf(fp, "*MediaType %s%s%s: \"<</MediaType(%s)>>setpagedevice\"\n",
ppdname,
(human_readable ? "/" : ""),
attr = ippFindAttribute(response, "output-mode-supported",
IPP_TAG_KEYWORD);
- human_readable = lookup_option("print-color-mode", opt_strings_catalog,
- printer_opt_strings_catalog);
+ human_readable = cfCatalogLookUpOption("print-color-mode",
+ opt_strings_catalog,
+ printer_opt_strings_catalog);
if (attr && ippGetCount(attr) > 0) {
const char *default_color = NULL; /* Default */
int first_choice = 1;
(human_readable ? human_readable : "Color Mode"));
}
- human_readable2 = lookup_choice("bi-level", "print-color-mode",
- opt_strings_catalog,
- printer_opt_strings_catalog);
+ human_readable2 = cfCatalogLookUpChoice("bi-level", "print-color-mode",
+ opt_strings_catalog,
+ printer_opt_strings_catalog);
cupsFilePrintf(fp, "*ColorModel FastGray/%s: \"\"\n",
(human_readable2 ? human_readable2 : "Text"));
(human_readable ? human_readable : "Color Mode"));
}
- human_readable2 = lookup_choice("process-bi-level", "print-color-mode",
- opt_strings_catalog,
- printer_opt_strings_catalog);
+ human_readable2 = cfCatalogLookUpChoice("process-bi-level",
+ "print-color-mode",
+ opt_strings_catalog,
+ printer_opt_strings_catalog);
cupsFilePrintf(fp, "*ColorModel ProcessFastGray/%s: \"\"\n",
(human_readable2 ? human_readable2 : "Process Text"));
} else if (!strcmp(keyword, "auto-monochrome")) {
(human_readable ? human_readable : "Color Mode"));
}
- human_readable2 = lookup_choice("auto-monochrome", "print-color-mode",
- opt_strings_catalog,
- printer_opt_strings_catalog);
+ human_readable2 = cfCatalogLookUpChoice("auto-monochrome",
+ "print-color-mode",
+ opt_strings_catalog,
+ printer_opt_strings_catalog);
cupsFilePrintf(fp, "*ColorModel AutoGray/%s: \"\"\n",
(human_readable2 ? human_readable2 : "Auto Monochrome"));
} else if (!strcmp(keyword, "monochrome")) {
(human_readable ? human_readable : "Color Mode"));
}
- human_readable2 = lookup_choice("monochrome", "print-color-mode",
- opt_strings_catalog,
- printer_opt_strings_catalog);
+ human_readable2 = cfCatalogLookUpChoice("monochrome",
+ "print-color-mode",
+ opt_strings_catalog,
+ printer_opt_strings_catalog);
cupsFilePrintf(fp, "*ColorModel Gray/%s: \"\"\n",
(human_readable2 ? human_readable2 : "Monochrome"));
(human_readable ? human_readable : "Color Mode"));
}
- human_readable2 = lookup_choice("process-monochrome",
- "print-color-mode",
- opt_strings_catalog,
- printer_opt_strings_catalog);
+ human_readable2 = cfCatalogLookUpChoice("process-monochrome",
+ "print-color-mode",
+ opt_strings_catalog,
+ printer_opt_strings_catalog);
cupsFilePrintf(fp, "*ColorModel ProcessGray/%s: \"\"\n",
(human_readable2 ? human_readable2 :
"Process Monochrome"));
(human_readable ? human_readable : "Color Mode"));
}
- human_readable2 = lookup_choice("color", "print-color-mode",
- opt_strings_catalog,
- printer_opt_strings_catalog);
+ human_readable2 = cfCatalogLookUpChoice("color", "print-color-mode",
+ opt_strings_catalog,
+ printer_opt_strings_catalog);
cupsFilePrintf(fp, "*ColorModel RGB/%s: \"\"\n",
(human_readable2 ? human_readable2 : "Color"));
!ippContainsString(attr, "process-monochrome") &&
!ippContainsString(attr, "bi-level") &&
!ippContainsString(attr, "process-bi-level")) {
- human_readable2 = lookup_choice("monochrome", "print-color-mode",
- opt_strings_catalog,
- printer_opt_strings_catalog);
+ human_readable2 = cfCatalogLookUpChoice("monochrome",
+ "print-color-mode",
+ opt_strings_catalog,
+ printer_opt_strings_catalog);
cupsFilePrintf(fp, "*ColorModel Gray/%s: \"\"\n",
(human_readable2 ? human_readable2 : "Grayscale"));
}
IPP_TAG_KEYWORD)) != NULL &&
ippContainsString(attr, "two-sided-long-edge")) ||
(attr == NULL && duplex)) {
- human_readable = lookup_option("sides", opt_strings_catalog,
- printer_opt_strings_catalog);
+ human_readable = cfCatalogLookUpOption("sides", opt_strings_catalog,
+ printer_opt_strings_catalog);
cupsFilePrintf(fp, "*OpenUI *Duplex/%s: PickOne\n"
"*OrderDependency: 10 AnySetup *Duplex\n"
"*DefaultDuplex: None\n",
(human_readable ? human_readable : "2-Sided Printing"));
- human_readable = lookup_choice("one-sided", "sides", opt_strings_catalog,
- printer_opt_strings_catalog);
+ human_readable = cfCatalogLookUpChoice("one-sided", "sides",
+ opt_strings_catalog,
+ printer_opt_strings_catalog);
cupsFilePrintf(fp, "*Duplex None/%s: \"<</Duplex false>>setpagedevice\"\n",
(human_readable ? human_readable : "Off"));
- human_readable = lookup_choice("two-sided-long-edge", "sides",
- opt_strings_catalog,
- printer_opt_strings_catalog);
+ human_readable = cfCatalogLookUpChoice("two-sided-long-edge", "sides",
+ opt_strings_catalog,
+ printer_opt_strings_catalog);
cupsFilePrintf(fp, "*Duplex DuplexNoTumble/%s: \"<</Duplex true/Tumble false>>setpagedevice\"\n",
(human_readable ? human_readable : "On (Portrait)"));
- human_readable = lookup_choice("two-sided-short-edge", "sides",
- opt_strings_catalog,
- printer_opt_strings_catalog);
+ human_readable = cfCatalogLookUpChoice("two-sided-short-edge", "sides",
+ opt_strings_catalog,
+ printer_opt_strings_catalog);
cupsFilePrintf(fp, "*Duplex DuplexTumble/%s: \"<</Duplex true/Tumble true>>setpagedevice\"\n",
(human_readable ? human_readable : "On (Landscape)"));
cupsFilePrintf(fp, "*CloseUI: *Duplex\n");
if ((attr = ippFindAttribute(response, "output-bin-supported",
IPP_TAG_ZERO)) != NULL &&
(count = ippGetCount(attr)) > 0) {
- human_readable = lookup_option("output-bin", opt_strings_catalog,
- printer_opt_strings_catalog);
+ human_readable = cfCatalogLookUpOption("output-bin", opt_strings_catalog,
+ printer_opt_strings_catalog);
cupsFilePrintf(fp, "*OpenUI *OutputBin/%s: PickOne\n"
"*OrderDependency: 10 AnySetup *OutputBin\n"
"*DefaultOutputBin: %s\n",
ppdPwgPpdizeName(keyword, ppdname, sizeof(ppdname));
- human_readable = lookup_choice((char *)keyword, "output-bin",
- opt_strings_catalog,
- printer_opt_strings_catalog);
+ human_readable = cfCatalogLookUpChoice((char *)keyword, "output-bin",
+ opt_strings_catalog,
+ printer_opt_strings_catalog);
cupsFilePrintf(fp, "*OutputBin %s%s%s: \"\"\n",
ppdname,
(human_readable ? "/" : ""),
cupsArrayAdd(fin_options, "*StapleLocation");
- human_readable = lookup_choice("staple", "finishing-template",
- opt_strings_catalog,
- printer_opt_strings_catalog);
+ human_readable = cfCatalogLookUpChoice("staple", "finishing-template",
+ opt_strings_catalog,
+ printer_opt_strings_catalog);
cupsFilePrintf(fp, "*OpenUI *StapleLocation/%s: PickOne\n",
(human_readable ? human_readable : "Staple"));
cupsFilePuts(fp, "*OrderDependency: 10 AnySetup *StapleLocation\n");
cupsFilePuts(fp, "*DefaultStapleLocation: None\n");
- human_readable = lookup_choice("3", "finishings",
- opt_strings_catalog,
- printer_opt_strings_catalog);
+ human_readable = cfCatalogLookUpChoice("3", "finishings",
+ opt_strings_catalog,
+ printer_opt_strings_catalog);
cupsFilePrintf(fp, "*StapleLocation None/%s: \"\"\n",
(human_readable ? human_readable : "None"));
continue;
snprintf(buf, sizeof(buf), "%d", value);
- human_readable = lookup_choice(buf, "finishings", opt_strings_catalog,
- printer_opt_strings_catalog);
+ human_readable = cfCatalogLookUpChoice(buf, "finishings",
+ opt_strings_catalog,
+ printer_opt_strings_catalog);
cupsFilePrintf(fp, "*StapleLocation %s%s%s: \"\"\n", ppd_keyword,
(human_readable ? "/" : ""),
(human_readable ? human_readable : ""));
cupsArrayAdd(fin_options, "*FoldType");
- human_readable = lookup_choice("fold", "finishing-template",
- opt_strings_catalog,
- printer_opt_strings_catalog);
+ human_readable = cfCatalogLookUpChoice("fold", "finishing-template",
+ opt_strings_catalog,
+ printer_opt_strings_catalog);
cupsFilePrintf(fp, "*OpenUI *FoldType/%s: PickOne\n",
(human_readable ? human_readable : "Fold"));
cupsFilePuts(fp, "*OrderDependency: 10 AnySetup *FoldType\n");
cupsFilePuts(fp, "*DefaultFoldType: None\n");
- human_readable = lookup_choice("3", "finishings",
- opt_strings_catalog,
- printer_opt_strings_catalog);
+ human_readable = cfCatalogLookUpChoice("3", "finishings",
+ opt_strings_catalog,
+ printer_opt_strings_catalog);
cupsFilePrintf(fp, "*FoldType None/%s: \"\"\n",
(human_readable ? human_readable : "None"));
continue;
snprintf(buf, sizeof(buf), "%d", value);
- human_readable = lookup_choice(buf, "finishings", opt_strings_catalog,
- printer_opt_strings_catalog);
+ human_readable = cfCatalogLookUpChoice(buf, "finishings",
+ opt_strings_catalog,
+ printer_opt_strings_catalog);
cupsFilePrintf(fp, "*FoldType %s%s%s: \"\"\n", ppd_keyword,
(human_readable ? "/" : ""),
(human_readable ? human_readable : ""));
cupsArrayAdd(fin_options, "*PunchMedia");
- human_readable = lookup_choice("punch", "finishing-template",
- opt_strings_catalog,
- printer_opt_strings_catalog);
+ human_readable = cfCatalogLookUpChoice("punch", "finishing-template",
+ opt_strings_catalog,
+ printer_opt_strings_catalog);
cupsFilePrintf(fp, "*OpenUI *PunchMedia/%s: PickOne\n",
(human_readable ? human_readable : "Punch"));
cupsFilePuts(fp, "*OrderDependency: 10 AnySetup *PunchMedia\n");
cupsFilePuts(fp, "*DefaultPunchMedia: None\n");
- human_readable = lookup_choice("3", "finishings",
- opt_strings_catalog,
- printer_opt_strings_catalog);
+ human_readable = cfCatalogLookUpChoice("3", "finishings",
+ opt_strings_catalog,
+ printer_opt_strings_catalog);
cupsFilePrintf(fp, "*PunchMedia None/%s: \"\"\n",
(human_readable ? human_readable : "None"));
continue;
snprintf(buf, sizeof(buf), "%d", value);
- human_readable = lookup_choice(buf, "finishings", opt_strings_catalog,
- printer_opt_strings_catalog);
+ human_readable = cfCatalogLookUpChoice(buf, "finishings",
+ opt_strings_catalog,
+ printer_opt_strings_catalog);
cupsFilePrintf(fp, "*PunchMedia %s%s%s: \"\"\n", ppd_keyword,
(human_readable ? "/" : ""),
(human_readable ? human_readable : ""));
if (ippContainsInteger(attr, IPP_FINISHINGS_BOOKLET_MAKER)) {
cupsArrayAdd(fin_options, "*Booklet");
- human_readable = lookup_choice("booklet-maker", "finishing-template",
- opt_strings_catalog,
- printer_opt_strings_catalog);
+ human_readable = cfCatalogLookUpChoice("booklet-maker",
+ "finishing-template",
+ opt_strings_catalog,
+ printer_opt_strings_catalog);
cupsFilePrintf(fp, "*OpenUI *Booklet/%s: Boolean\n",
(human_readable ? human_readable : "Booklet"));
cupsFilePuts(fp, "*OrderDependency: 10 AnySetup *Booklet\n");
cupsArrayAdd(fin_options, "*CutMedia");
- human_readable = lookup_choice("trim", "finishing-template",
- opt_strings_catalog,
- printer_opt_strings_catalog);
+ human_readable = cfCatalogLookUpChoice("trim", "finishing-template",
+ opt_strings_catalog,
+ printer_opt_strings_catalog);
cupsFilePrintf(fp, "*OpenUI *CutMedia/%s: PickOne\n",
(human_readable ? human_readable : "Cut"));
cupsFilePuts(fp, "*OrderDependency: 10 AnySetup *CutMedia\n");
cupsFilePuts(fp, "*DefaultCutMedia: None\n");
- human_readable = lookup_choice("3", "finishings",
- opt_strings_catalog,
- printer_opt_strings_catalog);
+ human_readable = cfCatalogLookUpChoice("3", "finishings",
+ opt_strings_catalog,
+ printer_opt_strings_catalog);
cupsFilePrintf(fp, "*CutMedia None/%s: \"\"\n",
(human_readable ? human_readable : "None"));
ppd_keyword = trim_keywords[value - IPP_FINISHINGS_TRIM_AFTER_PAGES];
snprintf(buf, sizeof(buf), "%d", value);
- human_readable = lookup_choice(buf, "finishings", opt_strings_catalog,
- printer_opt_strings_catalog);
+ human_readable = cfCatalogLookUpChoice(buf, "finishings",
+ opt_strings_catalog,
+ printer_opt_strings_catalog);
cupsFilePrintf(fp, "*CutMedia %s%s%s: \"\"\n", ppd_keyword,
(human_readable ? "/" : ""),
(human_readable ? human_readable : ""));
ipp_attribute_t *finishing_attr; /* Current finishing member attribute */
cups_array_t *templates; /* Finishing templates */
- human_readable = lookup_option("finishing-template", opt_strings_catalog,
- printer_opt_strings_catalog);
+ human_readable = cfCatalogLookUpOption("finishing-template",
+ opt_strings_catalog,
+ printer_opt_strings_catalog);
cupsFilePrintf(fp, "*OpenUI *cupsFinishingTemplate/%s: PickOne\n",
(human_readable ? human_readable : "Finishing Template"));
cupsFilePuts(fp, "*OrderDependency: 10 AnySetup *cupsFinishingTemplate\n");
cupsFilePuts(fp, "*DefaultcupsFinishingTemplate: none\n");
- human_readable = lookup_choice("3", "finishings",
- opt_strings_catalog,
- printer_opt_strings_catalog);
+ human_readable = cfCatalogLookUpChoice("3", "finishings",
+ opt_strings_catalog,
+ printer_opt_strings_catalog);
cupsFilePrintf(fp, "*cupsFinishingTemplate None/%s: \"\"\n",
(human_readable ? human_readable : "None"));
cupsArrayAdd(templates, (void *)keyword);
- human_readable = lookup_choice((char *)keyword, "finishing-template",
- opt_strings_catalog,
- printer_opt_strings_catalog);
+ human_readable = cfCatalogLookUpChoice((char *)keyword,
+ "finishing-template",
+ opt_strings_catalog,
+ printer_opt_strings_catalog);
if (human_readable == NULL)
human_readable = (char *)keyword;
cupsFilePrintf(fp, "*cupsFinishingTemplate %s/%s: \"\n", keyword,
if ((quality =
ippFindAttribute(response, "print-quality-supported",
IPP_TAG_ENUM)) != NULL) {
- human_readable = lookup_option("print-quality", opt_strings_catalog,
- printer_opt_strings_catalog);
+ human_readable = cfCatalogLookUpOption("print-quality", opt_strings_catalog,
+ printer_opt_strings_catalog);
cupsFilePrintf(fp, "*OpenUI *cupsPrintQuality/%s: PickOne\n"
"*OrderDependency: 10 AnySetup *cupsPrintQuality\n"
"*DefaultcupsPrintQuality: Normal\n",
(human_readable ? human_readable : "Print Quality"));
if (ippContainsInteger(quality, IPP_QUALITY_DRAFT)) {
- human_readable = lookup_choice("3", "print-quality", opt_strings_catalog,
- printer_opt_strings_catalog);
+ human_readable = cfCatalogLookUpChoice("3", "print-quality",
+ opt_strings_catalog,
+ printer_opt_strings_catalog);
cupsFilePrintf(fp, "*cupsPrintQuality Draft/%s: \"<</HWResolution[%d %d]>>setpagedevice\"\n",
(human_readable ? human_readable : "Draft"),
min_res->x, min_res->y);
}
- human_readable = lookup_choice("4", "print-quality", opt_strings_catalog,
- printer_opt_strings_catalog);
+ human_readable = cfCatalogLookUpChoice("4", "print-quality",
+ opt_strings_catalog,
+ printer_opt_strings_catalog);
cupsFilePrintf(fp, "*cupsPrintQuality Normal/%s: \"<</HWResolution[%d %d]>>setpagedevice\"\n",
(human_readable ? human_readable : "Normal"),
common_def->x, common_def->y);
if (ippContainsInteger(quality, IPP_QUALITY_HIGH)) {
- human_readable = lookup_choice("5", "print-quality", opt_strings_catalog,
- printer_opt_strings_catalog);
+ human_readable = cfCatalogLookUpChoice("5", "print-quality",
+ opt_strings_catalog,
+ printer_opt_strings_catalog);
cupsFilePrintf(fp, "*cupsPrintQuality High/%s: \"<</HWResolution[%d %d]>>setpagedevice\"\n",
(human_readable ? human_readable : "High"),
max_res->x, max_res->y);
if ((attr = ippFindAttribute(response, "print-content-optimize-supported",
IPP_TAG_ZERO)) != NULL &&
(count = ippGetCount(attr)) > 1) {
- human_readable = lookup_option("print-content-optimize",
- opt_strings_catalog,
- printer_opt_strings_catalog);
+ human_readable = cfCatalogLookUpOption("print-content-optimize",
+ opt_strings_catalog,
+ printer_opt_strings_catalog);
cupsFilePrintf(fp, "*OpenUI *print-content-optimize/%s: PickOne\n"
"*OrderDependency: 10 AnySetup *print-content-optimize\n"
"*Defaultprint-content-optimize: %s\n",
for (i = 0; i < count; i ++) {
keyword = ippGetString(attr, i, NULL);
- human_readable = lookup_choice((char *)keyword,
- "print-content-optimize",
- opt_strings_catalog,
- printer_opt_strings_catalog);
+ human_readable = cfCatalogLookUpChoice((char *)keyword,
+ "print-content-optimize",
+ opt_strings_catalog,
+ printer_opt_strings_catalog);
cupsFilePrintf(fp, "*print-content-optimize %s%s%s: \"\"\n",
keyword,
(human_readable ? "/" : ""),
if ((attr = ippFindAttribute(response, "print-rendering-intent-supported",
IPP_TAG_ZERO)) != NULL &&
(count = ippGetCount(attr)) > 1) {
- human_readable = lookup_option("print-rendering-intent",
- opt_strings_catalog,
- printer_opt_strings_catalog);
- cupsFilePrintf(fp, "*OpenUI *print-rendering-intent/%s: PickOne\n"
- "*OrderDependency: 10 AnySetup *print-rendering-intent\n"
- "*Defaultprint-rendering-intent: %s\n",
+ human_readable = cfCatalogLookUpOption("print-rendering-intent",
+ opt_strings_catalog,
+ printer_opt_strings_catalog);
+ cupsFilePrintf(fp, "*OpenUI *cupsRenderingIntent/%s: PickOne\n"
+ "*OrderDependency: 10 AnySetup *cupsRenderingIntent\n"
+ "*DefaultcupsRenderingIntent: %s\n",
(human_readable ? human_readable :
"Print Rendering Intent"),
ppdname);
for (i = 0; i < count; i ++) {
keyword = ippGetString(attr, i, NULL);
- human_readable = lookup_choice((char *)keyword,
- "print-rendering-intent",
- opt_strings_catalog,
- printer_opt_strings_catalog);
- cupsFilePrintf(fp, "*print-rendering-intent %s%s%s: \"\"\n",
+ human_readable = cfCatalogLookUpChoice((char *)keyword,
+ "print-rendering-intent",
+ opt_strings_catalog,
+ printer_opt_strings_catalog);
+ cupsFilePrintf(fp, "*cupsRenderingIntent %s%s%s: \"<</cupsRenderingIntent (%s)>>setpagedevice\"\n",
keyword,
(human_readable ? "/" : ""),
- (human_readable ? human_readable : ""));
+ (human_readable ? human_readable : ""),
+ keyword);
}
- cupsFilePuts(fp, "*CloseUI: *print-rendering-intent\n");
+ cupsFilePuts(fp, "*CloseUI: *cupsRenderingIntent\n");
}
/*
if ((attr = ippFindAttribute(response, "print-scaling-supported",
IPP_TAG_ZERO)) != NULL &&
(count = ippGetCount(attr)) > 1) {
- human_readable = lookup_option("print-scaling", opt_strings_catalog,
- printer_opt_strings_catalog);
+ human_readable = cfCatalogLookUpOption("print-scaling",
+ opt_strings_catalog,
+ printer_opt_strings_catalog);
cupsFilePrintf(fp, "*OpenUI *print-scaling/%s: PickOne\n"
"*OrderDependency: 10 AnySetup *print-scaling\n"
"*Defaultprint-scaling: %s\n",
for (i = 0; i < count; i ++) {
keyword = ippGetString(attr, i, NULL);
- human_readable = lookup_choice((char *)keyword, "print-scaling",
- opt_strings_catalog,
- printer_opt_strings_catalog);
+ human_readable = cfCatalogLookUpChoice((char *)keyword, "print-scaling",
+ opt_strings_catalog,
+ printer_opt_strings_catalog);
cupsFilePrintf(fp, "*print-scaling %s%s%s: \"\"\n",
keyword,
(human_readable ? "/" : ""),
*/
if (is_fax) {
- human_readable = lookup_option("Phone", opt_strings_catalog,
- printer_opt_strings_catalog);
+ human_readable = cfCatalogLookUpOption("Phone", opt_strings_catalog,
+ printer_opt_strings_catalog);
cupsFilePrintf(fp, "*OpenUI *phone/%s: PickOne\n"
"*OrderDependency: 10 AnySetup *phone\n"
cupsFilePrintf(fp,"*Customphone True: \"\"\n"
"*ParamCustomphone Text: 1 string 0 64\n");
- human_readable = lookup_option("faxPrefix", opt_strings_catalog,
- printer_opt_strings_catalog);
+ human_readable = cfCatalogLookUpOption("faxPrefix", opt_strings_catalog,
+ printer_opt_strings_catalog);
cupsFilePrintf(fp, "*OpenUI *faxPrefix/%s: PickOne\n"
"*OrderDependency: 10 AnySetup *faxPrefix\n"
if (!preset || !preset_name)
continue;
- if ((localized_name = lookup_option((char *)preset_name,
- opt_strings_catalog,
- printer_opt_strings_catalog)) == NULL)
+ if ((localized_name =
+ cfCatalogLookUpOption((char *)preset_name,
+ opt_strings_catalog,
+ printer_opt_strings_catalog)) == NULL)
cupsFilePrintf(fp, "*APPrinterPreset %s: \"\n", preset_name);
else
cupsFilePrintf(fp, "*APPrinterPreset %s/%s: \"\n", preset_name,
(is_fax ? "Fax " : ""));
cupsFileClose(fp);
+ if (opt_strings_catalog)
+ cupsArrayDelete(opt_strings_catalog);
if (printer_opt_strings_catalog)
cupsArrayDelete(printer_opt_strings_catalog);
return (NULL);
}
-
-#endif /* HAVE_CUPS_1_6 */
#include "ppd.h"
#include "debug-internal.h"
+#include <ctype.h>
+#include <errno.h>
/*
static ipp_t *create_media_col(const char *media, const char *source, const char *type, int width, int length, int bottom, int left, int right, int top);
static ipp_t *create_media_size(int width, int length);
+static ipp_t *create_media_size_ranges(int min_width, int min_length, int max_width, int max_length);
/*
*/
ipp_t * /* O - IPP attributes or `NULL`
- on error */
+ on error */
ppdLoadAttributes(
- ppd_file_t *ppd, /* I - PPD file data */
- cups_array_t *docformats) /* I - document-format-supported
- values */
+ ppd_file_t *ppd) /* I - PPD file data */
{
int i, j; /* Looping vars */
+ char *ptr;
+ cups_array_t *docformats; /* document-format-supported
+ values */
ipp_t *attrs; /* Attributes */
ipp_attribute_t *attr; /* Current attribute */
+ ipp_attribute_t *aux_attr; /* Auxiliary attribute */
ipp_t *col; /* Current collection value */
ppd_attr_t *ppd_attr; /* PPD attribute */
+ ppd_option_t *ppd_option; /* PPD option */
ppd_choice_t *ppd_choice; /* PPD choice */
ppd_size_t *ppd_size; /* Default PPD size */
pwg_size_t *pwg_size, /* Current PWG size */
*default_size = NULL; /* Default PWG size */
const char *default_source = NULL, /* Default media source */
- *default_type = NULL; /* Default media type */
+ *default_type = NULL, /* Default media type */
+ *default_output_bin = NULL, /* Default output bin */
+ *default_output_order = NULL; /* Default output order */
pwg_map_t *pwg_map; /* Mapping from PWG to PPD keywords */
ppd_cache_t *pc; /* PPD cache */
ppd_pwg_finishings_t *finishings; /* Current finishings value */
int margins[10]; /* media-xxx-margin-supported values */
int xres, /* Default horizontal resolution */
yres; /* Default vertical resolution */
- int num_urf; /* Number of urf-supported values */
- const char *urf[10]; /* urf-supported values */
- char urf_rs[32]; /* RS value */
+ int urf_supported_found;
+ int pwg_raster_found;
+ int is_texttotext;
+ int num_items; /* Number of IPP attribute values */
+ const char *items[20]; /* IPP attribute values */
+ char item_buf[64]; /* RS value */
+ int res_x[20], res_y[20], int_item[20];
+ char *val,
+ *def_output_bin = NULL,
+ buf[1024];
+ int def_found,
+ order,
+ face_up;
static const int orientation_requested_supported[4] =
{ /* orientation-requested-supported values */
IPP_ORIENT_PORTRAIT,
if (ppd == NULL)
return (NULL);
- ppdMarkDefaults(ppd);
-
if (ppd->cache == NULL)
{
if ((pc = ppdCacheCreateWithPPD(ppd)) != NULL)
if ((ppd_choice = ppdFindMarkedChoice(ppd, "MediaType")) != NULL)
default_type = ppdCacheGetType(pc, ppd_choice->choice);
+ if ((ppd_choice = ppdFindMarkedChoice(ppd, "OutputOrder")) != NULL)
+ default_output_order = ppd_choice->choice;
+ if ((ppd_choice = ppdFindMarkedChoice(ppd, "OutputBin")) != NULL)
+ {
+ default_output_bin = ppd_choice->choice;
+ if (default_output_order == NULL &&
+ (ppd_attr = ppdFindAttr(ppd, "PageStackOrder",
+ ppd_choice->choice)) != NULL)
+ default_output_order = ppd_attr->value;
+ }
+ if (default_output_order == NULL &&
+ (ppd_attr = ppdFindAttr(ppd, "DefaultOutputOrder", 0)) != NULL)
+ default_output_order = ppd_attr->value;
+ if (default_output_order == NULL)
+ default_output_order = "Normal";
+
if ((ppd_attr = ppdFindAttr(ppd, "DefaultResolution", NULL)) != NULL)
{
/*
xres = yres = 300;
}
- snprintf(urf_rs, sizeof(urf_rs), "RS%d", yres < xres ? yres : xres);
-
- num_urf = 0;
- urf[num_urf ++] = "V1.4";
- urf[num_urf ++] = "CP1";
- urf[num_urf ++] = urf_rs;
- urf[num_urf ++] = "W8";
- if (pc->sides_2sided_long)
- urf[num_urf ++] = "DM1";
- if (ppd->color_device)
- urf[num_urf ++] = "SRGB24";
-
/*
- * PostScript printers accept PDF via one of the CUPS PDF to PostScript
- * filters, along with PostScript (of course) and JPEG...
+ * Data formats which the printer understands, if the PPD specifies
+ * a driver in a "*cupsFilter(2): ..." line, we add the input format
+ * of the driver, as this is what our filter need to produce.
*/
- cupsArrayAdd(docformats, "application/pdf");
- cupsArrayAdd(docformats, "application/postscript");
- cupsArrayAdd(docformats, "image/jpeg");
+ docformats = cupsArrayNew3((cups_array_func_t)strcmp, NULL, NULL, 0, NULL,
+ (cups_afree_func_t)free);
+ is_texttotext = 0;
+ if (ppd->num_filters)
+ {
+ char *filter;
+ for (filter = (char *)cupsArrayFirst(pc->filters);
+ filter;
+ filter = (char *)cupsArrayNext(pc->filters))
+ {
+ char buf[256];
+
+ /* String of the "*cupsfilter:" or "*cupsfilter2:" line */
+ strncpy(buf, filter, sizeof(buf) - 1);
+
+ /* Is the PPD file using the "texttotext" filter? */
+ if (strcmp(buf + strlen(buf) - 10, "texttotext") == 0)
+ is_texttotext = 1;
+
+ /* Separate the first word */
+ ptr = buf;
+ while (*ptr && !isspace(*ptr)) ptr ++;
+ if (*ptr)
+ *ptr = '\0';
+
+ /* Add it to the list of output formats */
+ cupsArrayAdd(docformats, strdup(buf));
+ }
+ }
+ else
+ cupsArrayAdd(docformats, strdup("application/vnd.cups-postscript"));
/*
* Create the attributes...
attrs = ippNew();
+ /*
+ * Properties of supported Raster formats: Convert from strings
+ * in the PPD files (from driverless PPD auto-generator) into
+ * printer IPP attributes
+ */
+
+ urf_supported_found = 0;
+ pwg_raster_found = 0;
+ for (i = 0; i < ppd->num_attrs; i ++)
+ {
+ ppd_attr = ppd->attrs[i];
+ if ((cupsArrayFind(docformats, (void *)"image/urf") &&
+ strcasecmp(ppd_attr->name, "cupsUrfSupported") == 0) ||
+ (cupsArrayFind(docformats, (void *)"image/pwg-raster") &&
+ strncasecmp(ppd_attr->name, "cupsPwgRaster", 13) == 0) ||
+ (cupsArrayFind(docformats, (void *)"application/PCLm") &&
+ strncasecmp(ppd_attr->name, "cupsPclm", 8) == 0))
+ {
+ /* Convert PPD-style names into IPP-style names */
+ ppdPwgUnppdizeName(ppd_attr->name + 4, item_buf, sizeof(item_buf), NULL);
+ if (strcasecmp(item_buf, "urf-supported") == 0)
+ /* Explicit urf-supported string in the PPD, so we do not need to
+ generate one later */
+ urf_supported_found = 1;
+ if (strncasecmp(item_buf, "pwg-raster-", 11) == 0)
+ /* Explicit pwg-raster-... attributes in the PPD, so we do not need to
+ generate them later */
+ pwg_raster_found = 1;
+ /* Make array from comma-separated list */
+ strncpy(buf, ppd_attr->value, sizeof(buf) - 1);
+ num_items = 0;
+ char *p = buf;
+ do
+ {
+ items[num_items ++] = p;
+ if ((p = strchr(p, ',')) != NULL)
+ {
+ *p = '\0';
+ p ++;
+ }
+ }
+ while (p);
+ if (strlen(items[0]) > 3 &&
+ strncasecmp(items[0] + strlen(items[0]) - 3, "dpi", 3) == 0 &&
+ isdigit(*(items[0] + strlen(items[0]) - 4)))
+ {
+ /* Resolutions */
+ for (j = 0; j < num_items; j ++)
+ if (sscanf(items[j], "%dx%d", &res_x[j], &res_y[j]) == 1)
+ res_y[j] = res_x[j];
+ ippAddResolutions(attrs, IPP_TAG_PRINTER, item_buf, num_items, IPP_RES_PER_INCH, res_x, res_y);
+ }
+ else if (strlen(items[0]) > 0 &&
+ ((int)(strtol(items[0], &p, 10) * 0) || (errno == 0 && *p == '\0')))
+ {
+ /* Integer number(s) */
+ for (j = 0; j < num_items; j ++)
+ int_item[j] = (int)strtol(items[j], NULL, 10);
+ ippAddIntegers(attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, item_buf, num_items, int_item);
+ }
+ else
+ /* General */
+ ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, item_buf, num_items, NULL, items);
+ }
+ }
+
+ /*
+ * Generate urf-supported entry for the printer IPP attributes, if there
+ * is no such entry in the PPD file (from driverless PPD auto-generator
+ */
+
+ if (urf_supported_found == 0 &&
+ cupsArrayFind(docformats, (void *)"image/urf"))
+ {
+ snprintf(item_buf, sizeof(item_buf), "RS%d", yres < xres ? yres : xres);
+
+ num_items = 0;
+ items[num_items ++] = "V1.4";
+ items[num_items ++] = "CP1";
+ items[num_items ++] = item_buf;
+ items[num_items ++] = "W8";
+ if (pc->sides_2sided_long)
+ items[num_items ++] = "DM1";
+ if (ppd->color_device)
+ items[num_items ++] = "SRGB24";
+
+ /* urf-supported IPP attribute */
+ ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "urf-supported", num_items, NULL, items);
+ }
+
+ /*
+ * Generate pwg-raster-document-xxx-supported entries for the printer
+ * IPP attributes, if there is no such entry in the PPD file (from
+ * driverless PPD auto-generator
+ */
+
+ if (pwg_raster_found == 0 &&
+ cupsArrayFind(docformats, (void *)"image/pwg-raster"))
+ {
+ ippAddResolution(attrs, IPP_TAG_PRINTER, "pwg-raster-document-resolution-supported", IPP_RES_PER_INCH, xres, yres);
+
+ if (pc->sides_2sided_long)
+ ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "pwg-raster-document-sheet-back", NULL, "normal");
+
+ if (ppd->color_device)
+ ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "pwg-raster-document-type-supported", (int)(sizeof(pwg_raster_document_type_supported_color) / sizeof(pwg_raster_document_type_supported_color[0])), NULL, pwg_raster_document_type_supported_color);
+ else
+ ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "pwg-raster-document-type-supported", (int)(sizeof(pwg_raster_document_type_supported) / sizeof(pwg_raster_document_type_supported[0])), NULL, pwg_raster_document_type_supported);
+ }
+
+ /* Fax out PPD? */
+ if (((ppd_attr = ppdFindAttr(ppd, "cupsFax", NULL)) != NULL &&
+ strcasecmp(ppd_attr->value, "True") == 0) ||
+ ((ppd_attr = ppdFindAttr(ppd, "cupsIPPFaxOut", NULL)) != NULL &&
+ strcasecmp(ppd_attr->value, "True") == 0))
+ {
+ ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "ipp-features-supported", NULL, "faxout");
+ ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_URI), "printer-uri-supported", NULL, "ipp://localhost/ipp/faxout");
+ }
+
/* color-supported */
ippAddBoolean(attrs, IPP_TAG_PRINTER, "color-supported", (char)ppd->color_device);
/* copies-default */
- ippAddInteger(attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "copies-default", 1);
+ if (((ppd_choice = ppdFindMarkedChoice(ppd, "Copies")) == NULL ||
+ (i = atoi(ppd_choice->choice)) <= 0) &&
+ ((ppd_attr = ppdFindAttr(ppd, "DefaultCopies", NULL)) == NULL ||
+ (i = atoi(ppd_attr->value)) <= 0))
+ i = 1;
+ ippAddInteger(attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "copies-default", i);
/* copies-supported */
- ippAddRange(attrs, IPP_TAG_PRINTER, "copies-supported", 1, 999);
+ ippAddRange(attrs, IPP_TAG_PRINTER, "copies-supported", 1,
+ pc->max_copies > 0 ? pc->max_copies : 999);
+
+ /* document-format-supported */
+ attr = ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "document-format-supported", cupsArrayCount(docformats), NULL, NULL);
+ for (ptr = (char *)cupsArrayFirst(docformats), i = 0; ptr;
+ ptr = (char *)cupsArrayNext(docformats), i ++)
+ ippSetString(attrs, &attr, i, ptr);
/* document-password-supported */
ippAddInteger(attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "document-password-supported", 127);
ippAddIntegers(attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-bottom-margin-supported", num_margins, margins);
- /* media-col-database */
+ /* landscape-orientation-requested-preferred */
+ if (ppd->landscape < 0) /* Direction the printer rotates landscape
+ (-90) */
+ {
+ /* Rotate clockwise (reverse landscape)*/
+ ippAddInteger(attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "landscape-orientation-requested-preferred", 5);
+ }
+ else if (ppd->landscape > 0) /* (+90) */
+ {
+ /* Rotate counter-clockwise (landscape) */
+ ippAddInteger(attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "landscape-orientation-requested-preferred", 4);
+ }
+
+ /* media-col-database and media-col-default */
attr = ippAddCollections(attrs, IPP_TAG_PRINTER, "media-col-database", pc->num_sizes, NULL);
for (i = 0, pwg_size = pc->sizes; i < pc->num_sizes; i ++, pwg_size ++)
{
- col = create_media_col(pwg_size->map.pwg, NULL, NULL, pwg_size->width, pwg_size->length, pwg_size->bottom, pwg_size->left, pwg_size->right, pwg_size->top);
+ if ((ptr = strchr(pwg_size->map.ppd, '.')) != NULL)
+ {
+ /* Page size variant, use original size's PWG name but PPD's
+ dimensions and margins.
+
+ This way we can associate extra size for overspraying when
+ printing borderless with the original page size, for example
+ for cfFilterPWGToRaster() to correct original-sized PWG
+ Raster to overspray-sized CUPS Raster (for HPLIP for
+ example). Filters can also switch to overspray size if the
+ original size plus zero margins is requested for a job */
+ pwg_size_t *size;
+ memmove(buf, pwg_size->map.ppd, ptr - pwg_size->map.ppd);
+ buf[ptr - pwg_size->map.ppd] = '\0';
+ for (j = 0, size = pc->sizes; j < pc->num_sizes; j ++, size ++)
+ /* Find entry of original size */
+ if (strcasecmp(buf, size->map.ppd) == 0)
+ {
+ ptr = size->map.pwg;
+ break;
+ }
+ if (j == pc->num_sizes)
+ ptr = pwg_size->map.pwg;
+ }
+ else
+ ptr = pwg_size->map.pwg;
+ col = create_media_col(ptr, NULL, NULL, pwg_size->width, pwg_size->length, pwg_size->bottom, pwg_size->left, pwg_size->right, pwg_size->top);
+ if (is_texttotext)
+ {
+ /* Add info about the number of lines and number of columns defined in
+ the PPD for each page size to the appropriate media-col-database
+ entries */
+ snprintf(buf, sizeof(buf), "%sNumColumns", pwg_size->map.ppd);
+ if ((ppd_choice = ppdFindMarkedChoice(ppd, buf)) != NULL &&
+ (j = atoi(ppd_choice->choice)) > 0)
+ ippAddInteger(col, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "num-columns", j);
+ snprintf(buf, sizeof(buf), "%sNumLines", pwg_size->map.ppd);
+ if ((ppd_choice = ppdFindMarkedChoice(ppd, buf)) != NULL &&
+ (j = atoi(ppd_choice->choice)) > 0)
+ ippAddInteger(col, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "num-lines", j);
+ }
ippSetCollection(attrs, &attr, i, col);
ippDelete(col);
+ if (pwg_size == default_size)
+ {
+ /* media-col-default */
+ col = create_media_col(ptr, default_source, default_type, pwg_size->width, pwg_size->length, pwg_size->bottom, pwg_size->left, pwg_size->right, pwg_size->top);
+ ippAddCollection(attrs, IPP_TAG_PRINTER, "media-col-default", col);
+ ippDelete(col);
+ }
}
- /* media-col-default */
- col = create_media_col(default_size->map.pwg, default_source, default_type, default_size->width, default_size->length, default_size->bottom, default_size->left, default_size->right, default_size->top);
- ippAddCollection(attrs, IPP_TAG_PRINTER, "media-col-default", col);
- ippDelete(col);
-
/* media-col-ready */
col = create_media_col(default_size->map.pwg, default_source, default_type, default_size->width, default_size->length, default_size->bottom, default_size->left, default_size->right, default_size->top);
ippAddCollection(attrs, IPP_TAG_PRINTER, "media-col-ready", col);
ippSetString(attrs, &attr, i, pwg_size->map.pwg);
/* media-size-supported */
- attr = ippAddCollections(attrs, IPP_TAG_PRINTER, "media-size-supported", pc->num_sizes, NULL);
+ attr = ippAddCollections(attrs, IPP_TAG_PRINTER, "media-size-supported", pc->num_sizes + (ppd->variable_sizes ? 1 : 0), NULL);
for (i = 0, pwg_size = pc->sizes; i < pc->num_sizes; i ++, pwg_size ++)
{
col = create_media_size(pwg_size->width, pwg_size->length);
ippSetCollection(attrs, &attr, i, col);
ippDelete(col);
}
+ if (ppd->variable_sizes)
+ {
+ col = create_media_size_ranges(pc->custom_min_width, pc->custom_min_length,
+ pc->custom_max_width, pc->custom_max_length);
+ ippSetCollection(attrs, &attr, pc->num_sizes, col);
+ ippDelete(col);
+ }
/* media-source-supported */
if (pc->num_sources > 0)
/* orientation-requested-supported */
ippAddIntegers(attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "orientation-requested-supported", (int)(sizeof(orientation_requested_supported) / sizeof(orientation_requested_supported[0])), orientation_requested_supported);
- /* output-bin-default */
- if (pc->num_bins > 0)
- ippAddString(attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "output-bin-default", NULL, pc->bins->pwg);
- else
- ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "output-bin-default", NULL, "face-down");
-
- /* output-bin-supported */
+ /* output-bin-supported and output-bin-default */
+ def_found = 0;
if (pc->num_bins > 0)
{
attr = ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "output-bin-supported", pc->num_bins, NULL, NULL);
for (i = 0, pwg_map = pc->bins; i < pc->num_bins; i ++, pwg_map ++)
+ {
ippSetString(attrs, &attr, i, pwg_map->pwg);
+ if (default_output_bin && !strcmp(pwg_map->ppd, default_output_bin))
+ {
+ def_output_bin = pwg_map->pwg;
+ def_found = 1;
+ }
+ if ((ppd_attr = ppdFindAttr(ppd, "PageStackOrder",
+ pwg_map->ppd)) != NULL)
+ val = ppd_attr->value;
+ else
+ val = NULL;
+ order = (val && strcasecmp(val, "Normal") == 0 ? 1 :
+ (val && strcasecmp(val, "Reverse") == 0 ? -1 : 0));
+ if (i == 0 ||
+ (!def_found && ((order == 1 &&
+ strcasecmp(default_output_order, "Normal")) ||
+ (order == -1 &&
+ strcasecmp(default_output_order, "Reverse")))))
+ def_output_bin = pwg_map->pwg;
+ face_up = (((strcasestr(pwg_map->pwg, "face") &&
+ strcasestr(pwg_map->pwg, "up")) ||
+ (strcasestr(pwg_map->ppd, "face") &&
+ strcasestr(pwg_map->ppd, "up"))) ? 1 :
+ (((strcasestr(pwg_map->pwg, "face") &&
+ strcasestr(pwg_map->pwg, "down")) ||
+ (strcasestr(pwg_map->ppd, "face") &&
+ strcasestr(pwg_map->ppd, "down"))) ? -1 : 0));
+ if (order == 0)
+ {
+ if (face_up != 0)
+ order = -face_up;
+ else
+ order = (strcasecmp(default_output_order, "Normal") == 0 ? 1 :
+ (strcasecmp(default_output_order, "Reverse") == 0 ? -1 : 0));
+ }
+ if (face_up == 0 && order != 0)
+ face_up = -order;
+ snprintf(buf, sizeof(buf), "type=unknown;maxcapacity=-2;remaining=-2;status=5;stackingorder=%s;pagedelivery=%s;name=%s",
+ (order == -1 ? "lastToFirst" :
+ (order == 1 ? "firstToLast" :
+ "unknown")),
+ (face_up == -1 ? "faceDown" :
+ (face_up == -1 ? "faceUp" :
+ "unknown")),
+ pwg_map->ppd);
+ if (i == 0)
+ aux_attr = ippAddOctetString(attrs, IPP_TAG_PRINTER,
+ "printer-output-tray", buf, strlen(buf));
+ else
+ ippSetOctetString(attrs, &aux_attr, i, buf, strlen(buf));
+ }
}
else
{
- ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "output-bin-supported", NULL, "face-down");
+ order = (strcasecmp(default_output_order, "Normal") == 0 ? 1 :
+ (strcasecmp(default_output_order, "Reverse") == 0 ? -1 : 1));
+ def_output_bin = (order == 1 ? "face-down" : "face-up");
+ ippAddString(attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "output-bin-supported", NULL, def_output_bin);
+ snprintf(buf, sizeof(buf), "type=unknown;maxcapacity=-2;remaining=-2;status=5;stackingorder=%s;pagedelivery=%s;name=%s",
+ (order == -1 ? "lastToFirst" : "firstToLast"),
+ (order == -1 ? "faceUp" : "faceDown"),
+ def_output_bin);
+ ippAddOctetString(attrs, IPP_TAG_PRINTER,
+ "printer-output-tray", buf, strlen(buf));
}
+ ippAddString(attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "output-bin-default", NULL, def_output_bin);
/* overrides-supported */
ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "overrides-supported", (int)(sizeof(overrides_supported) / sizeof(overrides_supported[0])), NULL, overrides_supported);
ippAddInteger(attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "pages-per-minute-color", ppd->throughput);
/* print-color-mode-default */
- ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "print-color-mode-default", NULL, ppd->color_device ? "auto" : "monochrome");
+ bool mono =
+ (ppd->color_device &&
+ (((ppd_choice = ppdFindMarkedChoice(ppd, "ColorModel")) != NULL &&
+ (strcasestr(ppd_choice->choice, "mono") ||
+ strcasestr(ppd_choice->choice, "gray") ||
+ strcasestr(ppd_choice->choice, "bw") ||
+ strcasestr(ppd_choice->choice, "bi-level") ||
+ strcasestr(ppd_choice->choice, "bi_level"))) ||
+ ((ppd_choice = ppdFindMarkedChoice(ppd, "OutputMode")) != NULL &&
+ (strcasestr(ppd_choice->choice, "mono") ||
+ strcasestr(ppd_choice->choice, "gray") ||
+ strcasestr(ppd_choice->choice, "bw") ||
+ strcasestr(ppd_choice->choice, "bi-level") ||
+ strcasestr(ppd_choice->choice, "bi_level")))));
+ ippAddString(attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "print-color-mode-default", NULL, ppd->color_device && !mono ? "auto" : "monochrome");
/* print-color-mode-supported */
if (ppd->color_device)
ippAddIntegers(attrs, IPP_TAG_PRINTER, IPP_TAG_ENUM, "print-quality-supported", (int)(sizeof(print_quality_supported) / sizeof(print_quality_supported[0])), print_quality_supported);
/* print-rendering-intent-default */
- ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "print-rendering-intent-default", NULL, "auto");
+ if ((ppd_choice =
+ ppdFindMarkedChoice(ppd, "cupsRenderingIntent")) != NULL ||
+ (ppd_choice =
+ ppdFindMarkedChoice(ppd, "print-rendering-intent")) != NULL)
+ ippAddString(attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "print-rendering-intent-default", NULL, ppd_choice->choice);
+ else
+ ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "print-rendering-intent-default", NULL, "auto");
/* print-rendering-intent-supported */
- ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "print-rendering-intent-supported", NULL, "auto");
+ if (((ppd_option = ppdFindOption(ppd, "cupsRenderingIntent")) != NULL ||
+ (ppd_option = ppdFindOption(ppd, "print-rendering-intent")) != NULL) &&
+ ppd_option->num_choices > 0)
+ {
+ for (i = 0; i < ppd_option->num_choices && i < sizeof(items); i ++)
+ items[i] = ppd_option->choices[i].choice;
+ ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "print-rendering-intent-supported", i, NULL, items);
+ }
+ else
+ ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "print-rendering-intent-supported", NULL, "auto");
/* printer-device-id */
if ((ppd_attr = ppdFindAttr(ppd, "1284DeviceId", NULL)) != NULL)
char device_id[1024]; /* Device ID string */
+ //XXX TODO: CMD:
snprintf(device_id, sizeof(device_id), "MFG:%s;MDL:%s;CMD:PS;", ppd->manufacturer, ppd->modelname);
ippAddString(attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-device-id", NULL, device_id);
}
+ /* printer-info */
+ ippAddString(attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-info", NULL, ppd->nickname);
+
/* printer-input-tray */
if (pc->num_sources > 0)
{
}
/* printer-make-and-model */
+ // XXX TODO: Rip off driver info
ippAddString(attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT, "printer-make-and-model", NULL, ppd->nickname);
/* printer-resolution-default */
ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_TEXT), "printer-supply-description", (int)(sizeof(printer_supply_description) / sizeof(printer_supply_description[0])), NULL, printer_supply_description);
}
- /* pwg-raster-document-xxx-supported */
- if (cupsArrayFind(docformats, (void *)"image/pwg-raster"))
- {
- ippAddResolution(attrs, IPP_TAG_PRINTER, "pwg-raster-document-resolution-supported", IPP_RES_PER_INCH, xres, yres);
-
- if (pc->sides_2sided_long)
- ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "pwg-raster-document-sheet-back", NULL, "normal");
-
- if (ppd->color_device)
- ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "pwg-raster-document-type-supported", (int)(sizeof(pwg_raster_document_type_supported_color) / sizeof(pwg_raster_document_type_supported_color[0])), NULL, pwg_raster_document_type_supported_color);
- else
- ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "pwg-raster-document-type-supported", (int)(sizeof(pwg_raster_document_type_supported) / sizeof(pwg_raster_document_type_supported[0])), NULL, pwg_raster_document_type_supported);
- }
-
/* sides-default */
- ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "sides-default", NULL, "one-sided");
+ if (pc->sides_option && pc->sides_2sided_long &&
+ ppdIsMarked(ppd, pc->sides_option, pc->sides_2sided_long))
+ ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "sides-default", NULL, "two-sided-long-edge");
+ else if (pc->sides_option && pc->sides_2sided_short &&
+ ppdIsMarked(ppd, pc->sides_option, pc->sides_2sided_short))
+ ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "sides-default", NULL, "two-sided-long-short");
+ else
+ ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "sides-default", NULL, "one-sided");
/* sides-supported */
- if (pc->sides_2sided_long)
+ if (pc->sides_option && pc->sides_2sided_long)
ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "sides-supported", (int)(sizeof(sides_supported) / sizeof(sides_supported[0])), NULL, sides_supported);
else
ippAddString(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "sides-supported", NULL, "one-sided");
- /* urf-supported */
- if (cupsArrayFind(docformats, (void *)"image/urf"))
- ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "urf-supported", num_urf, NULL, urf);
+ /* Extra attributes for "texttotext" filter */
+ if (is_texttotext)
+ {
+ if ((ppd_choice = ppdFindMarkedChoice(ppd, "OverLongLines")) != NULL &&
+ ppd_choice->choice && ppd_choice->choice[0])
+ {
+ ppdPwgUnppdizeName(ppd_choice->choice, buf, sizeof(buf), NULL);
+ ippAddString(attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "over-long-lines-default", NULL, buf);
+ }
+
+ if ((ppd_choice = ppdFindMarkedChoice(ppd, "TabWidth")) != NULL &&
+ (i = atoi(ppd_choice->choice)) > 0)
+ ippAddInteger(attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "tab-width-default", i);
+ if ((ppd_choice = ppdFindMarkedChoice(ppd, "Pagination")) != NULL &&
+ ppd_choice->choice && ppd_choice->choice[0])
+ {
+ ppdPwgUnppdizeName(ppd_choice->choice, buf, sizeof(buf), NULL);
+ ippAddString(attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "pagination-default", NULL, buf);
+ }
+
+ if ((ppd_choice = ppdFindMarkedChoice(ppd, "page-left")) != NULL &&
+ (i = atoi(ppd_choice->choice)) > 0)
+ ippAddInteger(attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "page-left-default", i);
+
+ if ((ppd_choice = ppdFindMarkedChoice(ppd, "page-right")) != NULL &&
+ (i = atoi(ppd_choice->choice)) > 0)
+ ippAddInteger(attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "page-right-default", i);
+
+ if ((ppd_choice = ppdFindMarkedChoice(ppd, "page-top")) != NULL &&
+ (i = atoi(ppd_choice->choice)) > 0)
+ ippAddInteger(attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "page-top-default", i);
+
+ if ((ppd_choice = ppdFindMarkedChoice(ppd, "page-bottom")) != NULL &&
+ (i = atoi(ppd_choice->choice)) > 0)
+ ippAddInteger(attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER,
+ "page-bottom-default", i);
+
+ if ((ppd_choice = ppdFindMarkedChoice(ppd, "PrinterEncoding")) != NULL &&
+ ppd_choice->choice && ppd_choice->choice[0])
+ ippAddString(attrs, IPP_TAG_PRINTER, IPP_TAG_TEXT,
+ "printer-encoding-default", NULL, ppd_choice->choice);
+
+ if ((ppd_choice = ppdFindMarkedChoice(ppd, "NewlineCharacters")) != NULL &&
+ ppd_choice->choice && ppd_choice->choice[0])
+ {
+ ppdPwgUnppdizeName(ppd_choice->choice, buf, sizeof(buf), NULL);
+ ippAddString(attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "newline-characters-default", NULL, buf);
+ }
+
+ if ((ppd_choice = ppdFindMarkedChoice(ppd, "SendFF")) != NULL &&
+ ppd_choice->choice && ppd_choice->choice[0])
+ {
+ ppdPwgUnppdizeName(ppd_choice->choice, buf, sizeof(buf), NULL);
+ ippAddString(attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD,
+ "send-ff-default", NULL, buf);
+ }
+
+ }
+
+ /* Clean up */
+ cupsArrayDelete(docformats);
return (attrs);
}
return (media_size);
}
+
+
+/*
+ * 'create_media_size_range()' - Create a media-size range for custom sizes.
+ */
+
+static ipp_t * /* O - media-col collection */
+create_media_size_ranges(int min_width, /* I - min x dim in 2540ths */
+ int min_length, /* I - nin y dim in 2540ths */
+ int max_width, /* I - max x dim in 2540ths */
+ int max_length) /* I - max y dim in 2540ths */
+{
+ ipp_t *media_size_ranges = ippNew(); /* media-size value */
+
+ ippAddRange(media_size_ranges, IPP_TAG_PRINTER, "x-dimension", min_width, max_width);
+ ippAddRange(media_size_ranges, IPP_TAG_PRINTER, "y-dimension", min_length, max_length);
+
+ return (media_size_ranges);
+}
--- /dev/null
+/*
+ * PPD color profile attribute lookup functions for libppd.
+ *
+ * Copyright 2007-2011 by Apple Inc.
+ * Copyright 1993-2005 by Easy Software Products.
+ *
+ * These coded instructions, statements, and computer programs are the
+ * property of Apple Inc. and are protected by Federal copyright
+ * law. Distribution and use rights are outlined in the file "COPYING"
+ * which should have been included with this file.
+ *
+ * Contents:
+ *
+ * ppdFindColorAttr() - Find a PPD attribute based on the colormodel,
+ * media, and resolution.
+ * ppdLutLoad() - Load a LUT from a PPD file.
+ * ppdRGBLoad() - Load a RGB color profile from a PPD file.
+ * ppdCMYKLoad() - Load a CMYK color profile from PPD attributes.
+ */
+
+/*
+ * Include necessary headers.
+ */
+
+#include <config.h>
+#include "ppd.h"
+#include <cupsfilters/filter.h>
+#include <cupsfilters/driver.h>
+#include <string.h>
+#include <ctype.h>
+
+
+/*
+ * 'ppdFindColorAttr()' - Find a PPD attribute based on the colormodel,
+ * media, and resolution.
+ */
+
+ppd_attr_t * /* O - Matching attribute or
+ NULL */
+ppdFindColorAttr(ppd_file_t *ppd, /* I - PPD file */
+ const char *name, /* I - Attribute name */
+ const char *colormodel, /* I - Color model */
+ const char *media, /* I - Media type */
+ const char *resolution, /* I - Resolution */
+ char *spec, /* O - Final selection string */
+ int specsize, /* I - Size of string buffer */
+ cf_logfunc_t log, /* I - Log function */
+ void *ld) /* I - Log function data */
+{
+ ppd_attr_t *attr; /* Attribute */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!ppd || !name || !colormodel || !media || !resolution || !spec ||
+ specsize < IPP_MAX_NAME)
+ return (NULL);
+
+ /*
+ * Look for the attribute with the following keywords:
+ *
+ * ColorModel.MediaType.Resolution
+ * ColorModel.Resolution
+ * ColorModel
+ * MediaType.Resolution
+ * MediaType
+ * Resolution
+ * ""
+ */
+
+ snprintf(spec, specsize, "%s.%s.%s", colormodel, media, resolution);
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "Looking for \"*%s %s\"...", name, spec);
+ if ((attr = ppdFindAttr(ppd, name, spec)) != NULL && attr->value != NULL)
+ return (attr);
+
+ snprintf(spec, specsize, "%s.%s", colormodel, resolution);
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "Looking for \"*%s %s\"...", name, spec);
+ if ((attr = ppdFindAttr(ppd, name, spec)) != NULL && attr->value != NULL)
+ return (attr);
+
+ snprintf(spec, specsize, "%s", colormodel);
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "Looking for \"*%s %s\"...", name, spec);
+ if ((attr = ppdFindAttr(ppd, name, spec)) != NULL && attr->value != NULL)
+ return (attr);
+
+ snprintf(spec, specsize, "%s.%s", media, resolution);
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "Looking for \"*%s %s\"...", name, spec);
+ if ((attr = ppdFindAttr(ppd, name, spec)) != NULL && attr->value != NULL)
+ return (attr);
+
+ snprintf(spec, specsize, "%s", media);
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "Looking for \"*%s %s\"...", name, spec);
+ if ((attr = ppdFindAttr(ppd, name, spec)) != NULL && attr->value != NULL)
+ return (attr);
+
+ snprintf(spec, specsize, "%s", resolution);
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "Looking for \"*%s %s\"...", name, spec);
+ if ((attr = ppdFindAttr(ppd, name, spec)) != NULL && attr->value != NULL)
+ return (attr);
+
+ spec[0] = '\0';
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "Looking for \"*%s\"...", name);
+ if ((attr = ppdFindAttr(ppd, name, spec)) != NULL && attr->value != NULL)
+ return (attr);
+
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "No instance of \"*%s\" found...", name);
+
+ return (NULL);
+}
+
+
+/*
+ * 'ppdLutLoad()' - Load a LUT from a PPD file.
+ */
+
+cf_lut_t * /* O - New lookup table */
+ppdLutLoad(ppd_file_t *ppd, /* I - PPD file */
+ const char *colormodel, /* I - Color model */
+ const char *media, /* I - Media type */
+ const char *resolution, /* I - Resolution */
+ const char *ink, /* I - Ink name */
+ cf_logfunc_t log, /* I - Log function */
+ void *ld) /* I - Log function data */
+{
+ char name[PPD_MAX_NAME], /* Attribute name */
+ spec[PPD_MAX_NAME]; /* Attribute spec */
+ ppd_attr_t *attr; /* Attribute */
+ int nvals; /* Number of values */
+ float vals[4]; /* Values */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (!ppd || !colormodel || !media || !resolution || !ink)
+ return (NULL);
+
+ /*
+ * Try to find the LUT values...
+ */
+
+ snprintf(name, sizeof(name), "cups%sDither", ink);
+
+ if ((attr = ppdFindColorAttr(ppd, name, colormodel, media, resolution, spec,
+ sizeof(spec), log, ld)) == NULL)
+ attr = ppdFindColorAttr(ppd, "cupsAllDither", colormodel, media,
+ resolution, spec, sizeof(spec), log, ld);
+
+ if (!attr)
+ return (NULL);
+
+ vals[0] = 0.0;
+ vals[1] = 0.0;
+ vals[2] = 0.0;
+ vals[3] = 0.0;
+ nvals = sscanf(attr->value, "%f%f%f", vals + 1, vals + 2, vals + 3) + 1;
+
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "Loaded LUT %s from PPD with values [%.3f %.3f %.3f %.3f]",
+ name, vals[0], vals[1], vals[2], vals[3]);
+
+ return (cfLutNew(nvals, vals, log, ld));
+}
+
+
+/*
+ * 'ppdRGBLoad()' - Load a RGB color profile from a PPD file.
+ */
+
+cf_rgb_t * /* O - New color profile */
+ppdRGBLoad(ppd_file_t *ppd, /* I - PPD file */
+ const char *colormodel, /* I - Color model */
+ const char *media, /* I - Media type */
+ const char *resolution, /* I - Resolution */
+ cf_logfunc_t log, /* I - Log function */
+ void *ld) /* I - Log function data */
+{
+ int i, /* Looping var */
+ cube_size, /* Size of color lookup cube */
+ num_channels, /* Number of color channels */
+ num_samples; /* Number of color samples */
+ cf_sample_t *samples; /* Color samples */
+ float values[7]; /* Color sample values */
+ char spec[IPP_MAX_NAME]; /* Profile name */
+ ppd_attr_t *attr; /* Attribute from PPD file */
+ cf_rgb_t *rgbptr; /* RGB color profile */
+
+
+ /*
+ * Find the following attributes:
+ *
+ * cupsRGBProfile - Specifies the cube size, number of channels, and
+ * number of samples
+ * cupsRGBSample - Specifies an RGB to CMYK color sample
+ */
+
+ if ((attr = ppdFindColorAttr(ppd, "cupsRGBProfile", colormodel, media,
+ resolution, spec, sizeof(spec), log, ld)) == NULL)
+ {
+ if (log) log(ld, CF_LOGLEVEL_DEBUG,
+ "No cupsRGBProfile attribute found for the current settings!");
+ return (NULL);
+ }
+
+ if (!attr->value || sscanf(attr->value, "%d%d%d", &cube_size, &num_channels,
+ &num_samples) != 3)
+ {
+ if (log) log(ld, CF_LOGLEVEL_ERROR,
+ "Bad cupsRGBProfile attribute \'%s\'!",
+ attr->value ? attr->value : "(null)");
+ return (NULL);
+ }
+
+ if (cube_size < 2 || cube_size > 16 ||
+ num_channels < 1 || num_channels > CF_MAX_RGB ||
+ num_samples != (cube_size * cube_size * cube_size))
+ {
+ if (log) log(ld, CF_LOGLEVEL_ERROR,
+ "Bad cupsRGBProfile attribute \'%s\'!",
+ attr->value);
+ return (NULL);
+ }
+
+ /*
+ * Allocate memory for the samples and read them...
+ */
+
+ if ((samples = calloc(num_samples, sizeof(cf_sample_t))) == NULL)
+ {
+ if (log) log(ld, CF_LOGLEVEL_ERROR,
+ "Unable to allocate memory for RGB profile!");
+ return (NULL);
+ }
+
+ /*
+ * Read all of the samples...
+ */
+
+ for (i = 0; i < num_samples; i ++)
+ if ((attr = ppdFindNextAttr(ppd, "cupsRGBSample", spec)) == NULL)
+ break;
+ else if (!attr->value)
+ {
+ if (log) log(ld, CF_LOGLEVEL_ERROR,
+ "Bad cupsRGBSample value!");
+ break;
+ }
+ else if (sscanf(attr->value, "%f%f%f%f%f%f%f", values + 0,
+ values + 1, values + 2, values + 3, values + 4, values + 5,
+ values + 6) != (3 + num_channels))
+ {
+ if (log) log(ld, CF_LOGLEVEL_ERROR,
+ "Bad cupsRGBSample value!");
+ break;
+ }
+ else
+ {
+ samples[i].rgb[0] = (int)(255.0 * values[0] + 0.5);
+ samples[i].rgb[1] = (int)(255.0 * values[1] + 0.5);
+ samples[i].rgb[2] = (int)(255.0 * values[2] + 0.5);
+ samples[i].colors[0] = (int)(255.0 * values[3] + 0.5);
+ if (num_channels > 1)
+ samples[i].colors[1] = (int)(255.0 * values[4] + 0.5);
+ if (num_channels > 2)
+ samples[i].colors[2] = (int)(255.0 * values[5] + 0.5);
+ if (num_channels > 3)
+ samples[i].colors[3] = (int)(255.0 * values[6] + 0.5);
+ }
+
+ /*
+ * If everything went OK, create the color profile...
+ */
+
+ if (i == num_samples)
+ rgbptr = cfRGBNew(num_samples, samples, cube_size, num_channels);
+ else
+ rgbptr = NULL;
+
+ /*
+ * Free the temporary sample array and return...
+ */
+
+ free(samples);
+
+ return (rgbptr);
+}
+
+
+/*
+ * 'ppdCMYKLoad()' - Load a CMYK color profile from PPD attributes.
+ */
+
+cf_cmyk_t * /* O - CMYK color separation */
+ppdCMYKLoad(ppd_file_t *ppd, /* I - PPD file */
+ const char *colormodel, /* I - ColorModel value */
+ const char *media, /* I - MediaType value */
+ const char *resolution, /* I - Resolution value */
+ cf_logfunc_t log, /* I - Log function */
+ void *ld) /* I - Log function data */
+{
+ cf_cmyk_t *cmyk; /* CMYK color separation */
+ char spec[IPP_MAX_NAME]; /* Profile name */
+ ppd_attr_t *attr; /* Attribute from PPD file */
+ int num_channels; /* Number of color components */
+ float gamval, /* Gamma correction value */
+ density, /* Density value */
+ light, /* Light ink limit */
+ dark, /* Light ink cut-off */
+ lower, /* Start of black ink */
+ upper; /* End of color ink */
+ int num_xypoints; /* Number of X,Y points */
+ float xypoints[100 * 2], /* X,Y points */
+ *xyptr; /* Current X,Y point */
+
+
+ /*
+ * Range check input...
+ */
+
+ if (ppd == NULL || colormodel == NULL || resolution == NULL || media == NULL)
+ return (NULL);
+
+ /*
+ * Find the following attributes:
+ *
+ * cupsAllGamma - Set default curve using gamma + density
+ * cupsAllXY - Set default curve using XY points
+ * cupsBlackGamma - Set black curve using gamma + density
+ * cupsBlackGeneration - Set black generation
+ * cupsBlackLightDark - Set black light/dark transition
+ * cupsBlackXY - Set black curve using XY points
+ * cupsCyanGamma - Set cyan curve using gamma + density
+ * cupsCyanLightDark - Set cyan light/dark transition
+ * cupsCyanXY - Set cyan curve using XY points
+ * cupsInkChannels - Set number of color channels
+ * cupsInkLimit - Set total ink limit
+ * cupsLightBlackGamma - Set light black curve using gamma + density
+ * cupsLightBlackXY - Set light black curve using XY points
+ * cupsLightCyanGamma - Set light cyan curve using gamma + density
+ * cupsLightCyanXY - Set light cyan curve using XY points
+ * cupsLightMagentaGamma - Set light magenta curve using gamma + density
+ * cupsLightMagentaXY - Set light magenta curve using XY points
+ * cupsMagentaGamma - Set magenta curve using gamma + density
+ * cupsMagentaLightDark - Set magenta light/dark transition
+ * cupsMagentaXY - Set magenta curve using XY points
+ * cupsYellowGamma - Set yellow curve using gamma + density
+ * cupsYellowXY - Set yellow curve using XY points
+ *
+ * The only required attribute is cupsInkChannels.
+ *
+ * The *XY attributes have precedence over the *Gamma attributes, and
+ * the *Light* attributes have precedence over the corresponding
+ * *LightDark* attributes.
+ */
+
+ /*
+ * Get the required cupsInkChannels attribute...
+ */
+
+ if ((attr = ppdFindColorAttr(ppd, "cupsInkChannels", colormodel, media,
+ resolution, spec, sizeof(spec), log, ld)) == NULL)
+ return (NULL);
+
+ num_channels = atoi(attr->value);
+
+ if (num_channels < 1 || num_channels > 7 || num_channels == 5)
+ return (NULL);
+
+ if ((cmyk = cfCMYKNew(num_channels)) == NULL)
+ return (NULL);
+
+ /*
+ * Get the optional cupsInkLimit attribute...
+ */
+
+ if ((attr = ppdFindColorAttr(ppd, "cupsInkLimit", colormodel, media,
+ resolution, spec, sizeof(spec), log, ld)) != NULL)
+ cfCMYKSetInkLimit(cmyk, atof(attr->value));
+
+ /*
+ * Get the optional cupsBlackGeneration attribute...
+ */
+
+ if ((attr = ppdFindColorAttr(ppd, "cupsBlackGeneration", colormodel, media,
+ resolution, spec, sizeof(spec), log, ld)) != NULL)
+ {
+ if (sscanf(attr->value, "%f%f", &lower, &upper) == 2)
+ cfCMYKSetBlack(cmyk, lower, upper, log, ld);
+ }
+
+ /*
+ * Get the optional cupsBlackXY or cupsBlackGamma attributes...
+ */
+
+ if (num_channels != 3)
+ {
+ if ((attr = ppdFindColorAttr(ppd, "cupsBlackXY", colormodel, media,
+ resolution, spec, sizeof(spec), log, ld)) != NULL)
+ {
+ for (num_xypoints = 0, xyptr = xypoints;
+ attr != NULL && attr->value != NULL && num_xypoints < 100;
+ attr = ppdFindNextAttr(ppd, "cupsBlackXY", spec))
+ if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
+ {
+ num_xypoints ++;
+ xyptr += 2;
+ }
+
+ switch (num_channels)
+ {
+ case 1 :
+ case 2 :
+ cfCMYKSetCurve(cmyk, 0, num_xypoints, xypoints, log, ld);
+ break;
+ case 4 :
+ cfCMYKSetCurve(cmyk, 3, num_xypoints, xypoints, log, ld);
+ break;
+ case 6 :
+ case 7 :
+ cfCMYKSetCurve(cmyk, 5, num_xypoints, xypoints, log, ld);
+ break;
+ }
+ }
+ else if ((attr = ppdFindColorAttr(ppd, "cupsBlackGamma", colormodel,
+ media, resolution, spec,
+ sizeof(spec), log, ld)) != NULL)
+ {
+ if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
+ switch (num_channels)
+ {
+ case 1 :
+ case 2 :
+ cfCMYKSetGamma(cmyk, 0, gamval, density, log, ld);
+ break;
+ case 4 :
+ cfCMYKSetGamma(cmyk, 3, gamval, density, log, ld);
+ break;
+ case 6 :
+ case 7 :
+ cfCMYKSetGamma(cmyk, 5, gamval, density, log, ld);
+ break;
+ }
+ }
+ else if ((attr = ppdFindColorAttr(ppd, "cupsAllXY", colormodel, media,
+ resolution, spec, sizeof(spec), log, ld)) !=
+ NULL)
+ {
+ for (num_xypoints = 0, xyptr = xypoints;
+ attr != NULL && attr->value != NULL && num_xypoints < 100;
+ attr = ppdFindNextAttr(ppd, "cupsAllXY", spec))
+ if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
+ {
+ num_xypoints ++;
+ xyptr += 2;
+ }
+
+ switch (num_channels)
+ {
+ case 1 :
+ case 2 :
+ cfCMYKSetCurve(cmyk, 0, num_xypoints, xypoints, log, ld);
+ break;
+ case 4 :
+ cfCMYKSetCurve(cmyk, 3, num_xypoints, xypoints, log, ld);
+ break;
+ case 6 :
+ case 7 :
+ cfCMYKSetCurve(cmyk, 5, num_xypoints, xypoints, log, ld);
+ break;
+ }
+ }
+ else if ((attr = ppdFindColorAttr(ppd, "cupsAllGamma", colormodel,
+ media, resolution, spec,
+ sizeof(spec), log, ld)) != NULL &&
+ num_channels != 3)
+ {
+ if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
+ switch (num_channels)
+ {
+ case 1 :
+ case 2 :
+ cfCMYKSetGamma(cmyk, 0, gamval, density, log, ld);
+ break;
+ case 4 :
+ cfCMYKSetGamma(cmyk, 3, gamval, density, log, ld);
+ break;
+ case 6 :
+ case 7 :
+ cfCMYKSetGamma(cmyk, 5, gamval, density, log, ld);
+ break;
+ }
+ }
+ }
+
+ if (num_channels > 2)
+ {
+ /*
+ * Get the optional cupsCyanXY or cupsCyanGamma attributes...
+ */
+
+ if ((attr = ppdFindColorAttr(ppd, "cupsCyanXY", colormodel, media,
+ resolution, spec, sizeof(spec), log, ld)) != NULL)
+ {
+ for (num_xypoints = 0, xyptr = xypoints;
+ attr != NULL && attr->value != NULL && num_xypoints < 100;
+ attr = ppdFindNextAttr(ppd, "cupsCyanXY", spec))
+ if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
+ {
+ num_xypoints ++;
+ xyptr += 2;
+ }
+
+ cfCMYKSetCurve(cmyk, 0, num_xypoints, xypoints, log, ld);
+ }
+ else if ((attr = ppdFindColorAttr(ppd, "cupsCyanGamma", colormodel, media,
+ resolution, spec, sizeof(spec), log, ld)) !=
+ NULL)
+ {
+ if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
+ cfCMYKSetGamma(cmyk, 0, gamval, density, log, ld);
+ }
+ else if ((attr = ppdFindColorAttr(ppd, "cupsAllXY", colormodel, media,
+ resolution, spec, sizeof(spec), log, ld)) !=
+ NULL)
+ {
+ for (num_xypoints = 0, xyptr = xypoints;
+ attr != NULL && attr->value != NULL && num_xypoints < 100;
+ attr = ppdFindNextAttr(ppd, "cupsAllXY", spec))
+ if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
+ {
+ num_xypoints ++;
+ xyptr += 2;
+ }
+
+ cfCMYKSetCurve(cmyk, 0, num_xypoints, xypoints, log, ld);
+ }
+ else if ((attr = ppdFindColorAttr(ppd, "cupsAllGamma", colormodel, media,
+ resolution, spec, sizeof(spec), log, ld)) !=
+ NULL)
+ {
+ if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
+ cfCMYKSetGamma(cmyk, 0, gamval, density, log, ld);
+ }
+
+ /*
+ * Get the optional cupsMagentaXY or cupsMagentaGamma attributes...
+ */
+
+ if ((attr = ppdFindColorAttr(ppd, "cupsMagentaXY", colormodel, media,
+ resolution, spec, sizeof(spec), log, ld)) != NULL)
+ {
+ for (num_xypoints = 0, xyptr = xypoints;
+ attr != NULL && attr->value != NULL && num_xypoints < 100;
+ attr = ppdFindNextAttr(ppd, "cupsMagentaXY", spec))
+ if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
+ {
+ num_xypoints ++;
+ xyptr += 2;
+ }
+
+ switch (num_channels)
+ {
+ case 3 :
+ case 4 :
+ cfCMYKSetCurve(cmyk, 1, num_xypoints, xypoints, log, ld);
+ break;
+ case 6 :
+ case 7 :
+ cfCMYKSetCurve(cmyk, 2, num_xypoints, xypoints, log, ld);
+ break;
+ }
+ }
+ else if ((attr = ppdFindColorAttr(ppd, "cupsMagentaGamma", colormodel, media,
+ resolution, spec, sizeof(spec), log, ld)) !=
+ NULL)
+ {
+ if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
+ switch (num_channels)
+ {
+ case 3 :
+ case 4 :
+ cfCMYKSetGamma(cmyk, 1, gamval, density, log, ld);
+ break;
+ case 6 :
+ case 7 :
+ cfCMYKSetGamma(cmyk, 2, gamval, density, log, ld);
+ break;
+ }
+ }
+ else if ((attr = ppdFindColorAttr(ppd, "cupsAllXY", colormodel, media,
+ resolution, spec, sizeof(spec), log, ld)) !=
+ NULL)
+ {
+ for (num_xypoints = 0, xyptr = xypoints;
+ attr != NULL && attr->value != NULL && num_xypoints < 100;
+ attr = ppdFindNextAttr(ppd, "cupsAllXY", spec))
+ if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
+ {
+ num_xypoints ++;
+ xyptr += 2;
+ }
+
+ switch (num_channels)
+ {
+ case 3 :
+ case 4 :
+ cfCMYKSetCurve(cmyk, 1, num_xypoints, xypoints, log, ld);
+ break;
+ case 6 :
+ case 7 :
+ cfCMYKSetCurve(cmyk, 2, num_xypoints, xypoints, log, ld);
+ break;
+ }
+ }
+ else if ((attr = ppdFindColorAttr(ppd, "cupsAllGamma", colormodel, media,
+ resolution, spec, sizeof(spec), log, ld)) !=
+ NULL)
+ {
+ if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
+ switch (num_channels)
+ {
+ case 3 :
+ case 4 :
+ cfCMYKSetGamma(cmyk, 1, gamval, density, log, ld);
+ break;
+ case 6 :
+ case 7 :
+ cfCMYKSetGamma(cmyk, 2, gamval, density, log, ld);
+ break;
+ }
+ }
+
+ /*
+ * Get the optional cupsYellowXY or cupsYellowGamma attributes...
+ */
+
+ if ((attr = ppdFindColorAttr(ppd, "cupsYellowXY", colormodel, media,
+ resolution, spec, sizeof(spec), log, ld)) != NULL)
+ {
+ for (num_xypoints = 0, xyptr = xypoints;
+ attr != NULL && attr->value != NULL && num_xypoints < 100;
+ attr = ppdFindNextAttr(ppd, "cupsYellowXY", spec))
+ if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
+ {
+ num_xypoints ++;
+ xyptr += 2;
+ }
+
+ switch (num_channels)
+ {
+ case 3 :
+ case 4 :
+ cfCMYKSetCurve(cmyk, 2, num_xypoints, xypoints, log, ld);
+ break;
+ case 6 :
+ case 7 :
+ cfCMYKSetCurve(cmyk, 4, num_xypoints, xypoints, log, ld);
+ break;
+ }
+ }
+ else if ((attr = ppdFindColorAttr(ppd, "cupsYellowGamma", colormodel, media,
+ resolution, spec, sizeof(spec), log, ld)) !=
+ NULL)
+ {
+ if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
+ switch (num_channels)
+ {
+ case 3 :
+ case 4 :
+ cfCMYKSetGamma(cmyk, 2, gamval, density, log, ld);
+ break;
+ case 6 :
+ case 7 :
+ cfCMYKSetGamma(cmyk, 4, gamval, density, log, ld);
+ break;
+ }
+ }
+ else if ((attr = ppdFindColorAttr(ppd, "cupsAllXY", colormodel, media,
+ resolution, spec, sizeof(spec), log, ld)) !=
+ NULL)
+ {
+ for (num_xypoints = 0, xyptr = xypoints;
+ attr != NULL && attr->value != NULL && num_xypoints < 100;
+ attr = ppdFindNextAttr(ppd, "cupsAllXY", spec))
+ if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
+ {
+ num_xypoints ++;
+ xyptr += 2;
+ }
+
+ switch (num_channels)
+ {
+ case 3 :
+ case 4 :
+ cfCMYKSetCurve(cmyk, 2, num_xypoints, xypoints, log, ld);
+ break;
+ case 6 :
+ case 7 :
+ cfCMYKSetCurve(cmyk, 4, num_xypoints, xypoints, log, ld);
+ break;
+ }
+ }
+ else if ((attr = ppdFindColorAttr(ppd, "cupsAllGamma", colormodel, media,
+ resolution, spec, sizeof(spec), log, ld)) !=
+ NULL)
+ {
+ if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
+ switch (num_channels)
+ {
+ case 3 :
+ case 4 :
+ cfCMYKSetGamma(cmyk, 2, gamval, density, log, ld);
+ break;
+ case 6 :
+ case 7 :
+ cfCMYKSetGamma(cmyk, 4, gamval, density, log, ld);
+ break;
+ }
+ }
+ }
+
+ /*
+ * Get the optional cupsLightBlackXY, cupsLightBlackGamma, or
+ * cupsBlackLtDk attributes...
+ */
+
+ if (num_channels == 2 || num_channels == 7)
+ {
+ if ((attr = ppdFindColorAttr(ppd, "cupsLightBlackXY", colormodel, media,
+ resolution, spec, sizeof(spec), log, ld)) != NULL)
+ {
+ for (num_xypoints = 0, xyptr = xypoints;
+ attr != NULL && attr->value != NULL && num_xypoints < 100;
+ attr = ppdFindNextAttr(ppd, "cupsLightBlackXY", spec))
+ if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
+ {
+ num_xypoints ++;
+ xyptr += 2;
+ }
+
+ switch (num_channels)
+ {
+ case 2 :
+ cfCMYKSetCurve(cmyk, 1, num_xypoints, xypoints, log, ld);
+ break;
+ case 7 :
+ cfCMYKSetCurve(cmyk, 6, num_xypoints, xypoints, log, ld);
+ break;
+ }
+ }
+ else if ((attr = ppdFindColorAttr(ppd, "cupsLightBlackGamma", colormodel,
+ media, resolution, spec,
+ sizeof(spec), log, ld)) != NULL)
+ {
+ if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
+ switch (num_channels)
+ {
+ case 2 :
+ cfCMYKSetGamma(cmyk, 1, gamval, density, log, ld);
+ break;
+ case 7 :
+ cfCMYKSetGamma(cmyk, 6, gamval, density, log, ld);
+ break;
+ }
+ }
+ else if ((attr = ppdFindColorAttr(ppd, "cupsBlackLtDk", colormodel, media,
+ resolution, spec, sizeof(spec), log, ld)) !=
+ NULL)
+ {
+ if (sscanf(attr->value, "%f%f", &light, &dark) == 2)
+ switch (num_channels)
+ {
+ case 2 :
+ cfCMYKSetLtDk(cmyk, 0, light, dark, log, ld);
+ break;
+ case 7 :
+ cfCMYKSetLtDk(cmyk, 5, light, dark, log, ld);
+ break;
+ }
+ else
+ if (log) log(ld, CF_LOGLEVEL_ERROR,
+ "Bad cupsBlackLtDk value \"%s\"!",
+ attr->value);
+ }
+ else
+ if (log) log(ld, CF_LOGLEVEL_WARN,
+ "No light black attribute found for %s!",
+ spec);
+ }
+
+ if (num_channels >= 6)
+ {
+ /*
+ * Get the optional cupsLightCyanXY, cupsLightCyanGamma, or
+ * cupsCyanLtDk attributes...
+ */
+
+ if ((attr = ppdFindColorAttr(ppd, "cupsLightCyanXY", colormodel, media,
+ resolution, spec, sizeof(spec), log, ld)) != NULL)
+ {
+ for (num_xypoints = 0, xyptr = xypoints;
+ attr != NULL && attr->value != NULL && num_xypoints < 100;
+ attr = ppdFindNextAttr(ppd, "cupsLightCyanXY", spec))
+ if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
+ {
+ num_xypoints ++;
+ xyptr += 2;
+ }
+
+ cfCMYKSetCurve(cmyk, 1, num_xypoints, xypoints, log, ld);
+ }
+ else if ((attr = ppdFindColorAttr(ppd, "cupsLightCyanGamma", colormodel,
+ media, resolution, spec,
+ sizeof(spec), log, ld)) != NULL)
+ {
+ if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
+ cfCMYKSetGamma(cmyk, 1, gamval, density, log, ld);
+ }
+ else if ((attr = ppdFindColorAttr(ppd, "cupsCyanLtDk", colormodel, media,
+ resolution, spec, sizeof(spec), log, ld)) !=
+ NULL)
+ {
+ if (sscanf(attr->value, "%f%f", &light, &dark) == 2)
+ cfCMYKSetLtDk(cmyk, 0, light, dark, log, ld);
+ else
+ if (log) log(ld, CF_LOGLEVEL_ERROR,
+ "Bad cupsCyanLtDk value \"%s\"!",
+ attr->value);
+ }
+ else
+ if (log) log(ld, CF_LOGLEVEL_WARN,
+ "No light cyan attribute found for %s!",
+ spec);
+
+ /*
+ * Get the optional cupsLightMagentaXY, cupsLightMagentaGamma, or
+ * cupsMagentaLtDk attributes...
+ */
+
+ if ((attr = ppdFindColorAttr(ppd, "cupsLightMagentaXY", colormodel, media,
+ resolution, spec, sizeof(spec), log, ld)) != NULL)
+ {
+ for (num_xypoints = 0, xyptr = xypoints;
+ attr != NULL && attr->value != NULL && num_xypoints < 100;
+ attr = ppdFindNextAttr(ppd, "cupsLightMagentaXY", spec))
+ if (sscanf(attr->value, "%f%f", xyptr, xyptr + 1) == 2)
+ {
+ num_xypoints ++;
+ xyptr += 2;
+ }
+
+ cfCMYKSetCurve(cmyk, 3, num_xypoints, xypoints, log, ld);
+ }
+ else if ((attr = ppdFindColorAttr(ppd, "cupsLightMagentaGamma", colormodel,
+ media, resolution, spec,
+ sizeof(spec), log, ld)) != NULL)
+ {
+ if (sscanf(attr->value, "%f%f", &gamval, &density) == 2)
+ cfCMYKSetGamma(cmyk, 3, gamval, density, log, ld);
+ }
+ else if ((attr = ppdFindColorAttr(ppd, "cupsMagentaLtDk", colormodel, media,
+ resolution, spec, sizeof(spec), log, ld)) !=
+ NULL)
+ {
+ if (sscanf(attr->value, "%f%f", &light, &dark) == 2)
+ cfCMYKSetLtDk(cmyk, 2, light, dark, log, ld);
+ else
+ if (log) log(ld, CF_LOGLEVEL_ERROR,
+ "Bad cupsMagentaLtDk value \"%s\"!",
+ attr->value);
+ }
+ else
+ if (log) log(ld, CF_LOGLEVEL_WARN,
+ "No light magenta attribute found for %s!",
+ spec);
+ }
+
+ /*
+ * Return the new profile...
+ */
+
+ return (cmyk);
+}
free(ppd->jcl_begin);
free(ppd->jcl_end);
free(ppd->jcl_ps);
+#if HAVE_CUPS_3_X
+ free(ppd->jcl_pdf);
+#endif
/*
* Free any UI groups, subgroups, and options...
ppd->jcl_ps = strdup(string);
ppd_decode(ppd->jcl_ps); /* Decode quoted string */
}
+#if HAVE_CUPS_3_X
+ else if (!strcmp(keyword, "JCLToPDFInterpreter"))
+ {
+ ppd->jcl_pdf = strdup(string);
+ ppd_decode(ppd->jcl_pdf); /* Decode quoted string */
+ }
+#endif
else if (!strcmp(keyword, "AccurateScreensSupport"))
ppd->accurate_screens = !strcasecmp(string, "True");
else if (!strcmp(keyword, "ColorDevice"))
# include <cupsfilters/log.h>
# include <stdio.h>
+# include <stdbool.h>
# include <cups/raster.h>
+# include <cupsfilters/driver.h>
/*
@private@ */
char *jcl_begin; /* Start JCL commands */
char *jcl_ps; /* Enter PostScript interpreter */
+#if HAVE_CUPS_3_X
+ char *jcl_pdf; /* Enter PDF interpreter */
+#endif
char *jcl_end; /* End JCL commands */
char *lang_encoding; /* Language encoding */
char *lang_version; /* Language version (English, Spanish,
extern cups_encoding_t ppdGetEncoding(const char *name);
extern cups_array_t *ppdGetLanguages(ppd_file_t *ppd);
extern ppd_globals_t *ppdGlobals(void);
+extern void ppdHandleMedia(ppd_file_t *ppd);
extern unsigned ppdHashName(const char *name);
extern ppd_attr_t *ppdLocalizedAttr(ppd_file_t *ppd, const char *keyword,
const char *spec, const char *ll_CC);
const char *dashchars);
/**** New in cups-filters 2.0.0: Overtaken from ippeveprinter ****/
-extern ipp_t *ppdLoadAttributes(ppd_file_t *ppd,
- cups_array_t *docformats);
+extern ipp_t *ppdLoadAttributes(ppd_file_t *ppd);
/**** New in cups-filters 2.0.0: Overtaken from ippeveps ****/
extern int ppdGetOptions(cups_option_t **options,
/**** New in cups-filters 2.0.0: For PPD retro-fit Printer Applications ****/
extern void ppdCacheAssignPresets(ppd_file_t *ppd, ppd_cache_t *pc);
+/**** New in cups-filters 2.0.0: JCL for PDF printers, for
+ ppdFilterPDFToPDF() and ppdFilterImageToPDF() ****/
+extern int ppdEmitJCLPDF(ppd_file_t *ppd, FILE *fp,
+ int job_id, const char *user,
+ const char *title,
+ int hw_copies, bool hw_collate);
+
+/**** New in cups-filters 2.0.0: PPD file generator for CUPS queues for
+ driverless printers, compared to the one of CUPS this one supports
+ also clusters composed of different printers as composed by
+ cups-browsed, was cfCreatePPDFromIPP(2)() in libcupsfilters before ****/
+char *ppdCreatePPDFromIPP(char *buffer, size_t bufsize,
+ ipp_t *response, const char *make_model,
+ const char *pdl, int color, int duplex,
+ char *status_msg, size_t status_msg_size);
+char *ppdCreatePPDFromIPP2(char *buffer, size_t bufsize,
+ ipp_t *response, const char *make_model,
+ const char *pdl, int color, int duplex,
+ cups_array_t* conflicts,
+ cups_array_t *sizes,
+ char* default_pagesize,
+ const char *default_cluster_color,
+ char *status_msg, size_t status_msg_size);
+
+/**** New in cups-filters 2.0.0: Functions to load color profile data from
+ PPD files, from driver.h ****/
+extern ppd_attr_t *ppdFindColorAttr(ppd_file_t *ppd, const char *name,
+ const char *colormodel,
+ const char *media,
+ const char *resolution,
+ char *spec, int specsize,
+ cf_logfunc_t log,
+ void *ld);
+extern cf_lut_t *ppdLutLoad(ppd_file_t *ppd,
+ const char *colormodel,
+ const char *media,
+ const char *resolution,
+ const char *ink,
+ cf_logfunc_t log,
+ void *ld);
+extern cf_rgb_t *ppdRGBLoad(ppd_file_t *ppd,
+ const char *colormodel,
+ const char *media,
+ const char *resolution,
+ cf_logfunc_t log,
+ void *ld);
+extern cf_cmyk_t *ppdCMYKLoad(ppd_file_t *ppd,
+ const char *colormodel,
+ const char *media,
+ const char *resolution,
+ cf_logfunc_t log,
+ void *ld);
+
/*
* C++ magic...
* Include necessary headers...
*/
-#include "colormanager.h"
-#include "filter.h"
-#include "image.h"
+#include <cupsfilters/colormanager.h>
+#include <cupsfilters/filter.h>
+#include <cupsfilters/image.h>
#include <config.h>
#include <sys/types.h>
#include <sys/stat.h>
switch (ret) {
case Z_ERRNO:
if (doc->logfunc) doc->logfunc(doc->logdata, CF_LOGLEVEL_ERROR,
- "cfFilterRasterToPS: zpipe - error in source data or output file");
+ "ppdFilterRasterToPS: zpipe - error in source data or output file");
break;
case Z_STREAM_ERROR:
if (doc->logfunc) doc->logfunc(doc->logdata, CF_LOGLEVEL_ERROR,
- "cfFilterRasterToPS: zpipe - invalid compression level");
+ "ppdFilterRasterToPS: zpipe - invalid compression level");
break;
case Z_DATA_ERROR:
if (doc->logfunc) doc->logfunc(doc->logdata, CF_LOGLEVEL_ERROR,
- "cfFilterRasterToPS: zpipe - invalid or incomplete deflate data");
+ "ppdFilterRasterToPS: zpipe - invalid or incomplete deflate data");
break;
case Z_MEM_ERROR:
if (doc->logfunc) doc->logfunc(doc->logdata, CF_LOGLEVEL_ERROR,
- "cfFilterRasterToPS: zpipe - out of memory");
+ "ppdFilterRasterToPS: zpipe - out of memory");
break;
case Z_VERSION_ERROR:
if (doc->logfunc) doc->logfunc(doc->logdata, CF_LOGLEVEL_ERROR,
- "cfFilterRasterToPS: zpipe - zlib version mismatch!");
+ "ppdFilterRasterToPS: zpipe - zlib version mismatch!");
}
}
}
/*
- * 'cfFilterRasterToPS()' - Filter function to convert PWG raster input
+ * 'ppdFilterRasterToPS()' - Filter function to convert PWG raster input
* to PostScript
*/
int /* O - Error status */
-cfFilterRasterToPS(int inputfd, /* I - File descriptor input stream */
+ppdFilterRasterToPS(int inputfd, /* I - File descriptor input stream */
int outputfd, /* I - File descriptor output stream */
int inputseekable, /* I - Is input stream seekable? (unused) */
cf_filter_data_t *data, /* I - Job and printer data */
if (!iscanceled || !iscanceled(icd))
{
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterRasterToPS: Unable to open input data stream.");
+ "ppdFilterRasterToPS: Unable to open input data stream.");
}
return (1);
if (!iscanceled || !iscanceled(icd))
{
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterRasterToPS: Unable to open output data stream.");
+ "ppdFilterRasterToPS: Unable to open output data stream.");
}
cupsFileClose(inputfp);
if (iscanceled && iscanceled(icd))
{
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterRasterToPS: Job canceled");
+ "ppdFilterRasterToPS: Job canceled");
break;
}
Page ++;
if (log) log(ld, CF_LOGLEVEL_INFO,
- "cfFilterRasterToPS: Starting page %d.", Page);
+ "ppdFilterRasterToPS: Starting page %d.", Page);
/*
* Write the starting of the page
if (empty)
{
if (log) log(ld, CF_LOGLEVEL_DEBUG,
- "cfFilterRasterToPS: Input is empty, outputting empty file.");
+ "ppdFilterRasterToPS: Input is empty, outputting empty file.");
cupsRasterClose(ras);
return 0;
}
* main() - Enumerate or display PPD files.
* cat_ppd() - Display a PPD file.
* list_ppds() - List PPDs.
+ *
+ * Compile with:gcc -o testdriver testdriver.c -I.. -lppd -lcups
*/
/*
* Include necessary headers...
*/
-#include <cups/string-private.h>
+#include <ppd/ppd.h>
+#include <ppd/string-private.h>
#include <cups/cups.h>
#include <cups/cups.h>
#include <cups/raster.h>
#include <cupsfilters/ipp.h>
-#include <cupsfilters/ppdgenerator.h>
+#include <cupsfilters/ipp.h>
#include <ppd/ppd.h>
#include "cups-notifier.h"
{
cups_array_t *sizes, *page_media;
cups_size_t *size;
- ipp_attribute_t *defattr;
- char *ppdsizename, *temp;
- int min_length = INT_MAX, min_width = INT_MAX,
- max_length = 0, max_width = 0,
- bottom, left, right, top;
- char ppdname[41];
+ char *ppdsizename, *ptr;
ppdsizename = (char *)malloc(sizeof(char) * 128);
- sizes = cfGenerateSizes(printer_attributes, &defattr, &min_length, &min_width,
- &max_length, &max_width,
- &bottom, &left, &right, &top,ppdname);
+ cfGenerateSizes(printer_attributes, CF_GEN_SIZES_DEFAULT,
+ &sizes, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL);
if ((page_media = cupsArrayNew3((cups_array_func_t)strcasecmp, NULL, NULL, 0,
(cups_acopy_func_t)strdup,
(cups_afree_func_t)free)) == NULL)
for (size = (cups_size_t *)cupsArrayFirst(sizes); size;
size = (cups_size_t *)cupsArrayNext(sizes)) {
strcpy(ppdsizename, size->media);
- if (( temp = strchr(ppdsizename, ' ')) != NULL)
- *temp = '\0';
+ if (( ptr = strchr(ppdsizename, ' ')) != NULL)
+ *ptr = '\0';
cupsArrayAdd(page_media, ppdsizename);
}
free(ppdsizename);
*sizes_ppdname;
cups_size_t *size;
remote_printer_t *p;
- ipp_attribute_t *defattr;
- char ppdname[41], pagesize[128];
+ char pagesize[128];
char* first_space;
- int min_length, min_width, max_length, max_width,
- bottom, left, right, top;
cluster_sizes = cupsArrayNew3((cups_array_func_t)pwg_compare_sizes,
NULL, NULL, 0,
if(p->status == STATUS_DISAPPEARED || p->status == STATUS_UNCONFIRMED ||
p->status == STATUS_TO_BE_RELEASED )
continue;
- defattr = NULL;
- min_length = INT_MAX;
- min_width = INT_MAX;
- max_length = 0;
- max_width = 0;
- bottom = 0;
- left = 0;
- right = 0;
- top = 0;
- sizes = cfGenerateSizes(p->prattrs, &defattr, &min_length, &min_width,
- &max_length, &max_width,
- &bottom, &left, &right, &top, ppdname);
+ cfGenerateSizes(p->prattrs, CF_GEN_SIZES_DEFAULT,
+ &sizes, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL);
for (size = (cups_size_t *)cupsArrayFirst(sizes);
size; size = (cups_size_t *)cupsArrayNext(sizes)) {
if (!cupsArrayFind(cluster_sizes, size)) {
/*get_cluster_attributes - Returns ipp_t* containing the options supplied by
all the printers in the cluster, which can be sent
- to cfCreatePPDFromIPP2() to generate the PPD file */
+ to ppdCreatePPDFromIPP2() to generate the PPD file */
ipp_t* get_cluster_attributes(char* cluster_name)
{
remote_printer_t *p;
int max_pages_per_min = 0, pages_per_min;
remote_printer_t *p, *def_printer = NULL;
int i, count;
- ipp_attribute_t *attr, *media_attr, *media_col_default, *defattr;
+ ipp_attribute_t *attr, *media_attr, *media_col_default;
ipp_t *media_col,
*media_size, *current_media=NULL;
char media_source[32], media_type[32];
const char *keyword;
cf_res_t *res;
int xres, yres;
- int min_length = INT_MAX, min_width = INT_MAX,
- max_length = 0, max_width = 0,
- bottom, left, right, top;
char ppdname[41];
- cups_array_t *sizes;
/*The printer with the maximum Throughtput(pages_per_min) is selected as
the default printer*/
debug_printf("Default Attributes of the cluster %s are : \n", cluster_name);
/* Generating the default pagesize for the cluster*/
- sizes = cfGenerateSizes(def_printer->prattrs, &defattr, &min_length,
- &min_width, &max_length, &max_width,
- &bottom, &left, &right, &top, ppdname);
+ cfGenerateSizes(def_printer->prattrs, CF_GEN_SIZES_DEFAULT,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ ppdname, NULL);
strcpy(default_pagesize, ppdname);
debug_printf("Default PageSize : %s\n", default_pagesize);
cfFreeResolution(res, NULL);
}
}
-
- cupsArrayDelete(sizes);
}
/* Function to see which printer in the cluster supports the
ourselves */
printer_ipp_response = (num_cluster_printers == 1) ? p->prattrs :
printer_attributes;
- if (!cfCreatePPDFromIPP2(ppdname, sizeof(ppdname), printer_ipp_response,
- make_model,
- pdl, color, duplex, conflicts, sizes,
- default_pagesize, default_color,
- ppdgenerator_msg, sizeof(ppdgenerator_msg))) {
+ if (!ppdCreatePPDFromIPP2(ppdname, sizeof(ppdname), printer_ipp_response,
+ make_model,
+ pdl, color, duplex, conflicts, sizes,
+ default_pagesize, default_color,
+ ppdgenerator_msg, sizeof(ppdgenerator_msg))) {
if (errno != 0)
debug_printf("Unable to create PPD file: %s\n",
strerror(errno));
ourselves */
printer_ipp_response = (num_cluster_printers == 1) ? p->prattrs :
printer_attributes;
- if (!cfCreatePPDFromIPP2(ppdname, sizeof(ppdname), printer_ipp_response,
- make_model,
- pdl, color, duplex, conflicts, sizes,
- default_pagesize, default_color,
- ppdgenerator_msg, sizeof(ppdgenerator_msg))) {
+ if (!ppdCreatePPDFromIPP2(ppdname, sizeof(ppdname),
+ printer_ipp_response, make_model,
+ pdl, color, duplex, conflicts, sizes,
+ default_pagesize, default_color,
+ ppdgenerator_msg, sizeof(ppdgenerator_msg))) {
if (errno != 0)
debug_printf("Unable to create PPD file: %s\n",
strerror(errno));
#include <ppd/ppd.h>
#include <cups/raster.h>
#include <cupsfilters/ipp.h>
-#include <cupsfilters/ppdgenerator.h>
+#include <cupsfilters/ipp.h>
#define MAX_OUTPUT_LEN 8192
}
/* Generate the PPD file */
- if (!cfCreatePPDFromIPP(ppdname, sizeof(ppdname), response, NULL, NULL, 0,
- 0, ppdgenerator_msg, sizeof(ppdgenerator_msg))) {
+ if (!ppdCreatePPDFromIPP(ppdname, sizeof(ppdname), response, NULL, NULL, 0,
+ 0, ppdgenerator_msg, sizeof(ppdgenerator_msg))) {
if (strlen(ppdgenerator_msg) > 0)
fprintf(stderr, "ERROR: Unable to create PPD file: %s\n",
ppdgenerator_msg);