1278 lines
40 KiB
Diff
1278 lines
40 KiB
Diff
diff -up ghostscript-9.01/configure.ac.colord ghostscript-9.01/configure.ac
|
|
--- ghostscript-9.01/configure.ac.colord 2011-02-02 14:12:15.000000000 +0000
|
|
+++ ghostscript-9.01/configure.ac 2011-03-10 13:48:17.599512567 +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 -up ghostscript-9.01/cups/colord.c.colord ghostscript-9.01/cups/colord.c
|
|
--- ghostscript-9.01/cups/colord.c.colord 2011-03-10 13:48:17.600512671 +0000
|
|
+++ ghostscript-9.01/cups/colord.c 2011-03-10 13:48:17.600512671 +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 -up ghostscript-9.01/cups/colord.h.colord ghostscript-9.01/cups/colord.h
|
|
--- ghostscript-9.01/cups/colord.h.colord 2011-03-10 13:48:17.601512775 +0000
|
|
+++ ghostscript-9.01/cups/colord.h 2011-03-10 13:48:17.601512775 +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 -up ghostscript-9.01/cups/cups.mak.colord ghostscript-9.01/cups/cups.mak
|
|
--- ghostscript-9.01/cups/cups.mak.colord 2011-03-10 13:48:17.573509871 +0000
|
|
+++ ghostscript-9.01/cups/cups.mak 2011-03-10 13:48:17.602512879 +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 -up ghostscript-9.01/cups/gstoraster.c.colord ghostscript-9.01/cups/gstoraster.c
|
|
--- ghostscript-9.01/cups/gstoraster.c.colord 2011-03-10 13:48:17.604513086 +0000
|
|
+++ ghostscript-9.01/cups/gstoraster.c 2011-03-10 14:40:00.005019314 +0000
|
|
@@ -0,0 +1,712 @@
|
|
+/* -*- 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) {
|
|
+ const char *env_printer = getenv("PRINTER");
|
|
+ char *device_id;
|
|
+
|
|
+ if (env_printer) {
|
|
+ device_id = malloc (5 + strlen (env_printer) + 1);
|
|
+ if (device_id) {
|
|
+ strcpy (device_id, "cups-");
|
|
+ strcpy (device_id + 5, env_printer);
|
|
+ fprintf(stderr, "DEBUG: PPD uses qualifier '%s.%s.%s'\n",
|
|
+ qualifier[0], qualifier[1], qualifier[2]);
|
|
+ icc_profile = colord_get_profile_for_device_id (device_id,
|
|
+ (const char**) qualifier);
|
|
+ free (device_id);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* 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 -up ghostscript-9.01/cups/gstoraster.convs.colord ghostscript-9.01/cups/gstoraster.convs
|
|
--- ghostscript-9.01/cups/gstoraster.convs.colord 2011-03-10 13:48:17.605513190 +0000
|
|
+++ ghostscript-9.01/cups/gstoraster.convs 2011-03-10 13:48:17.605513190 +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 -up ghostscript-9.01/Makefile.in.colord ghostscript-9.01/Makefile.in
|
|
--- ghostscript-9.01/Makefile.in.colord 2011-02-02 14:12:15.000000000 +0000
|
|
+++ ghostscript-9.01/Makefile.in 2011-03-10 13:48:17.607513397 +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@
|
|
|