From 63ba0ce8b38645aac83fa905c128b5859f22a81d Mon Sep 17 00:00:00 2001 From: Richard Hughes Date: Tue, 8 Mar 2011 11:29:45 +0000 Subject: [PATCH] Backport a patch from svn trunk to enable colord support. --- ghostscript-colord.patch | 1267 ++++++++++++++++++++++++++++ ghostscript-ijs-automake-ver.patch | 12 + ghostscript.spec | 17 +- 3 files changed, 1295 insertions(+), 1 deletion(-) create mode 100644 ghostscript-colord.patch create mode 100644 ghostscript-ijs-automake-ver.patch diff --git a/ghostscript-colord.patch b/ghostscript-colord.patch new file mode 100644 index 0000000..813397c --- /dev/null +++ b/ghostscript-colord.patch @@ -0,0 +1,1267 @@ +diff -urNp ghostscript-9.01.old/configure.ac ghostscript-9.01/configure.ac +--- ghostscript-9.01.old/configure.ac 2011-03-08 10:47:24.851721587 +0000 ++++ ghostscript-9.01/configure.ac 2011-03-08 10:48:11.022721481 +0000 +@@ -423,6 +423,37 @@ AC_SUBST(HAVE_FONTCONFIG) + AC_SUBST(FONTCONFIG_CFLAGS) + AC_SUBST(FONTCONFIG_LIBS) + ++dnl DBus support ++HAVE_DBUS="" ++DBUS_CFLAGS="" ++DBUS_LIBS="" ++AC_ARG_ENABLE([dbus], AC_HELP_STRING([--disable-dbus], ++ [Do not use dbus to communicate with external services])) ++if test "$enable_dbus" != "no"; then ++ if test "x$PKGCONFIG" != x; then ++ AC_MSG_CHECKING(for dbus with pkg-config) ++ if $PKGCONFIG --exists dbus-1; then ++ AC_MSG_RESULT(yes) ++ DBUS_CFLAGS="$CFLAGS `$PKGCONFIG --cflags dbus-1`" ++ DBUS_LIBS="`$PKGCONFIG --libs dbus-1`" ++ HAVE_DBUS=-DHAVE_DBUS ++ else ++ AC_MSG_RESULT(no) ++ fi ++ fi ++ if test -z "$HAVE_DBUS"; then ++ AC_CHECK_LIB([dbus], [dbus_message_iter_get_basic], [ ++ AC_CHECK_HEADER([dbus-1.0/dbus/dbus.h], [ ++ DBUS_LIBS="-ldbus-1 -lpthread -lrt" ++ HAVE_DBUS="-DHAVE_DBUS" ++ ]) ++ ]) ++ fi ++fi ++AC_SUBST(HAVE_DBUS) ++AC_SUBST(DBUS_CFLAGS) ++AC_SUBST(DBUS_LIBS) ++ + AC_CHECK_LIB(dl, dlopen) + + AC_ARG_ENABLE([freetype], AC_HELP_STRING([--disable-freetype], +@@ -1439,6 +1470,6 @@ dnl ------------------------------------ + AC_SUBST(OPT_CFLAGS) + AC_SUBST(DBG_CFLAGS) + AC_SUBST(GCFLAGS) +-AC_OUTPUT(Makefile cups/pstopxl cups/pstoraster) ++AC_OUTPUT(Makefile cups/pstopxl) + +-chmod +x cups/pstopxl cups/pstoraster ++chmod +x cups/pstopxl +diff -urNp ghostscript-9.01.old/cups/colord.c ghostscript-9.01/cups/colord.c +--- ghostscript-9.01.old/cups/colord.c 1970-01-01 01:00:00.000000000 +0100 ++++ ghostscript-9.01/cups/colord.c 2011-03-08 10:48:11.023721494 +0000 +@@ -0,0 +1,367 @@ ++/* ++Copyright (c) 2011, Tim Waugh ++Copyright (c) 2011, Richard Hughes ++ ++Permission is hereby granted, free of charge, to any person obtaining ++a copy of this software and associated documentation files (the ++"Software"), to deal in the Software without restriction, including ++without limitation the rights to use, copy, modify, merge, publish, ++distribute, sublicense, and/or sell copies of the Software, and to ++permit persons to whom the Software is furnished to do so, subject to ++the following conditions: ++ ++The above copyright notice and this permission notice shall be included ++in all copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ++IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ++CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, ++TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE ++SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++ ++MIT Open Source License - http://www.opensource.org/ ++ ++*/ ++ ++/* $Id$ */ ++ ++/* Common routines for accessing the colord CMS framework */ ++ ++#include ++#include ++#include ++ ++#ifdef HAVE_DBUS ++ #include ++#endif ++ ++#include "colord.h" ++ ++#define QUAL_COLORSPACE 0 ++#define QUAL_MEDIA 1 ++#define QUAL_RESOLUTION 2 ++#define QUAL_SIZE 3 ++ ++char ** ++colord_get_qualifier_for_ppd (ppd_file_t *ppd) ++{ ++ char q_keyword[PPD_MAX_NAME]; ++ 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); ++ ++ if (q1_attr && q1_attr->value && q1_attr->value[0]) ++ q1_choice = q1_attr->value; ++ else ++ q1_choice = ""; ++ ++ /* get colorspace */ ++ if ((attr = ppdFindAttr (ppd, "cupsICCQualifier2", 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); ++ ++ 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]) ++ { ++ snprintf(q_keyword, sizeof(q_keyword), "Default%s", attr->value); ++ q2_attr = ppdFindAttr(ppd, q_keyword, NULL); ++ } ++ 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); ++ } ++ 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 = ""; ++ ++ /* 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 (DBusConnection *con, ++ const char *object_path) ++{ ++ char *filename = NULL; ++ const char *interface = "org.freedesktop.ColorManager.Profile"; ++ const char *property = "Filename"; ++ const char *tmp; ++ DBusError error; ++ DBusMessageIter args; ++ DBusMessage *message = NULL; ++ DBusMessage *reply = NULL; ++ DBusMessageIter sub; ++ ++ message = dbus_message_new_method_call("org.freedesktop.ColorManager", ++ object_path, ++ "org.freedesktop.DBus.Properties", ++ "Get"); ++ ++ dbus_message_iter_init_append(message, &args); ++ dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &interface); ++ dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &property); ++ ++ /* send syncronous */ ++ dbus_error_init(&error); ++ fprintf(stderr, "DEBUG: Calling %s.Get(%s)\n", interface, property); ++ reply = dbus_connection_send_with_reply_and_block(con, ++ message, ++ -1, ++ &error); ++ if (reply == NULL) { ++ fprintf(stderr, "DEBUG: Failed to send: %s:%s\n", ++ error.name, error.message); ++ dbus_error_free(&error); ++ goto out; ++ } ++ ++ /* get reply data */ ++ dbus_message_iter_init(reply, &args); ++ if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_VARIANT) { ++ fprintf(stderr, "DEBUG: Incorrect reply type\n"); ++ goto out; ++ } ++ ++ dbus_message_iter_recurse(&args, &sub); ++ dbus_message_iter_get_basic(&sub, &tmp); ++ filename = strdup(tmp); ++out: ++ if (message != NULL) ++ dbus_message_unref(message); ++ if (reply != NULL) ++ dbus_message_unref(reply); ++ return filename; ++} ++ ++static char * ++get_profile_for_device_path (DBusConnection *con, ++ const char *object_path, ++ const char **split) ++{ ++ char **key = NULL; ++ char *profile = NULL; ++ char str[256]; ++ const char *tmp; ++ DBusError error; ++ DBusMessageIter args; ++ DBusMessageIter entry; ++ DBusMessage *message = NULL; ++ DBusMessage *reply = NULL; ++ int i = 0; ++ const int max_keys = 7; ++ ++ message = dbus_message_new_method_call("org.freedesktop.ColorManager", ++ object_path, ++ "org.freedesktop.ColorManager.Device", ++ "GetProfileForQualifiers"); ++ dbus_message_iter_init_append(message, &args); ++ ++ /* create the fallbacks */ ++ key = calloc(max_keys + 1, sizeof(char*)); ++ ++ /* exact match */ ++ i = 0; ++ snprintf(str, sizeof(str), "%s.%s.%s", ++ split[QUAL_COLORSPACE], ++ split[QUAL_MEDIA], ++ split[QUAL_RESOLUTION]); ++ key[i++] = strdup(str); ++ snprintf(str, sizeof(str), "%s.%s.*", ++ split[QUAL_COLORSPACE], ++ split[QUAL_MEDIA]); ++ key[i++] = strdup(str); ++ snprintf(str, sizeof(str), "%s.*.%s", ++ split[QUAL_COLORSPACE], ++ split[QUAL_RESOLUTION]); ++ key[i++] = strdup(str); ++ snprintf(str, sizeof(str), "%s.*.*", ++ split[QUAL_COLORSPACE]); ++ key[i++] = strdup(str); ++ key[i++] = strdup("*"); ++ dbus_message_iter_open_container(&args, ++ DBUS_TYPE_ARRAY, ++ "s", ++ &entry); ++ for (i=0; key[i] != NULL; i++) { ++ dbus_message_iter_append_basic(&entry, ++ DBUS_TYPE_STRING, ++ &key[i]); ++ } ++ dbus_message_iter_close_container(&args, &entry); ++ ++ /* send syncronous */ ++ dbus_error_init(&error); ++ fprintf(stderr, "DEBUG: Calling GetProfileForQualifiers(%s...)\n", key[0]); ++ reply = dbus_connection_send_with_reply_and_block(con, ++ message, ++ -1, ++ &error); ++ if (reply == NULL) { ++ fprintf(stderr, "DEBUG: Failed to send: %s:%s\n", ++ error.name, error.message); ++ dbus_error_free(&error); ++ goto out; ++ } ++ ++ /* get reply data */ ++ dbus_message_iter_init(reply, &args); ++ if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH) { ++ fprintf(stderr, "DEBUG: Incorrect reply type\n"); ++ goto out; ++ } ++ dbus_message_iter_get_basic(&args, &tmp); ++ fprintf(stderr, "DEBUG: Found profile %s\n", tmp); ++ ++ /* get filename */ ++ profile = get_filename_for_profile_path(con, tmp); ++ ++out: ++ if (message != NULL) ++ dbus_message_unref(message); ++ if (reply != NULL) ++ dbus_message_unref(reply); ++ if (key != NULL) { ++ for (i=0; i < max_keys; i++) ++ free(key[i]); ++ free(key); ++ } ++ return profile; ++} ++ ++static char * ++get_profile_for_device_id (DBusConnection *con, ++ const char *device_id, ++ const char **qualifier_tuple) ++{ ++ char *profile = NULL; ++ const char *device_path_tmp; ++ DBusError error; ++ DBusMessageIter args; ++ DBusMessage *message = NULL; ++ DBusMessage *reply = NULL; ++ ++ message = dbus_message_new_method_call("org.freedesktop.ColorManager", ++ "/org/freedesktop/ColorManager", ++ "org.freedesktop.ColorManager", ++ "FindDeviceById"); ++ dbus_message_iter_init_append(message, &args); ++ dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &device_id); ++ ++ /* send syncronous */ ++ dbus_error_init(&error); ++ fprintf(stderr, "DEBUG: Calling FindDeviceById(%s)\n", device_id); ++ reply = dbus_connection_send_with_reply_and_block(con, ++ message, ++ -1, ++ &error); ++ if (reply == NULL) { ++ fprintf(stderr, "DEBUG: Failed to send: %s:%s\n", ++ error.name, error.message); ++ dbus_error_free(&error); ++ goto out; ++ } ++ ++ /* get reply data */ ++ dbus_message_iter_init(reply, &args); ++ if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH) { ++ fprintf(stderr, "DEBUG: Incorrect reply type\n"); ++ goto out; ++ } ++ dbus_message_iter_get_basic(&args, &device_path_tmp); ++ fprintf(stderr, "DEBUG: Found device %s\n", device_path_tmp); ++ profile = get_profile_for_device_path(con, device_path_tmp, qualifier_tuple); ++out: ++ if (message != NULL) ++ dbus_message_unref(message); ++ if (reply != NULL) ++ dbus_message_unref(reply); ++ return profile; ++} ++ ++char * ++colord_get_profile_for_device_id (const char *device_id, ++ const char **qualifier_tuple) ++{ ++ DBusConnection *con; ++ char *filename = NULL; ++ ++ /* connect to system bus */ ++ con = dbus_bus_get(DBUS_BUS_SYSTEM, NULL); ++ if (con == NULL) { ++ fprintf(stderr, "ERROR: Failed to connect to system bus\n"); ++ goto out; ++ } ++ ++ /* get the best profile for the device */ ++ filename = get_profile_for_device_id (con, device_id, qualifier_tuple); ++ if (filename == NULL) { ++ fprintf(stderr, "DEBUG: Failed to get profile filename!\n"); ++ goto out; ++ } ++ fprintf(stderr, "DEBUG: Use profile filename: '%s'\n", filename); ++out: ++ if (con != NULL) ++ dbus_connection_unref(con); ++ return filename; ++} ++ ++#else ++ ++char * ++colord_get_profile_for_device_id (const char *device_id, ++ const char **qualifier_tuple) ++{ ++ fprintf(stderr, "WARN: not compiled with DBus support\n"); ++ return NULL; ++} ++ ++#endif +diff -urNp ghostscript-9.01.old/cups/colord.h ghostscript-9.01/cups/colord.h +--- ghostscript-9.01.old/cups/colord.h 1970-01-01 01:00:00.000000000 +0100 ++++ ghostscript-9.01/cups/colord.h 2011-03-08 10:48:11.024721504 +0000 +@@ -0,0 +1,35 @@ ++/* ++Copyright (c) 2011, Richard Hughes ++ ++Permission is hereby granted, free of charge, to any person obtaining ++a copy of this software and associated documentation files (the ++"Software"), to deal in the Software without restriction, including ++without limitation the rights to use, copy, modify, merge, publish, ++distribute, sublicense, and/or sell copies of the Software, and to ++permit persons to whom the Software is furnished to do so, subject to ++the following conditions: ++ ++The above copyright notice and this permission notice shall be included ++in all copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ++IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ++CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, ++TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE ++SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++ ++MIT Open Source License - http://www.opensource.org/ ++ ++*/ ++ ++/* $Id$ */ ++ ++/* Common routines for accessing the colord CMS framework */ ++ ++#include ++ ++char **colord_get_qualifier_for_ppd (ppd_file_t *ppd); ++char *colord_get_profile_for_device_id (const char *device_id, ++ const char **qualifier_tuple); +diff -urNp ghostscript-9.01.old/cups/cups.mak ghostscript-9.01/cups/cups.mak +--- ghostscript-9.01.old/cups/cups.mak 2011-03-08 10:47:23.796721588 +0000 ++++ ghostscript-9.01/cups/cups.mak 2011-03-08 10:50:01.360721549 +0000 +@@ -35,30 +35,30 @@ cups_= $(GLOBJ)gdevcups.$(OBJ) + # CUPSDATA=`cups-config --datadir` + # CUPSPDFTORASTER= 1 if CUPS is new enough (cups-config --version) + +-PDFTORASTER_XE=$(BINDIR)$(D)pdftoraster$(XE) ++GSTORASTER_XE=$(BINDIR)$(D)gstoraster$(XE) + +-cups: pdftoraster +-pdftoraster: $(PDFTORASTER_XE) +-pdftoraster_=cups/pdftoraster.c ++cups: gstoraster + +-$(PDFTORASTER_XE): $(pdftoraster_) ++gstoraster: $(GSTORASTER_XE) ++gstoraster_=cups/gstoraster.c cups/colord.c ++ ++$(GSTORASTER_XE): $(gstoraster_) + if [ "$(CUPSPDFTORASTER)" = "1" ]; then \ +- $(GLCC) $(LDFLAGS) -DBINDIR='"$(bindir)"' -DGS='"$(GS)"' -o $@ $(pdftoraster_) `cups-config --image --ldflags --libs`; \ ++ $(GLCC) $(LDFLAGS) $(DBUS_CFLAGS) -DBINDIR='"$(bindir)"' -DCUPSDATA='"$(CUPSDATA)"' -DGS='"$(GS)"' -o $@ $(gstoraster_) `cups-config --image --ldflags --libs` $(DBUS_LIBS); \ + fi + ++ + install: install-cups + + install-cups: cups + -mkdir -p $(DESTDIR)$(CUPSSERVERBIN)/filter +- $(INSTALL_PROGRAM) cups/pstoraster $(DESTDIR)$(CUPSSERVERBIN)/filter + if [ "$(CUPSPDFTORASTER)" = "1" ]; then \ +- $(INSTALL_PROGRAM) $(PDFTORASTER_XE) $(DESTDIR)$(CUPSSERVERBIN)/filter; \ ++ $(INSTALL_PROGRAM) $(GSTORASTER_XE) $(DESTDIR)$(CUPSSERVERBIN)/filter; \ + fi + $(INSTALL_PROGRAM) cups/pstopxl $(DESTDIR)$(CUPSSERVERBIN)/filter + -mkdir -p $(DESTDIR)$(CUPSDATA)/mime +- $(INSTALL_DATA) cups/pstoraster.convs $(DESTDIR)$(CUPSDATA)/mime + if [ "$(CUPSPDFTORASTER)" = "1" ]; then \ +- $(INSTALL_DATA) cups/pdftoraster.convs $(DESTDIR)$(CUPSDATA)/mime; \ ++ $(INSTALL_DATA) cups/gstoraster.convs $(DESTDIR)$(CUPSDATA)/mime; \ + fi + -mkdir -p $(DESTDIR)$(CUPSDATA)/model + $(INSTALL_DATA) cups/pxlcolor.ppd $(DESTDIR)$(CUPSDATA)/model +diff -urNp ghostscript-9.01.old/cups/gstoraster.c ghostscript-9.01/cups/gstoraster.c +--- ghostscript-9.01.old/cups/gstoraster.c 1970-01-01 01:00:00.000000000 +0100 ++++ ghostscript-9.01/cups/gstoraster.c 2011-03-08 10:48:11.026721536 +0000 +@@ -0,0 +1,702 @@ ++/* -*- Mode: C; tab-width: 2; indent-tabs-mode: s; c-basic-offset: 8 -*- ++ ++Copyright (c) 2008, Till Kamppeter ++Copyright (c) 2011, Tim Waugh ++Copyright (c) 2011, Richard Hughes ++ ++Permission is hereby granted, free of charge, to any person obtaining ++a copy of this software and associated documentation files (the ++"Software"), to deal in the Software without restriction, including ++without limitation the rights to use, copy, modify, merge, publish, ++distribute, sublicense, and/or sell copies of the Software, and to ++permit persons to whom the Software is furnished to do so, subject to ++the following conditions: ++ ++The above copyright notice and this permission notice shall be included ++in all copies or substantial portions of the Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ++IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ++CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, ++TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE ++SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++ ++MIT Open Source License - http://www.opensource.org/ ++ ++*/ ++ ++/* $Id$ */ ++ ++/* PS/PDF to CUPS Raster filter based on Ghostscript */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "colord.h" ++ ++#define PDF_MAX_CHECK_COMMENT_LINES 20 ++ ++#ifndef GS ++#define GS "gs" ++#endif ++#ifndef BINDIR ++#define BINDIR "/usr/bin" ++#endif ++#ifndef CUPS_FONTPATH ++#define CUPS_FONTPATH "/usr/share/cups/fonts" ++#endif ++#ifndef CUPSDATA ++#define CUPSDATA "/usr/share/cups" ++#endif ++ ++typedef enum { ++ GS_DOC_TYPE_PDF, ++ GS_DOC_TYPE_PS, ++ GS_DOC_TYPE_UNKNOWN ++} GsDocType; ++ ++#ifdef CUPS_RASTER_SYNCv1 ++typedef cups_page_header2_t gs_page_header; ++#else ++typedef cups_page_header_t gs_page_header; ++#endif /* CUPS_RASTER_SYNCv1 */ ++ ++static GsDocType ++parse_doc_type(FILE *fp) ++{ ++ char buf[5]; ++ GsDocType doc_type; ++ char *rc; ++ ++ /* get the first few bytes of the file */ ++ doc_type = GS_DOC_TYPE_UNKNOWN; ++ rewind(fp); ++ rc = fgets(buf,sizeof(buf),fp); ++ if (rc == NULL) ++ goto out; ++ ++ /* is PDF */ ++ if (strncmp(buf,"%PDF",4) == 0) { ++ doc_type = GS_DOC_TYPE_PDF; ++ goto out; ++ } ++ ++ /* is PS */ ++ if (strncmp(buf,"%!",2) == 0) { ++ doc_type = GS_DOC_TYPE_PS; ++ goto out; ++ } ++out: ++ return doc_type; ++} ++ ++static void ++parse_pdf_header_options(FILE *fp, gs_page_header *h) ++{ ++ char buf[4096]; ++ int i; ++ ++ rewind(fp); ++ /* skip until PDF start header */ ++ while (fgets(buf,sizeof(buf),fp) != 0) { ++ if (strncmp(buf,"%PDF",4) == 0) { ++ break; ++ } ++ } ++ for (i = 0;i < PDF_MAX_CHECK_COMMENT_LINES;i++) { ++ if (fgets(buf,sizeof(buf),fp) == 0) break; ++ if (strncmp(buf,"%%PDFTOPDFNumCopies",19) == 0) { ++ char *p; ++ ++ p = strchr(buf+19,':'); ++ h->NumCopies = atoi(p+1); ++ } else if (strncmp(buf,"%%PDFTOPDFCollate",17) == 0) { ++ char *p; ++ ++ p = strchr(buf+17,':'); ++ while (*p == ' ' || *p == '\t') p++; ++ if (strncasecmp(p,"true",4) == 0) { ++ h->Collate = CUPS_TRUE; ++ } else { ++ h->Collate = CUPS_FALSE; ++ } ++ } ++ } ++} ++ ++static void ++add_pdf_header_options(gs_page_header *h, cups_array_t *gs_args) ++{ ++ int i; ++ char tmpstr[1024]; ++ ++ /* Simple boolean, enumerated choice, numerical, and string parameters */ ++ if (h->MediaClass[0] |= '\0') { ++ snprintf(tmpstr, sizeof(tmpstr), "-sMediaClass=%s", h->MediaClass); ++ cupsArrayAdd(gs_args, strdup(tmpstr)); ++ } ++ if (h->MediaColor[0] |= '\0') { ++ snprintf(tmpstr, sizeof(tmpstr), "-sMediaColor=%s", h->MediaColor); ++ cupsArrayAdd(gs_args, strdup(tmpstr)); ++ } ++ if (h->MediaType[0] |= '\0') { ++ snprintf(tmpstr, sizeof(tmpstr), "-sMediaType=%s", h->MediaType); ++ cupsArrayAdd(gs_args, strdup(tmpstr)); ++ } ++ if (h->OutputType[0] |= '\0') { ++ snprintf(tmpstr, sizeof(tmpstr), "-sOutputType=%s", h->OutputType); ++ cupsArrayAdd(gs_args, strdup(tmpstr)); ++ } ++ if (h->AdvanceDistance) { ++ snprintf(tmpstr, sizeof(tmpstr), "-dAdvanceDistance=%d", ++ (unsigned)(h->AdvanceDistance)); ++ cupsArrayAdd(gs_args, strdup(tmpstr)); ++ } ++ if (h->AdvanceMedia) { ++ snprintf(tmpstr, sizeof(tmpstr), "-dAdvanceMedia=%d", ++ (unsigned)(h->AdvanceMedia)); ++ cupsArrayAdd(gs_args, strdup(tmpstr)); ++ } ++ if (h->Collate) { ++ cupsArrayAdd(gs_args, strdup("-dCollate")); ++ } ++ if (h->CutMedia) { ++ snprintf(tmpstr, sizeof(tmpstr), "-dCutMedia=%d", ++ (unsigned)(h->CutMedia)); ++ cupsArrayAdd(gs_args, strdup(tmpstr)); ++ } ++ if (h->Duplex) { ++ cupsArrayAdd(gs_args, strdup("-dDuplex")); ++ } ++ if ((h->HWResolution[0] != 100) || (h->HWResolution[1] != 100)) ++ snprintf(tmpstr, sizeof(tmpstr), "-r%dx%d", ++ (unsigned)(h->HWResolution[0]), (unsigned)(h->HWResolution[1])); ++ else ++ snprintf(tmpstr, sizeof(tmpstr), "-r100x100"); ++ cupsArrayAdd(gs_args, strdup(tmpstr)); ++ if (h->InsertSheet) { ++ cupsArrayAdd(gs_args, strdup("-dInsertSheet")); ++ } ++ if (h->Jog) { ++ snprintf(tmpstr, sizeof(tmpstr), "-dJog=%d", ++ (unsigned)(h->Jog)); ++ cupsArrayAdd(gs_args, strdup(tmpstr)); ++ } ++ if (h->LeadingEdge) { ++ snprintf(tmpstr, sizeof(tmpstr), "-dLeadingEdge=%d", ++ (unsigned)(h->LeadingEdge)); ++ cupsArrayAdd(gs_args, strdup(tmpstr)); ++ } ++ if (h->ManualFeed) { ++ cupsArrayAdd(gs_args, strdup("-dManualFeed")); ++ } ++ if (h->MediaPosition) { ++ snprintf(tmpstr, sizeof(tmpstr), "-dMediaPosition=%d", ++ (unsigned)(h->MediaPosition)); ++ cupsArrayAdd(gs_args, strdup(tmpstr)); ++ } ++ if (h->MediaWeight) { ++ snprintf(tmpstr, sizeof(tmpstr), "-dMediaWeight=%d", ++ (unsigned)(h->MediaWeight)); ++ cupsArrayAdd(gs_args, strdup(tmpstr)); ++ } ++ if (h->MirrorPrint) { ++ cupsArrayAdd(gs_args, strdup("-dMirrorPrint")); ++ } ++ if (h->NegativePrint) { ++ cupsArrayAdd(gs_args, strdup("-dNegativePrint")); ++ } ++ if (h->NumCopies != 1) { ++ snprintf(tmpstr, sizeof(tmpstr), "-dNumCopies=%d", ++ (unsigned)(h->NumCopies)); ++ cupsArrayAdd(gs_args, strdup(tmpstr)); ++ } ++ if (h->Orientation) { ++ snprintf(tmpstr, sizeof(tmpstr), "-dOrientation=%d", ++ (unsigned)(h->Orientation)); ++ cupsArrayAdd(gs_args, strdup(tmpstr)); ++ } ++ if (h->OutputFaceUp) { ++ cupsArrayAdd(gs_args, strdup("-dOutputFaceUp")); ++ } ++ if (h->PageSize[0] != 612) ++ snprintf(tmpstr, sizeof(tmpstr), "-dDEVICEWIDTHPOINTS=%d", ++ (unsigned)(h->PageSize[0])); ++ else ++ snprintf(tmpstr, sizeof(tmpstr), "-dDEVICEWIDTHPOINTS=612"); ++ cupsArrayAdd(gs_args, strdup(tmpstr)); ++ if (h->PageSize[1] != 792) ++ snprintf(tmpstr, sizeof(tmpstr), "-dDEVICEHEIGHTPOINTS=%d", ++ (unsigned)(h->PageSize[1])); ++ else ++ snprintf(tmpstr, sizeof(tmpstr), "-dDEVICEHEIGHTPOINTS=792"); ++ cupsArrayAdd(gs_args, strdup(tmpstr)); ++ if (h->Separations) { ++ cupsArrayAdd(gs_args, strdup("-dSeparations")); ++ } ++ if (h->TraySwitch) { ++ cupsArrayAdd(gs_args, strdup("-dTraySwitch")); ++ } ++ if (h->Tumble) { ++ cupsArrayAdd(gs_args, strdup("-dTumble")); ++ } ++ if (h->cupsMediaType) { ++ snprintf(tmpstr, sizeof(tmpstr), "-dcupsMediaType=%d", ++ (unsigned)(h->cupsMediaType)); ++ cupsArrayAdd(gs_args, strdup(tmpstr)); ++ } ++ if (h->cupsBitsPerColor != 1) ++ snprintf(tmpstr, sizeof(tmpstr), "-dcupsBitsPerColor=%d", ++ (unsigned)(h->cupsBitsPerColor)); ++ else ++ snprintf(tmpstr, sizeof(tmpstr), "-dcupsBitsPerColor=1"); ++ cupsArrayAdd(gs_args, strdup(tmpstr)); ++ if (h->cupsColorOrder != CUPS_ORDER_CHUNKED) ++ snprintf(tmpstr, sizeof(tmpstr), "-dcupsColorOrder=%d", ++ (unsigned)(h->cupsColorOrder)); ++ else ++ snprintf(tmpstr, sizeof(tmpstr), "-dcupsColorOrder=%d", ++ CUPS_ORDER_CHUNKED); ++ cupsArrayAdd(gs_args, strdup(tmpstr)); ++ if (h->cupsColorSpace != CUPS_CSPACE_K) ++ snprintf(tmpstr, sizeof(tmpstr), "-dcupsColorSpace=%d", ++ (unsigned)(h->cupsColorSpace)); ++ else ++ snprintf(tmpstr, sizeof(tmpstr), "-dcupsColorSpace=%d", ++ CUPS_CSPACE_K); ++ cupsArrayAdd(gs_args, strdup(tmpstr)); ++ if (h->cupsCompression) { ++ snprintf(tmpstr, sizeof(tmpstr), "-dcupsCompression=%d", ++ (unsigned)(h->cupsCompression)); ++ cupsArrayAdd(gs_args, strdup(tmpstr)); ++ } ++ if (h->cupsRowCount) { ++ snprintf(tmpstr, sizeof(tmpstr), "-dcupsRowCount=%d", ++ (unsigned)(h->cupsRowCount)); ++ cupsArrayAdd(gs_args, strdup(tmpstr)); ++ } ++ if (h->cupsRowFeed) { ++ snprintf(tmpstr, sizeof(tmpstr), "-dcupsRowFeed=%d", ++ (unsigned)(h->cupsRowFeed)); ++ cupsArrayAdd(gs_args, strdup(tmpstr)); ++ } ++ if (h->cupsRowStep) { ++ snprintf(tmpstr, sizeof(tmpstr), "-dcupsRowStep=%d", ++ (unsigned)(h->cupsRowStep)); ++ cupsArrayAdd(gs_args, strdup(tmpstr)); ++ } ++#ifdef CUPS_RASTER_SYNCv1 ++ if (h->cupsBorderlessScalingFactor != 1.0f) { ++ snprintf(tmpstr, sizeof(tmpstr), "-dcupsBorderlessScalingFactor=%.4f", ++ h->cupsBorderlessScalingFactor); ++ cupsArrayAdd(gs_args, strdup(tmpstr)); ++ } ++ for (i=0; i <= 15; i ++) ++ if (h->cupsInteger[i]) { ++ snprintf(tmpstr, sizeof(tmpstr), "-dcupsInteger%d=%d", ++ i, (unsigned)(h->cupsInteger[i])); ++ cupsArrayAdd(gs_args, strdup(tmpstr)); ++ } ++ for (i=0; i <= 15; i ++) ++ if (h->cupsReal[i]) { ++ snprintf(tmpstr, sizeof(tmpstr), "-dcupsReal%d=%.4f", ++ i, h->cupsReal[i]); ++ cupsArrayAdd(gs_args, strdup(tmpstr)); ++ } ++ for (i=0; i <= 15; i ++) ++ if (h->cupsString[i][0] != '\0') { ++ snprintf(tmpstr, sizeof(tmpstr), "-scupsString%d=%s", ++ i, h->cupsString[i]); ++ cupsArrayAdd(gs_args, strdup(tmpstr)); ++ } ++ if (h->cupsMarkerType[0] != '\0') { ++ snprintf(tmpstr, sizeof(tmpstr), "-scupsMarkerType=%s", ++ h->cupsMarkerType); ++ cupsArrayAdd(gs_args, strdup(tmpstr)); ++ } ++ if (h->cupsRenderingIntent[0] != '\0') { ++ snprintf(tmpstr, sizeof(tmpstr), "-scupsRenderingIntent=%s", ++ h->cupsRenderingIntent); ++ cupsArrayAdd(gs_args, strdup(tmpstr)); ++ } ++ if (h->cupsPageSizeName[0] != '\0') { ++ snprintf(tmpstr, sizeof(tmpstr), "-scupsPageSizeName=%s", ++ h->cupsPageSizeName); ++ cupsArrayAdd(gs_args, strdup(tmpstr)); ++ } ++#endif /* CUPS_RASTER_SYNCv1 */ ++} ++ ++static int ++gs_spawn (const char *filename, ++ cups_array_t *gs_args, ++ char **envp, ++ FILE *fp) ++{ ++ char *argument; ++ char buf[BUFSIZ]; ++ char **gsargv; ++ const char* apos; ++ int fds[2]; ++ int i; ++ int n; ++ int numargs; ++ int pid; ++ int status = 1; ++ ++ /* Put Ghostscript command line argument into an array for the "exec()" ++ call */ ++ numargs = cupsArrayCount(gs_args); ++ gsargv = calloc(numargs + 1, sizeof(char *)); ++ for (argument = (char *)cupsArrayFirst(gs_args), i = 0; argument; ++ argument = (char *)cupsArrayNext(gs_args), i++) { ++ gsargv[i] = argument; ++ } ++ gsargv[i] = NULL; ++ ++ /* Debug output: Full Ghostscript command line and environment variables */ ++ fprintf(stderr, "DEBUG: Ghostscript command line:"); ++ for (i = 0; gsargv[i]; i ++) { ++ if ((strchr(gsargv[i],' ')) || (strchr(gsargv[i],'\t'))) ++ apos = "'"; ++ else ++ apos = ""; ++ fprintf(stderr, " %s%s%s", apos, gsargv[i], apos); ++ } ++ fprintf(stderr, "\n"); ++ ++ for (i = 0; envp[i]; i ++) ++ fprintf(stderr, "DEBUG: envp[%d]=\"%s\"\n", i, envp[i]); ++ ++ /* Create a pipe for feeding the job into Ghostscript */ ++ if (pipe(fds)) ++ { ++ fds[0] = -1; ++ fds[1] = -1; ++ fprintf(stderr, "ERROR: Unable to establish pipe for Ghostscript call"); ++ goto out; ++ } ++ ++ /* Set the "close on exec" flag on each end of the pipe... */ ++ if (fcntl(fds[0], F_SETFD, fcntl(fds[0], F_GETFD) | FD_CLOEXEC)) ++ { ++ close(fds[0]); ++ close(fds[1]); ++ fds[0] = -1; ++ fds[1] = -1; ++ fprintf(stderr, "ERROR: Unable to set \"close on exec\" flag on read end of the pipe for Ghostscript call"); ++ goto out; ++ } ++ if (fcntl(fds[1], F_SETFD, fcntl(fds[1], F_GETFD) | FD_CLOEXEC)) ++ { ++ close(fds[0]); ++ close(fds[1]); ++ fprintf(stderr, "ERROR: Unable to set \"close on exec\" flag on write end of the pipe for Ghostscript call"); ++ goto out; ++ } ++ ++ if ((pid = fork()) == 0) ++ { ++ /* Couple pipe with STDIN of Ghostscript process */ ++ if (fds[0] != 0) { ++ close(0); ++ if (fds[0] > 0) ++ dup(fds[0]); ++ else { ++ fprintf(stderr, "ERROR: Unable to couple pipe with STDIN of Ghostscript process"); ++ goto out; ++ } ++ } ++ ++ /* Execute Ghostscript command line ... */ ++ execve(filename, gsargv, envp); ++ perror(filename); ++ goto out; ++ } ++ ++ /* Feed job data into Ghostscript */ ++ while ((n = fread(buf, 1, BUFSIZ, fp)) > 0) { ++ if (write(fds[1], buf, n) != n) { ++ fprintf(stderr, "ERROR: Can't feed job data into Ghostscript"); ++ goto out; ++ } ++ } ++ close (fds[1]); ++ ++ if (waitpid (pid, &status, 0) == -1) { ++ perror ("gs"); ++ goto out; ++ } ++out: ++ free(gsargv); ++ return status; ++} ++ ++static char * ++get_ppd_icc_fallback (ppd_file_t *ppd, char **qualifier) ++{ ++ 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) { ++ fprintf(stderr, "INFO: no profiles specified in PPD\n"); ++ goto out; ++ } ++ ++ /* try to find a profile that matches the qualifier exactly */ ++ for (;attr != NULL; attr = ppdFindNextAttr(ppd, profile_key, NULL)) { ++ fprintf(stderr, "INFO: found profile %s in PPD with qualifier '%s'\n", ++ 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)); ++ ++ /* check the file exists */ ++ if (access(full_path, 0)) { ++ fprintf(stderr, "INFO: found profile %s in PPD that does not exist\n", ++ 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) { ++ fprintf(stderr, "INFO: no profiles in PPD for qualifier '%s'\n", ++ qualifer_tmp); ++ goto out; ++ } ++ ++out: ++ return icc_profile; ++} ++ ++int ++main (int argc, char **argv, char *envp[]) ++{ ++ char buf[BUFSIZ]; ++ char *icc_profile = NULL; ++ char **qualifier = NULL; ++ char *tmp; ++ char tmpstr[1024]; ++ const char *t = NULL; ++ cups_array_t *gs_args = NULL; ++ cups_option_t *options = NULL; ++ FILE *fp = NULL; ++ GsDocType doc_type; ++ gs_page_header h; ++ int fd; ++ int i; ++ int n; ++ int num_options; ++ int status = 1; ++ ppd_file_t *ppd = NULL; ++ ++ if (argc < 6 || argc > 7) { ++ fprintf(stderr, "ERROR: %s job-id user title copies options [file]\n", ++ argv[0]); ++ goto out; ++ } ++ ++ num_options = cupsParseOptions(argv[5], 0, &options); ++ ++ t = getenv("PPD"); ++ if ((ppd = ppdOpenFile(t)) == NULL) { ++ fprintf(stderr, "ERROR: Failed to open PPD: %s", t); ++ goto out; ++ } ++ ++ ppdMarkDefaults (ppd); ++ cupsMarkOptions (ppd, num_options, options); ++ ++ if (argc == 6) { ++ /* stdin */ ++ ++ fd = cupsTempFd(buf,BUFSIZ); ++ if (fd < 0) { ++ fprintf(stderr, "ERROR: Can't create temporary file"); ++ goto out; ++ } ++ /* remove name */ ++ unlink(buf); ++ ++ /* copy stdin to the tmp file */ ++ while ((n = read(0,buf,BUFSIZ)) > 0) { ++ if (write(fd,buf,n) != n) { ++ fprintf(stderr, "ERROR: Can't copy stdin to temporary file"); ++ close(fd); ++ goto out; ++ } ++ } ++ if (lseek(fd,0,SEEK_SET) < 0) { ++ fprintf(stderr, "ERROR: Can't rewind temporary file"); ++ close(fd); ++ goto out; ++ } ++ ++ if ((fp = fdopen(fd,"rb")) == 0) { ++ fprintf(stderr, "ERROR: Can't fdopen temporary file"); ++ close(fd); ++ goto out; ++ } ++ } else { ++ /* argc == 7 filename is specified */ ++ ++ if ((fp = fopen(argv[6],"rb")) == 0) { ++ fprintf(stderr, "ERROR: Can't open input file %s",argv[6]); ++ goto out; ++ } ++ } ++ ++ /* find out file type */ ++ doc_type = parse_doc_type(fp); ++ if (doc_type == GS_DOC_TYPE_UNKNOWN) { ++ fprintf(stderr, "ERROR: Can't detect file type"); ++ goto out; ++ } ++ ++ qualifier = colord_get_qualifier_for_ppd (ppd); ++ if (qualifier != NULL) { ++ ++ fprintf(stderr, "DEBUG: PPD uses qualifier '%s.%s.%s'\n", ++ qualifier[0], qualifier[1], qualifier[2]); ++ icc_profile = colord_get_profile_for_device_id (getenv("PRINTER"), ++ (const char**) qualifier); ++ ++ /* fall back to the PPD */ ++ if (icc_profile == NULL) ++ icc_profile = get_ppd_icc_fallback (ppd, qualifier); ++ ++ if(icc_profile != NULL) ++ fprintf(stderr, "DEBUG: Using ICC Profile '%s'\n", icc_profile); ++ } ++ ++ /* Ghostscript parameters */ ++ gs_args = cupsArrayNew(NULL, NULL); ++ if (!gs_args) ++ { ++ fprintf(stderr, "ERROR: Unable to allocate memory for Ghostscript arguments array\n"); ++ exit(1); ++ } ++ ++ /* Part of Ghostscript command line which is not dependent on the job and/or ++ the driver */ ++ snprintf(tmpstr, sizeof(tmpstr), "%s/%s", BINDIR, GS); ++ cupsArrayAdd(gs_args, strdup(tmpstr)); ++ cupsArrayAdd(gs_args, strdup("-dQUIET")); ++ /*cupsArrayAdd(gs_args, strdup("-dDEBUG"));*/ ++ cupsArrayAdd(gs_args, strdup("-dPARANOIDSAFER")); ++ cupsArrayAdd(gs_args, strdup("-dNOPAUSE")); ++ cupsArrayAdd(gs_args, strdup("-dBATCH")); ++ if (doc_type == GS_DOC_TYPE_PS) ++ cupsArrayAdd(gs_args, strdup("-dNOMEDIAATTRS")); ++ cupsArrayAdd(gs_args, strdup("-sDEVICE=cups")); ++ cupsArrayAdd(gs_args, strdup("-sstdout=%stderr")); ++ cupsArrayAdd(gs_args, strdup("-sOutputFile=%stdout")); ++ ++ /* setPDF specific options */ ++ if (doc_type == GS_DOC_TYPE_PDF) { ++ cupsRasterInterpretPPD(&h,ppd,num_options,options,0); ++ parse_pdf_header_options(fp, &h); ++ ++ /* fixed other values that pdftopdf handles */ ++ h.MirrorPrint = CUPS_FALSE; ++ h.Orientation = CUPS_ORIENT_0; ++ ++ /* get all the data from the header and pass it to ghostscript */ ++ add_pdf_header_options (&h, gs_args); ++ } ++ ++ /* CUPS font path */ ++ if ((t = getenv("CUPS_FONTPATH")) == NULL) ++ t = CUPS_FONTPATH; ++ snprintf(tmpstr, sizeof(tmpstr), "-I%s", t); ++ cupsArrayAdd(gs_args, strdup(tmpstr)); ++ ++ /* set the device output ICC profile */ ++ if(icc_profile != NULL) { ++ snprintf(tmpstr, sizeof(tmpstr), "-sOutputICCProfile=%s", icc_profile); ++ cupsArrayAdd(gs_args, strdup(tmpstr)); ++ } ++ ++ /* Switch to taking PostScript commands on the Ghostscript command line */ ++ cupsArrayAdd(gs_args, strdup("-c")); ++ ++ if ((t = cupsGetOption("profile", num_options, options)) != NULL) { ++ snprintf(tmpstr, sizeof(tmpstr), "<>setpagedevice", t); ++ cupsArrayAdd(gs_args, strdup(tmpstr)); ++ } ++ ++ /* Mark the end of PostScript commands supplied on the Ghostscript command ++ line (with the "-c" option), so that we can supply the input file name */ ++ cupsArrayAdd(gs_args, strdup("-f")); ++ ++ /* Let Ghostscript read from STDIN */ ++ cupsArrayAdd(gs_args, strdup("-_")); ++ ++ /* Execute Ghostscript command line ... */ ++ snprintf(tmpstr, sizeof(tmpstr), "%s/%s", BINDIR, GS); ++ ++ /* call Ghostscript */ ++ rewind(fp); ++ status = gs_spawn (tmpstr, gs_args, envp, fp); ++out: ++ if (fp) ++ fclose(fp); ++ if (qualifier != NULL) { ++ for (i=0; qualifier[i] != NULL; i++) ++ free(qualifier[i]); ++ free(qualifier); ++ } ++ if (gs_args) { ++ while ((tmp = cupsArrayFirst(gs_args)) != NULL) { ++ cupsArrayRemove(gs_args,tmp); ++ free(tmp); ++ } ++ cupsArrayDelete(gs_args); ++ } ++ free(icc_profile); ++ if (ppd) ++ ppdClose(ppd); ++ return status; ++} +diff -urNp ghostscript-9.01.old/cups/gstoraster.convs ghostscript-9.01/cups/gstoraster.convs +--- ghostscript-9.01.old/cups/gstoraster.convs 1970-01-01 01:00:00.000000000 +0100 ++++ ghostscript-9.01/cups/gstoraster.convs 2011-03-08 10:48:11.026721536 +0000 +@@ -0,0 +1,30 @@ ++# Copyright (c) 2008, Till Kamppeter ++# Copyright (c) 2011, Richard Hughes ++# ++# Permission is hereby granted, free of charge, to any person obtaining ++# a copy of this software and associated documentation files (the ++# "Software"), to deal in the Software without restriction, including ++# without limitation the rights to use, copy, modify, merge, publish, ++# distribute, sublicense, and/or sell copies of the Software, and to ++# permit persons to whom the Software is furnished to do so, subject to ++# the following conditions: ++# ++# The above copyright notice and this permission notice shall be included ++# in all copies or substantial portions of the Software. ++# ++# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ++# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ++# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ++# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ++# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, ++# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE ++# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ++# ++# MIT Open Source License - http://www.opensource.org/ ++# ++# $Id: pdftoraster.convs 8803 2008-06-24 14:16:29Z till $ ++# ++# CUPS file conversion rules for gstoraster filter ++ ++application/vnd.cups-pdf application/vnd.cups-raster 66 gstoraster ++application/vnd.cups-postscript application/vnd.cups-raster 100 gstoraster +diff -urNp ghostscript-9.01.old/Makefile.in ghostscript-9.01/Makefile.in +--- ghostscript-9.01.old/Makefile.in 2011-03-08 10:47:24.951721587 +0000 ++++ ghostscript-9.01/Makefile.in 2011-03-08 10:48:11.020721446 +0000 +@@ -140,7 +140,7 @@ GENOPT= + # -DHAVE_SETLOCALE + # call setlocale(LC_CTYPE) when running as a standalone app + +-CAPOPT= @HAVE_MKSTEMP@ @HAVE_HYPOT@ @HAVE_FILE64@ @HAVE_MKSTEMP64@ @HAVE_FONTCONFIG@ @HAVE_LIBIDN@ @HAVE_SETLOCALE@ ++CAPOPT= @HAVE_MKSTEMP@ @HAVE_HYPOT@ @HAVE_FILE64@ @HAVE_MKSTEMP64@ @HAVE_FONTCONFIG@ @HAVE_LIBIDN@ @HAVE_SETLOCALE@ @HAVE_DBUS@ + + # Define the name of the executable file. + +@@ -339,6 +339,10 @@ XCFLAGS=@DYNAMIC_FLAGS@ + FONTCONFIG_CFLAGS=@FONTCONFIG_CFLAGS@ + FONTCONFIG_LIBS=@FONTCONFIG_LIBS@ + ++# DBus flags, used by cups.mak ++DBUS_CFLAGS=@DBUS_CFLAGS@ ++DBUS_LIBS=@DBUS_LIBS@ ++ + # defines from autoconf; note that we don't use these at present. + ACDEFS=@DEFS@ + diff --git a/ghostscript-ijs-automake-ver.patch b/ghostscript-ijs-automake-ver.patch new file mode 100644 index 0000000..b27e277 --- /dev/null +++ b/ghostscript-ijs-automake-ver.patch @@ -0,0 +1,12 @@ +diff -urNp ghostscript-9.01.old/ijs/Makefile.am ghostscript-9.01/ijs/Makefile.am +--- ghostscript-9.01.old/ijs/Makefile.am 2011-03-08 10:09:33.055722164 +0000 ++++ ghostscript-9.01/ijs/Makefile.am 2011-03-08 10:09:37.390722163 +0000 +@@ -24,7 +24,7 @@ + + ## Process this file with automake to produce Makefile.in. + +-AUTOMAKE_OPTIONS = 1.6 foreign dist-bzip2 no-dependencies ++AUTOMAKE_OPTIONS = 1.8 foreign dist-bzip2 no-dependencies + + @SET_MAKE@ + diff --git a/ghostscript.spec b/ghostscript.spec index bb40900..7a650c1 100644 --- a/ghostscript.spec +++ b/ghostscript.spec @@ -5,7 +5,7 @@ Summary: A PostScript interpreter and renderer Name: ghostscript Version: %{gs_ver} -Release: 1%{?dist} +Release: 2%{?dist} # Included CMap data is Redistributable, no modification permitted, # see http://bugzilla.redhat.com/487510 @@ -19,6 +19,7 @@ Source4: cidfmap Patch1: ghostscript-multilib.patch Patch2: ghostscript-scripts.patch Patch3: ghostscript-noopt.patch +Patch4: ghostscript-ijs-automake-ver.patch Patch5: ghostscript-runlibfileifexists.patch Patch7: ghostscript-pksmraw.patch Patch8: ghostscript-jbig2dec-nullderef.patch @@ -28,9 +29,11 @@ Patch21: ghostscript-jbig2-image-refcount.patch Patch27: ghostscript-Fontmap.local.patch Patch28: ghostscript-iccprofiles-initdir.patch Patch29: ghostscript-gdevcups-debug-uninit.patch +Patch30: ghostscript-colord.patch Requires: urw-fonts >= 1.1, ghostscript-fonts Requires: poppler-data +Requires: colord BuildRequires: xz BuildRequires: libjpeg-devel, libXt-devel BuildRequires: zlib-devel, libpng-devel, unzip, gtk2-devel @@ -41,6 +44,7 @@ BuildRequires: libtiff-devel BuildRequires: cups-devel >= 1.1.13 BuildRequires: libtool BuildRequires: jasper-devel +BuildRequires: dbus-devel BuildRequires: poppler-data %{?_with_freetype:BuildRequires: freetype-devel} BuildRoot: %{_tmppath}/%{name}-%{gs_ver}-root @@ -113,6 +117,10 @@ rm -rf libpng zlib jpeg jasper # Build igcref.c with -O0 to work around bug #150771. %patch3 -p1 -b .noopt +# Fix ./autgen.sh in ijs sub-project +# See http://bugs.ghostscript.com/show_bug.cgi?id=692040 for details. +%patch4 -p1 -b .ijs-automake-ver + # Define .runlibfileifexists. %patch5 -p1 @@ -143,6 +151,9 @@ rm -rf libpng zlib jpeg jasper # gdevcups: don't use uninitialized variables in debugging output. %patch29 -p1 -b .gdevcups-debug-uninit +# colord: use colord to get the correct device profile +%patch30 -p1 -b .colord + # Convert manual pages to UTF-8 from8859_1() { iconv -f iso-8859-1 -t utf-8 < "$1" > "${1}_" @@ -176,6 +187,7 @@ for path in \ do FONTPATH="$FONTPATH${FONTPATH:+:}$path" done +autoconf --force %configure --with-ijs --enable-dynamic --with-fontpath="$FONTPATH" \ --with-drivers=ALL --disable-compile-inits --with-system-libtiff \ CFLAGS="$CFLAGS $EXTRACFLAGS" @@ -334,6 +346,9 @@ rm -rf $RPM_BUILD_ROOT %{_libdir}/libgs.so %changelog +* Thu Feb 10 2011 Richard Hughes 9.01-2 +- Backport a patch from svn trunk to enable colord support. + * Thu Feb 10 2011 Tim Waugh 9.01-1 - 9.01. No longer needed gdevcups-691733, glyph-stretch-691920, icc-fix, scan_token, or system-jasper patches.