[ghostscript] Backport a patch from svn trunk to enable colord support.
Richard Hughes
rhughes at fedoraproject.org
Tue Mar 8 11:30:42 UTC 2011
commit 63ba0ce8b38645aac83fa905c128b5859f22a81d
Author: Richard Hughes <richard at hughsie.com>
Date: Tue Mar 8 11:29:45 2011 +0000
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 deletions(-)
---
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 <cups/raster.h>
++#include <stdio.h>
++#include <sys/types.h>
++
++#ifdef HAVE_DBUS
++ #include <dbus/dbus.h>
++#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 <cups/raster.h>
++
++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 <stdio.h>
++#include <stdlib.h>
++#include <cups/cups.h>
++#include <stdarg.h>
++#include <fcntl.h>
++#include <cups/raster.h>
++#include <sys/types.h>
++#include <sys/wait.h>
++
++#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), "<</cupsProfile(%s)>>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 <rhughes at redhat.com> 9.01-2
+- Backport a patch from svn trunk to enable colord support.
+
* Thu Feb 10 2011 Tim Waugh <twaugh at redhat.com> 9.01-1
- 9.01. No longer needed gdevcups-691733, glyph-stretch-691920,
icc-fix, scan_token, or system-jasper patches.
More information about the scm-commits
mailing list