[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