diff -urNp ghostscript-9.01.old/configure.ac ghostscript-9.01/configure.ac --- ghostscript-9.01.old/configure.ac 2011-03-08 10:47:24.851721587 +0000 +++ ghostscript-9.01/configure.ac 2011-03-08 10:48:11.022721481 +0000 @@ -423,6 +423,37 @@ AC_SUBST(HAVE_FONTCONFIG) AC_SUBST(FONTCONFIG_CFLAGS) AC_SUBST(FONTCONFIG_LIBS) +dnl DBus support +HAVE_DBUS="" +DBUS_CFLAGS="" +DBUS_LIBS="" +AC_ARG_ENABLE([dbus], AC_HELP_STRING([--disable-dbus], + [Do not use dbus to communicate with external services])) +if test "$enable_dbus" != "no"; then + if test "x$PKGCONFIG" != x; then + AC_MSG_CHECKING(for dbus with pkg-config) + if $PKGCONFIG --exists dbus-1; then + AC_MSG_RESULT(yes) + DBUS_CFLAGS="$CFLAGS `$PKGCONFIG --cflags dbus-1`" + DBUS_LIBS="`$PKGCONFIG --libs dbus-1`" + HAVE_DBUS=-DHAVE_DBUS + else + AC_MSG_RESULT(no) + fi + fi + if test -z "$HAVE_DBUS"; then + AC_CHECK_LIB([dbus], [dbus_message_iter_get_basic], [ + AC_CHECK_HEADER([dbus-1.0/dbus/dbus.h], [ + DBUS_LIBS="-ldbus-1 -lpthread -lrt" + HAVE_DBUS="-DHAVE_DBUS" + ]) + ]) + fi +fi +AC_SUBST(HAVE_DBUS) +AC_SUBST(DBUS_CFLAGS) +AC_SUBST(DBUS_LIBS) + AC_CHECK_LIB(dl, dlopen) AC_ARG_ENABLE([freetype], AC_HELP_STRING([--disable-freetype], @@ -1439,6 +1470,6 @@ dnl ------------------------------------ AC_SUBST(OPT_CFLAGS) AC_SUBST(DBG_CFLAGS) AC_SUBST(GCFLAGS) -AC_OUTPUT(Makefile cups/pstopxl cups/pstoraster) +AC_OUTPUT(Makefile cups/pstopxl) -chmod +x cups/pstopxl cups/pstoraster +chmod +x cups/pstopxl diff -urNp ghostscript-9.01.old/cups/colord.c ghostscript-9.01/cups/colord.c --- ghostscript-9.01.old/cups/colord.c 1970-01-01 01:00:00.000000000 +0100 +++ ghostscript-9.01/cups/colord.c 2011-03-08 10:48:11.023721494 +0000 @@ -0,0 +1,367 @@ +/* +Copyright (c) 2011, Tim Waugh +Copyright (c) 2011, Richard Hughes + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +MIT Open Source License - http://www.opensource.org/ + +*/ + +/* $Id$ */ + +/* Common routines for accessing the colord CMS framework */ + +#include +#include +#include + +#ifdef HAVE_DBUS + #include +#endif + +#include "colord.h" + +#define QUAL_COLORSPACE 0 +#define QUAL_MEDIA 1 +#define QUAL_RESOLUTION 2 +#define QUAL_SIZE 3 + +char ** +colord_get_qualifier_for_ppd (ppd_file_t *ppd) +{ + char q_keyword[PPD_MAX_NAME]; + char **tuple = NULL; + const char *q1_choice; + const char *q2_choice; + const char *q3_choice; + ppd_attr_t *attr; + ppd_attr_t *q1_attr; + ppd_attr_t *q2_attr; + ppd_attr_t *q3_attr; + + /* get colorspace */ + if ((attr = ppdFindAttr (ppd, "cupsICCQualifier1", NULL)) != NULL && + attr->value && attr->value[0]) + { + snprintf (q_keyword, sizeof (q_keyword), "Default%s", attr->value); + q1_attr = ppdFindAttr (ppd, q_keyword, NULL); + } + else if ((q1_attr = ppdFindAttr (ppd, "DefaultColorModel", NULL)) == NULL) + q1_attr = ppdFindAttr (ppd, "DefaultColorSpace", NULL); + + if (q1_attr && q1_attr->value && q1_attr->value[0]) + q1_choice = q1_attr->value; + else + q1_choice = ""; + + /* get colorspace */ + if ((attr = ppdFindAttr (ppd, "cupsICCQualifier2", NULL)) != NULL && + attr->value && attr->value[0]) + { + snprintf (q_keyword, sizeof (q_keyword), "Default%s", attr->value); + q1_attr = ppdFindAttr (ppd, q_keyword, NULL); + } + else if ((q1_attr = ppdFindAttr (ppd, "DefaultColorModel", NULL)) == NULL) + q1_attr = ppdFindAttr (ppd, "DefaultColorSpace", NULL); + + if (q1_attr && q1_attr->value && q1_attr->value[0]) + q1_choice = q1_attr->value; + else + q1_choice = ""; + + /* get media */ + if ((attr = ppdFindAttr(ppd, "cupsICCQualifier2", NULL)) != NULL && + attr->value && attr->value[0]) + { + snprintf(q_keyword, sizeof(q_keyword), "Default%s", attr->value); + q2_attr = ppdFindAttr(ppd, q_keyword, NULL); + } + else + q2_attr = ppdFindAttr(ppd, "DefaultMediaType", NULL); + + if (q2_attr && q2_attr->value && q2_attr->value[0]) + q2_choice = q2_attr->value; + else + q2_choice = ""; + + /* get resolution */ + if ((attr = ppdFindAttr(ppd, "cupsICCQualifier3", NULL)) != NULL && + attr->value && attr->value[0]) + { + snprintf(q_keyword, sizeof(q_keyword), "Default%s", attr->value); + q3_attr = ppdFindAttr(ppd, q_keyword, NULL); + } + else + q3_attr = ppdFindAttr(ppd, "DefaultResolution", NULL); + + if (q3_attr && q3_attr->value && q3_attr->value[0]) + q3_choice = q3_attr->value; + else + q3_choice = ""; + + /* return a NULL terminated array so we don't have to break it up later */ + tuple = calloc(QUAL_SIZE + 1, sizeof(char*)); + tuple[QUAL_COLORSPACE] = strdup(q1_choice); + tuple[QUAL_MEDIA] = strdup(q2_choice); + tuple[QUAL_RESOLUTION] = strdup(q3_choice); + return tuple; +} + +#ifdef HAVE_DBUS + +static char * +get_filename_for_profile_path (DBusConnection *con, + const char *object_path) +{ + char *filename = NULL; + const char *interface = "org.freedesktop.ColorManager.Profile"; + const char *property = "Filename"; + const char *tmp; + DBusError error; + DBusMessageIter args; + DBusMessage *message = NULL; + DBusMessage *reply = NULL; + DBusMessageIter sub; + + message = dbus_message_new_method_call("org.freedesktop.ColorManager", + object_path, + "org.freedesktop.DBus.Properties", + "Get"); + + dbus_message_iter_init_append(message, &args); + dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &interface); + dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &property); + + /* send syncronous */ + dbus_error_init(&error); + fprintf(stderr, "DEBUG: Calling %s.Get(%s)\n", interface, property); + reply = dbus_connection_send_with_reply_and_block(con, + message, + -1, + &error); + if (reply == NULL) { + fprintf(stderr, "DEBUG: Failed to send: %s:%s\n", + error.name, error.message); + dbus_error_free(&error); + goto out; + } + + /* get reply data */ + dbus_message_iter_init(reply, &args); + if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_VARIANT) { + fprintf(stderr, "DEBUG: Incorrect reply type\n"); + goto out; + } + + dbus_message_iter_recurse(&args, &sub); + dbus_message_iter_get_basic(&sub, &tmp); + filename = strdup(tmp); +out: + if (message != NULL) + dbus_message_unref(message); + if (reply != NULL) + dbus_message_unref(reply); + return filename; +} + +static char * +get_profile_for_device_path (DBusConnection *con, + const char *object_path, + const char **split) +{ + char **key = NULL; + char *profile = NULL; + char str[256]; + const char *tmp; + DBusError error; + DBusMessageIter args; + DBusMessageIter entry; + DBusMessage *message = NULL; + DBusMessage *reply = NULL; + int i = 0; + const int max_keys = 7; + + message = dbus_message_new_method_call("org.freedesktop.ColorManager", + object_path, + "org.freedesktop.ColorManager.Device", + "GetProfileForQualifiers"); + dbus_message_iter_init_append(message, &args); + + /* create the fallbacks */ + key = calloc(max_keys + 1, sizeof(char*)); + + /* exact match */ + i = 0; + snprintf(str, sizeof(str), "%s.%s.%s", + split[QUAL_COLORSPACE], + split[QUAL_MEDIA], + split[QUAL_RESOLUTION]); + key[i++] = strdup(str); + snprintf(str, sizeof(str), "%s.%s.*", + split[QUAL_COLORSPACE], + split[QUAL_MEDIA]); + key[i++] = strdup(str); + snprintf(str, sizeof(str), "%s.*.%s", + split[QUAL_COLORSPACE], + split[QUAL_RESOLUTION]); + key[i++] = strdup(str); + snprintf(str, sizeof(str), "%s.*.*", + split[QUAL_COLORSPACE]); + key[i++] = strdup(str); + key[i++] = strdup("*"); + dbus_message_iter_open_container(&args, + DBUS_TYPE_ARRAY, + "s", + &entry); + for (i=0; key[i] != NULL; i++) { + dbus_message_iter_append_basic(&entry, + DBUS_TYPE_STRING, + &key[i]); + } + dbus_message_iter_close_container(&args, &entry); + + /* send syncronous */ + dbus_error_init(&error); + fprintf(stderr, "DEBUG: Calling GetProfileForQualifiers(%s...)\n", key[0]); + reply = dbus_connection_send_with_reply_and_block(con, + message, + -1, + &error); + if (reply == NULL) { + fprintf(stderr, "DEBUG: Failed to send: %s:%s\n", + error.name, error.message); + dbus_error_free(&error); + goto out; + } + + /* get reply data */ + dbus_message_iter_init(reply, &args); + if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH) { + fprintf(stderr, "DEBUG: Incorrect reply type\n"); + goto out; + } + dbus_message_iter_get_basic(&args, &tmp); + fprintf(stderr, "DEBUG: Found profile %s\n", tmp); + + /* get filename */ + profile = get_filename_for_profile_path(con, tmp); + +out: + if (message != NULL) + dbus_message_unref(message); + if (reply != NULL) + dbus_message_unref(reply); + if (key != NULL) { + for (i=0; i < max_keys; i++) + free(key[i]); + free(key); + } + return profile; +} + +static char * +get_profile_for_device_id (DBusConnection *con, + const char *device_id, + const char **qualifier_tuple) +{ + char *profile = NULL; + const char *device_path_tmp; + DBusError error; + DBusMessageIter args; + DBusMessage *message = NULL; + DBusMessage *reply = NULL; + + message = dbus_message_new_method_call("org.freedesktop.ColorManager", + "/org/freedesktop/ColorManager", + "org.freedesktop.ColorManager", + "FindDeviceById"); + dbus_message_iter_init_append(message, &args); + dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, &device_id); + + /* send syncronous */ + dbus_error_init(&error); + fprintf(stderr, "DEBUG: Calling FindDeviceById(%s)\n", device_id); + reply = dbus_connection_send_with_reply_and_block(con, + message, + -1, + &error); + if (reply == NULL) { + fprintf(stderr, "DEBUG: Failed to send: %s:%s\n", + error.name, error.message); + dbus_error_free(&error); + goto out; + } + + /* get reply data */ + dbus_message_iter_init(reply, &args); + if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH) { + fprintf(stderr, "DEBUG: Incorrect reply type\n"); + goto out; + } + dbus_message_iter_get_basic(&args, &device_path_tmp); + fprintf(stderr, "DEBUG: Found device %s\n", device_path_tmp); + profile = get_profile_for_device_path(con, device_path_tmp, qualifier_tuple); +out: + if (message != NULL) + dbus_message_unref(message); + if (reply != NULL) + dbus_message_unref(reply); + return profile; +} + +char * +colord_get_profile_for_device_id (const char *device_id, + const char **qualifier_tuple) +{ + DBusConnection *con; + char *filename = NULL; + + /* connect to system bus */ + con = dbus_bus_get(DBUS_BUS_SYSTEM, NULL); + if (con == NULL) { + fprintf(stderr, "ERROR: Failed to connect to system bus\n"); + goto out; + } + + /* get the best profile for the device */ + filename = get_profile_for_device_id (con, device_id, qualifier_tuple); + if (filename == NULL) { + fprintf(stderr, "DEBUG: Failed to get profile filename!\n"); + goto out; + } + fprintf(stderr, "DEBUG: Use profile filename: '%s'\n", filename); +out: + if (con != NULL) + dbus_connection_unref(con); + return filename; +} + +#else + +char * +colord_get_profile_for_device_id (const char *device_id, + const char **qualifier_tuple) +{ + fprintf(stderr, "WARN: not compiled with DBus support\n"); + return NULL; +} + +#endif diff -urNp ghostscript-9.01.old/cups/colord.h ghostscript-9.01/cups/colord.h --- ghostscript-9.01.old/cups/colord.h 1970-01-01 01:00:00.000000000 +0100 +++ ghostscript-9.01/cups/colord.h 2011-03-08 10:48:11.024721504 +0000 @@ -0,0 +1,35 @@ +/* +Copyright (c) 2011, Richard Hughes + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +MIT Open Source License - http://www.opensource.org/ + +*/ + +/* $Id$ */ + +/* Common routines for accessing the colord CMS framework */ + +#include + +char **colord_get_qualifier_for_ppd (ppd_file_t *ppd); +char *colord_get_profile_for_device_id (const char *device_id, + const char **qualifier_tuple); diff -urNp ghostscript-9.01.old/cups/cups.mak ghostscript-9.01/cups/cups.mak --- ghostscript-9.01.old/cups/cups.mak 2011-03-08 10:47:23.796721588 +0000 +++ ghostscript-9.01/cups/cups.mak 2011-03-08 10:50:01.360721549 +0000 @@ -35,30 +35,30 @@ cups_= $(GLOBJ)gdevcups.$(OBJ) # CUPSDATA=`cups-config --datadir` # CUPSPDFTORASTER= 1 if CUPS is new enough (cups-config --version) -PDFTORASTER_XE=$(BINDIR)$(D)pdftoraster$(XE) +GSTORASTER_XE=$(BINDIR)$(D)gstoraster$(XE) -cups: pdftoraster -pdftoraster: $(PDFTORASTER_XE) -pdftoraster_=cups/pdftoraster.c +cups: gstoraster -$(PDFTORASTER_XE): $(pdftoraster_) +gstoraster: $(GSTORASTER_XE) +gstoraster_=cups/gstoraster.c cups/colord.c + +$(GSTORASTER_XE): $(gstoraster_) if [ "$(CUPSPDFTORASTER)" = "1" ]; then \ - $(GLCC) $(LDFLAGS) -DBINDIR='"$(bindir)"' -DGS='"$(GS)"' -o $@ $(pdftoraster_) `cups-config --image --ldflags --libs`; \ + $(GLCC) $(LDFLAGS) $(DBUS_CFLAGS) -DBINDIR='"$(bindir)"' -DCUPSDATA='"$(CUPSDATA)"' -DGS='"$(GS)"' -o $@ $(gstoraster_) `cups-config --image --ldflags --libs` $(DBUS_LIBS); \ fi + install: install-cups install-cups: cups -mkdir -p $(DESTDIR)$(CUPSSERVERBIN)/filter - $(INSTALL_PROGRAM) cups/pstoraster $(DESTDIR)$(CUPSSERVERBIN)/filter if [ "$(CUPSPDFTORASTER)" = "1" ]; then \ - $(INSTALL_PROGRAM) $(PDFTORASTER_XE) $(DESTDIR)$(CUPSSERVERBIN)/filter; \ + $(INSTALL_PROGRAM) $(GSTORASTER_XE) $(DESTDIR)$(CUPSSERVERBIN)/filter; \ fi $(INSTALL_PROGRAM) cups/pstopxl $(DESTDIR)$(CUPSSERVERBIN)/filter -mkdir -p $(DESTDIR)$(CUPSDATA)/mime - $(INSTALL_DATA) cups/pstoraster.convs $(DESTDIR)$(CUPSDATA)/mime if [ "$(CUPSPDFTORASTER)" = "1" ]; then \ - $(INSTALL_DATA) cups/pdftoraster.convs $(DESTDIR)$(CUPSDATA)/mime; \ + $(INSTALL_DATA) cups/gstoraster.convs $(DESTDIR)$(CUPSDATA)/mime; \ fi -mkdir -p $(DESTDIR)$(CUPSDATA)/model $(INSTALL_DATA) cups/pxlcolor.ppd $(DESTDIR)$(CUPSDATA)/model diff -urNp ghostscript-9.01.old/cups/gstoraster.c ghostscript-9.01/cups/gstoraster.c --- ghostscript-9.01.old/cups/gstoraster.c 1970-01-01 01:00:00.000000000 +0100 +++ ghostscript-9.01/cups/gstoraster.c 2011-03-08 10:48:11.026721536 +0000 @@ -0,0 +1,702 @@ +/* -*- Mode: C; tab-width: 2; indent-tabs-mode: s; c-basic-offset: 8 -*- + +Copyright (c) 2008, Till Kamppeter +Copyright (c) 2011, Tim Waugh +Copyright (c) 2011, Richard Hughes + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +MIT Open Source License - http://www.opensource.org/ + +*/ + +/* $Id$ */ + +/* PS/PDF to CUPS Raster filter based on Ghostscript */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "colord.h" + +#define PDF_MAX_CHECK_COMMENT_LINES 20 + +#ifndef GS +#define GS "gs" +#endif +#ifndef BINDIR +#define BINDIR "/usr/bin" +#endif +#ifndef CUPS_FONTPATH +#define CUPS_FONTPATH "/usr/share/cups/fonts" +#endif +#ifndef CUPSDATA +#define CUPSDATA "/usr/share/cups" +#endif + +typedef enum { + GS_DOC_TYPE_PDF, + GS_DOC_TYPE_PS, + GS_DOC_TYPE_UNKNOWN +} GsDocType; + +#ifdef CUPS_RASTER_SYNCv1 +typedef cups_page_header2_t gs_page_header; +#else +typedef cups_page_header_t gs_page_header; +#endif /* CUPS_RASTER_SYNCv1 */ + +static GsDocType +parse_doc_type(FILE *fp) +{ + char buf[5]; + GsDocType doc_type; + char *rc; + + /* get the first few bytes of the file */ + doc_type = GS_DOC_TYPE_UNKNOWN; + rewind(fp); + rc = fgets(buf,sizeof(buf),fp); + if (rc == NULL) + goto out; + + /* is PDF */ + if (strncmp(buf,"%PDF",4) == 0) { + doc_type = GS_DOC_TYPE_PDF; + goto out; + } + + /* is PS */ + if (strncmp(buf,"%!",2) == 0) { + doc_type = GS_DOC_TYPE_PS; + goto out; + } +out: + return doc_type; +} + +static void +parse_pdf_header_options(FILE *fp, gs_page_header *h) +{ + char buf[4096]; + int i; + + rewind(fp); + /* skip until PDF start header */ + while (fgets(buf,sizeof(buf),fp) != 0) { + if (strncmp(buf,"%PDF",4) == 0) { + break; + } + } + for (i = 0;i < PDF_MAX_CHECK_COMMENT_LINES;i++) { + if (fgets(buf,sizeof(buf),fp) == 0) break; + if (strncmp(buf,"%%PDFTOPDFNumCopies",19) == 0) { + char *p; + + p = strchr(buf+19,':'); + h->NumCopies = atoi(p+1); + } else if (strncmp(buf,"%%PDFTOPDFCollate",17) == 0) { + char *p; + + p = strchr(buf+17,':'); + while (*p == ' ' || *p == '\t') p++; + if (strncasecmp(p,"true",4) == 0) { + h->Collate = CUPS_TRUE; + } else { + h->Collate = CUPS_FALSE; + } + } + } +} + +static void +add_pdf_header_options(gs_page_header *h, cups_array_t *gs_args) +{ + int i; + char tmpstr[1024]; + + /* Simple boolean, enumerated choice, numerical, and string parameters */ + if (h->MediaClass[0] |= '\0') { + snprintf(tmpstr, sizeof(tmpstr), "-sMediaClass=%s", h->MediaClass); + cupsArrayAdd(gs_args, strdup(tmpstr)); + } + if (h->MediaColor[0] |= '\0') { + snprintf(tmpstr, sizeof(tmpstr), "-sMediaColor=%s", h->MediaColor); + cupsArrayAdd(gs_args, strdup(tmpstr)); + } + if (h->MediaType[0] |= '\0') { + snprintf(tmpstr, sizeof(tmpstr), "-sMediaType=%s", h->MediaType); + cupsArrayAdd(gs_args, strdup(tmpstr)); + } + if (h->OutputType[0] |= '\0') { + snprintf(tmpstr, sizeof(tmpstr), "-sOutputType=%s", h->OutputType); + cupsArrayAdd(gs_args, strdup(tmpstr)); + } + if (h->AdvanceDistance) { + snprintf(tmpstr, sizeof(tmpstr), "-dAdvanceDistance=%d", + (unsigned)(h->AdvanceDistance)); + cupsArrayAdd(gs_args, strdup(tmpstr)); + } + if (h->AdvanceMedia) { + snprintf(tmpstr, sizeof(tmpstr), "-dAdvanceMedia=%d", + (unsigned)(h->AdvanceMedia)); + cupsArrayAdd(gs_args, strdup(tmpstr)); + } + if (h->Collate) { + cupsArrayAdd(gs_args, strdup("-dCollate")); + } + if (h->CutMedia) { + snprintf(tmpstr, sizeof(tmpstr), "-dCutMedia=%d", + (unsigned)(h->CutMedia)); + cupsArrayAdd(gs_args, strdup(tmpstr)); + } + if (h->Duplex) { + cupsArrayAdd(gs_args, strdup("-dDuplex")); + } + if ((h->HWResolution[0] != 100) || (h->HWResolution[1] != 100)) + snprintf(tmpstr, sizeof(tmpstr), "-r%dx%d", + (unsigned)(h->HWResolution[0]), (unsigned)(h->HWResolution[1])); + else + snprintf(tmpstr, sizeof(tmpstr), "-r100x100"); + cupsArrayAdd(gs_args, strdup(tmpstr)); + if (h->InsertSheet) { + cupsArrayAdd(gs_args, strdup("-dInsertSheet")); + } + if (h->Jog) { + snprintf(tmpstr, sizeof(tmpstr), "-dJog=%d", + (unsigned)(h->Jog)); + cupsArrayAdd(gs_args, strdup(tmpstr)); + } + if (h->LeadingEdge) { + snprintf(tmpstr, sizeof(tmpstr), "-dLeadingEdge=%d", + (unsigned)(h->LeadingEdge)); + cupsArrayAdd(gs_args, strdup(tmpstr)); + } + if (h->ManualFeed) { + cupsArrayAdd(gs_args, strdup("-dManualFeed")); + } + if (h->MediaPosition) { + snprintf(tmpstr, sizeof(tmpstr), "-dMediaPosition=%d", + (unsigned)(h->MediaPosition)); + cupsArrayAdd(gs_args, strdup(tmpstr)); + } + if (h->MediaWeight) { + snprintf(tmpstr, sizeof(tmpstr), "-dMediaWeight=%d", + (unsigned)(h->MediaWeight)); + cupsArrayAdd(gs_args, strdup(tmpstr)); + } + if (h->MirrorPrint) { + cupsArrayAdd(gs_args, strdup("-dMirrorPrint")); + } + if (h->NegativePrint) { + cupsArrayAdd(gs_args, strdup("-dNegativePrint")); + } + if (h->NumCopies != 1) { + snprintf(tmpstr, sizeof(tmpstr), "-dNumCopies=%d", + (unsigned)(h->NumCopies)); + cupsArrayAdd(gs_args, strdup(tmpstr)); + } + if (h->Orientation) { + snprintf(tmpstr, sizeof(tmpstr), "-dOrientation=%d", + (unsigned)(h->Orientation)); + cupsArrayAdd(gs_args, strdup(tmpstr)); + } + if (h->OutputFaceUp) { + cupsArrayAdd(gs_args, strdup("-dOutputFaceUp")); + } + if (h->PageSize[0] != 612) + snprintf(tmpstr, sizeof(tmpstr), "-dDEVICEWIDTHPOINTS=%d", + (unsigned)(h->PageSize[0])); + else + snprintf(tmpstr, sizeof(tmpstr), "-dDEVICEWIDTHPOINTS=612"); + cupsArrayAdd(gs_args, strdup(tmpstr)); + if (h->PageSize[1] != 792) + snprintf(tmpstr, sizeof(tmpstr), "-dDEVICEHEIGHTPOINTS=%d", + (unsigned)(h->PageSize[1])); + else + snprintf(tmpstr, sizeof(tmpstr), "-dDEVICEHEIGHTPOINTS=792"); + cupsArrayAdd(gs_args, strdup(tmpstr)); + if (h->Separations) { + cupsArrayAdd(gs_args, strdup("-dSeparations")); + } + if (h->TraySwitch) { + cupsArrayAdd(gs_args, strdup("-dTraySwitch")); + } + if (h->Tumble) { + cupsArrayAdd(gs_args, strdup("-dTumble")); + } + if (h->cupsMediaType) { + snprintf(tmpstr, sizeof(tmpstr), "-dcupsMediaType=%d", + (unsigned)(h->cupsMediaType)); + cupsArrayAdd(gs_args, strdup(tmpstr)); + } + if (h->cupsBitsPerColor != 1) + snprintf(tmpstr, sizeof(tmpstr), "-dcupsBitsPerColor=%d", + (unsigned)(h->cupsBitsPerColor)); + else + snprintf(tmpstr, sizeof(tmpstr), "-dcupsBitsPerColor=1"); + cupsArrayAdd(gs_args, strdup(tmpstr)); + if (h->cupsColorOrder != CUPS_ORDER_CHUNKED) + snprintf(tmpstr, sizeof(tmpstr), "-dcupsColorOrder=%d", + (unsigned)(h->cupsColorOrder)); + else + snprintf(tmpstr, sizeof(tmpstr), "-dcupsColorOrder=%d", + CUPS_ORDER_CHUNKED); + cupsArrayAdd(gs_args, strdup(tmpstr)); + if (h->cupsColorSpace != CUPS_CSPACE_K) + snprintf(tmpstr, sizeof(tmpstr), "-dcupsColorSpace=%d", + (unsigned)(h->cupsColorSpace)); + else + snprintf(tmpstr, sizeof(tmpstr), "-dcupsColorSpace=%d", + CUPS_CSPACE_K); + cupsArrayAdd(gs_args, strdup(tmpstr)); + if (h->cupsCompression) { + snprintf(tmpstr, sizeof(tmpstr), "-dcupsCompression=%d", + (unsigned)(h->cupsCompression)); + cupsArrayAdd(gs_args, strdup(tmpstr)); + } + if (h->cupsRowCount) { + snprintf(tmpstr, sizeof(tmpstr), "-dcupsRowCount=%d", + (unsigned)(h->cupsRowCount)); + cupsArrayAdd(gs_args, strdup(tmpstr)); + } + if (h->cupsRowFeed) { + snprintf(tmpstr, sizeof(tmpstr), "-dcupsRowFeed=%d", + (unsigned)(h->cupsRowFeed)); + cupsArrayAdd(gs_args, strdup(tmpstr)); + } + if (h->cupsRowStep) { + snprintf(tmpstr, sizeof(tmpstr), "-dcupsRowStep=%d", + (unsigned)(h->cupsRowStep)); + cupsArrayAdd(gs_args, strdup(tmpstr)); + } +#ifdef CUPS_RASTER_SYNCv1 + if (h->cupsBorderlessScalingFactor != 1.0f) { + snprintf(tmpstr, sizeof(tmpstr), "-dcupsBorderlessScalingFactor=%.4f", + h->cupsBorderlessScalingFactor); + cupsArrayAdd(gs_args, strdup(tmpstr)); + } + for (i=0; i <= 15; i ++) + if (h->cupsInteger[i]) { + snprintf(tmpstr, sizeof(tmpstr), "-dcupsInteger%d=%d", + i, (unsigned)(h->cupsInteger[i])); + cupsArrayAdd(gs_args, strdup(tmpstr)); + } + for (i=0; i <= 15; i ++) + if (h->cupsReal[i]) { + snprintf(tmpstr, sizeof(tmpstr), "-dcupsReal%d=%.4f", + i, h->cupsReal[i]); + cupsArrayAdd(gs_args, strdup(tmpstr)); + } + for (i=0; i <= 15; i ++) + if (h->cupsString[i][0] != '\0') { + snprintf(tmpstr, sizeof(tmpstr), "-scupsString%d=%s", + i, h->cupsString[i]); + cupsArrayAdd(gs_args, strdup(tmpstr)); + } + if (h->cupsMarkerType[0] != '\0') { + snprintf(tmpstr, sizeof(tmpstr), "-scupsMarkerType=%s", + h->cupsMarkerType); + cupsArrayAdd(gs_args, strdup(tmpstr)); + } + if (h->cupsRenderingIntent[0] != '\0') { + snprintf(tmpstr, sizeof(tmpstr), "-scupsRenderingIntent=%s", + h->cupsRenderingIntent); + cupsArrayAdd(gs_args, strdup(tmpstr)); + } + if (h->cupsPageSizeName[0] != '\0') { + snprintf(tmpstr, sizeof(tmpstr), "-scupsPageSizeName=%s", + h->cupsPageSizeName); + cupsArrayAdd(gs_args, strdup(tmpstr)); + } +#endif /* CUPS_RASTER_SYNCv1 */ +} + +static int +gs_spawn (const char *filename, + cups_array_t *gs_args, + char **envp, + FILE *fp) +{ + char *argument; + char buf[BUFSIZ]; + char **gsargv; + const char* apos; + int fds[2]; + int i; + int n; + int numargs; + int pid; + int status = 1; + + /* Put Ghostscript command line argument into an array for the "exec()" + call */ + numargs = cupsArrayCount(gs_args); + gsargv = calloc(numargs + 1, sizeof(char *)); + for (argument = (char *)cupsArrayFirst(gs_args), i = 0; argument; + argument = (char *)cupsArrayNext(gs_args), i++) { + gsargv[i] = argument; + } + gsargv[i] = NULL; + + /* Debug output: Full Ghostscript command line and environment variables */ + fprintf(stderr, "DEBUG: Ghostscript command line:"); + for (i = 0; gsargv[i]; i ++) { + if ((strchr(gsargv[i],' ')) || (strchr(gsargv[i],'\t'))) + apos = "'"; + else + apos = ""; + fprintf(stderr, " %s%s%s", apos, gsargv[i], apos); + } + fprintf(stderr, "\n"); + + for (i = 0; envp[i]; i ++) + fprintf(stderr, "DEBUG: envp[%d]=\"%s\"\n", i, envp[i]); + + /* Create a pipe for feeding the job into Ghostscript */ + if (pipe(fds)) + { + fds[0] = -1; + fds[1] = -1; + fprintf(stderr, "ERROR: Unable to establish pipe for Ghostscript call"); + goto out; + } + + /* Set the "close on exec" flag on each end of the pipe... */ + if (fcntl(fds[0], F_SETFD, fcntl(fds[0], F_GETFD) | FD_CLOEXEC)) + { + close(fds[0]); + close(fds[1]); + fds[0] = -1; + fds[1] = -1; + fprintf(stderr, "ERROR: Unable to set \"close on exec\" flag on read end of the pipe for Ghostscript call"); + goto out; + } + if (fcntl(fds[1], F_SETFD, fcntl(fds[1], F_GETFD) | FD_CLOEXEC)) + { + close(fds[0]); + close(fds[1]); + fprintf(stderr, "ERROR: Unable to set \"close on exec\" flag on write end of the pipe for Ghostscript call"); + goto out; + } + + if ((pid = fork()) == 0) + { + /* Couple pipe with STDIN of Ghostscript process */ + if (fds[0] != 0) { + close(0); + if (fds[0] > 0) + dup(fds[0]); + else { + fprintf(stderr, "ERROR: Unable to couple pipe with STDIN of Ghostscript process"); + goto out; + } + } + + /* Execute Ghostscript command line ... */ + execve(filename, gsargv, envp); + perror(filename); + goto out; + } + + /* Feed job data into Ghostscript */ + while ((n = fread(buf, 1, BUFSIZ, fp)) > 0) { + if (write(fds[1], buf, n) != n) { + fprintf(stderr, "ERROR: Can't feed job data into Ghostscript"); + goto out; + } + } + close (fds[1]); + + if (waitpid (pid, &status, 0) == -1) { + perror ("gs"); + goto out; + } +out: + free(gsargv); + return status; +} + +static char * +get_ppd_icc_fallback (ppd_file_t *ppd, char **qualifier) +{ + char full_path[1024]; + char *icc_profile = NULL; + char qualifer_tmp[1024]; + const char *profile_key; + ppd_attr_t *attr; + + /* get profile attr, falling back to CUPS */ + profile_key = "APTiogaProfile"; + attr = ppdFindAttr(ppd, profile_key, NULL); + if (attr == NULL) { + profile_key = "cupsICCProfile"; + attr = ppdFindAttr(ppd, profile_key, NULL); + } + + /* create a string for a quick comparion */ + snprintf(qualifer_tmp, sizeof(qualifer_tmp), + "%s.%s.%s", + qualifier[0], + qualifier[1], + qualifier[2]); + + /* neither */ + if (attr == NULL) { + fprintf(stderr, "INFO: no profiles specified in PPD\n"); + goto out; + } + + /* try to find a profile that matches the qualifier exactly */ + for (;attr != NULL; attr = ppdFindNextAttr(ppd, profile_key, NULL)) { + fprintf(stderr, "INFO: found profile %s in PPD with qualifier '%s'\n", + attr->value, attr->spec); + + /* invalid entry */ + if (attr->spec == NULL || attr->value == NULL) + continue; + + /* expand to a full path if not already specified */ + if (attr->value[0] != '/') + snprintf(full_path, sizeof(full_path), + "%s/profiles/%s", CUPSDATA, attr->value); + else + strncpy(full_path, attr->value, sizeof(full_path)); + + /* check the file exists */ + if (access(full_path, 0)) { + fprintf(stderr, "INFO: found profile %s in PPD that does not exist\n", + full_path); + continue; + } + + /* matches the qualifier */ + if (strcmp(qualifer_tmp, attr->spec) == 0) { + icc_profile = strdup(full_path); + goto out; + } + } + + /* no match */ + if (attr == NULL) { + fprintf(stderr, "INFO: no profiles in PPD for qualifier '%s'\n", + qualifer_tmp); + goto out; + } + +out: + return icc_profile; +} + +int +main (int argc, char **argv, char *envp[]) +{ + char buf[BUFSIZ]; + char *icc_profile = NULL; + char **qualifier = NULL; + char *tmp; + char tmpstr[1024]; + const char *t = NULL; + cups_array_t *gs_args = NULL; + cups_option_t *options = NULL; + FILE *fp = NULL; + GsDocType doc_type; + gs_page_header h; + int fd; + int i; + int n; + int num_options; + int status = 1; + ppd_file_t *ppd = NULL; + + if (argc < 6 || argc > 7) { + fprintf(stderr, "ERROR: %s job-id user title copies options [file]\n", + argv[0]); + goto out; + } + + num_options = cupsParseOptions(argv[5], 0, &options); + + t = getenv("PPD"); + if ((ppd = ppdOpenFile(t)) == NULL) { + fprintf(stderr, "ERROR: Failed to open PPD: %s", t); + goto out; + } + + ppdMarkDefaults (ppd); + cupsMarkOptions (ppd, num_options, options); + + if (argc == 6) { + /* stdin */ + + fd = cupsTempFd(buf,BUFSIZ); + if (fd < 0) { + fprintf(stderr, "ERROR: Can't create temporary file"); + goto out; + } + /* remove name */ + unlink(buf); + + /* copy stdin to the tmp file */ + while ((n = read(0,buf,BUFSIZ)) > 0) { + if (write(fd,buf,n) != n) { + fprintf(stderr, "ERROR: Can't copy stdin to temporary file"); + close(fd); + goto out; + } + } + if (lseek(fd,0,SEEK_SET) < 0) { + fprintf(stderr, "ERROR: Can't rewind temporary file"); + close(fd); + goto out; + } + + if ((fp = fdopen(fd,"rb")) == 0) { + fprintf(stderr, "ERROR: Can't fdopen temporary file"); + close(fd); + goto out; + } + } else { + /* argc == 7 filename is specified */ + + if ((fp = fopen(argv[6],"rb")) == 0) { + fprintf(stderr, "ERROR: Can't open input file %s",argv[6]); + goto out; + } + } + + /* find out file type */ + doc_type = parse_doc_type(fp); + if (doc_type == GS_DOC_TYPE_UNKNOWN) { + fprintf(stderr, "ERROR: Can't detect file type"); + goto out; + } + + qualifier = colord_get_qualifier_for_ppd (ppd); + if (qualifier != NULL) { + + fprintf(stderr, "DEBUG: PPD uses qualifier '%s.%s.%s'\n", + qualifier[0], qualifier[1], qualifier[2]); + icc_profile = colord_get_profile_for_device_id (getenv("PRINTER"), + (const char**) qualifier); + + /* fall back to the PPD */ + if (icc_profile == NULL) + icc_profile = get_ppd_icc_fallback (ppd, qualifier); + + if(icc_profile != NULL) + fprintf(stderr, "DEBUG: Using ICC Profile '%s'\n", icc_profile); + } + + /* Ghostscript parameters */ + gs_args = cupsArrayNew(NULL, NULL); + if (!gs_args) + { + fprintf(stderr, "ERROR: Unable to allocate memory for Ghostscript arguments array\n"); + exit(1); + } + + /* Part of Ghostscript command line which is not dependent on the job and/or + the driver */ + snprintf(tmpstr, sizeof(tmpstr), "%s/%s", BINDIR, GS); + cupsArrayAdd(gs_args, strdup(tmpstr)); + cupsArrayAdd(gs_args, strdup("-dQUIET")); + /*cupsArrayAdd(gs_args, strdup("-dDEBUG"));*/ + cupsArrayAdd(gs_args, strdup("-dPARANOIDSAFER")); + cupsArrayAdd(gs_args, strdup("-dNOPAUSE")); + cupsArrayAdd(gs_args, strdup("-dBATCH")); + if (doc_type == GS_DOC_TYPE_PS) + cupsArrayAdd(gs_args, strdup("-dNOMEDIAATTRS")); + cupsArrayAdd(gs_args, strdup("-sDEVICE=cups")); + cupsArrayAdd(gs_args, strdup("-sstdout=%stderr")); + cupsArrayAdd(gs_args, strdup("-sOutputFile=%stdout")); + + /* setPDF specific options */ + if (doc_type == GS_DOC_TYPE_PDF) { + cupsRasterInterpretPPD(&h,ppd,num_options,options,0); + parse_pdf_header_options(fp, &h); + + /* fixed other values that pdftopdf handles */ + h.MirrorPrint = CUPS_FALSE; + h.Orientation = CUPS_ORIENT_0; + + /* get all the data from the header and pass it to ghostscript */ + add_pdf_header_options (&h, gs_args); + } + + /* CUPS font path */ + if ((t = getenv("CUPS_FONTPATH")) == NULL) + t = CUPS_FONTPATH; + snprintf(tmpstr, sizeof(tmpstr), "-I%s", t); + cupsArrayAdd(gs_args, strdup(tmpstr)); + + /* set the device output ICC profile */ + if(icc_profile != NULL) { + snprintf(tmpstr, sizeof(tmpstr), "-sOutputICCProfile=%s", icc_profile); + cupsArrayAdd(gs_args, strdup(tmpstr)); + } + + /* Switch to taking PostScript commands on the Ghostscript command line */ + cupsArrayAdd(gs_args, strdup("-c")); + + if ((t = cupsGetOption("profile", num_options, options)) != NULL) { + snprintf(tmpstr, sizeof(tmpstr), "<>setpagedevice", t); + cupsArrayAdd(gs_args, strdup(tmpstr)); + } + + /* Mark the end of PostScript commands supplied on the Ghostscript command + line (with the "-c" option), so that we can supply the input file name */ + cupsArrayAdd(gs_args, strdup("-f")); + + /* Let Ghostscript read from STDIN */ + cupsArrayAdd(gs_args, strdup("-_")); + + /* Execute Ghostscript command line ... */ + snprintf(tmpstr, sizeof(tmpstr), "%s/%s", BINDIR, GS); + + /* call Ghostscript */ + rewind(fp); + status = gs_spawn (tmpstr, gs_args, envp, fp); +out: + if (fp) + fclose(fp); + if (qualifier != NULL) { + for (i=0; qualifier[i] != NULL; i++) + free(qualifier[i]); + free(qualifier); + } + if (gs_args) { + while ((tmp = cupsArrayFirst(gs_args)) != NULL) { + cupsArrayRemove(gs_args,tmp); + free(tmp); + } + cupsArrayDelete(gs_args); + } + free(icc_profile); + if (ppd) + ppdClose(ppd); + return status; +} diff -urNp ghostscript-9.01.old/cups/gstoraster.convs ghostscript-9.01/cups/gstoraster.convs --- ghostscript-9.01.old/cups/gstoraster.convs 1970-01-01 01:00:00.000000000 +0100 +++ ghostscript-9.01/cups/gstoraster.convs 2011-03-08 10:48:11.026721536 +0000 @@ -0,0 +1,30 @@ +# Copyright (c) 2008, Till Kamppeter +# Copyright (c) 2011, Richard Hughes +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# MIT Open Source License - http://www.opensource.org/ +# +# $Id: pdftoraster.convs 8803 2008-06-24 14:16:29Z till $ +# +# CUPS file conversion rules for gstoraster filter + +application/vnd.cups-pdf application/vnd.cups-raster 66 gstoraster +application/vnd.cups-postscript application/vnd.cups-raster 100 gstoraster diff -urNp ghostscript-9.01.old/Makefile.in ghostscript-9.01/Makefile.in --- ghostscript-9.01.old/Makefile.in 2011-03-08 10:47:24.951721587 +0000 +++ ghostscript-9.01/Makefile.in 2011-03-08 10:48:11.020721446 +0000 @@ -140,7 +140,7 @@ GENOPT= # -DHAVE_SETLOCALE # call setlocale(LC_CTYPE) when running as a standalone app -CAPOPT= @HAVE_MKSTEMP@ @HAVE_HYPOT@ @HAVE_FILE64@ @HAVE_MKSTEMP64@ @HAVE_FONTCONFIG@ @HAVE_LIBIDN@ @HAVE_SETLOCALE@ +CAPOPT= @HAVE_MKSTEMP@ @HAVE_HYPOT@ @HAVE_FILE64@ @HAVE_MKSTEMP64@ @HAVE_FONTCONFIG@ @HAVE_LIBIDN@ @HAVE_SETLOCALE@ @HAVE_DBUS@ # Define the name of the executable file. @@ -339,6 +339,10 @@ XCFLAGS=@DYNAMIC_FLAGS@ FONTCONFIG_CFLAGS=@FONTCONFIG_CFLAGS@ FONTCONFIG_LIBS=@FONTCONFIG_LIBS@ +# DBus flags, used by cups.mak +DBUS_CFLAGS=@DBUS_CFLAGS@ +DBUS_LIBS=@DBUS_LIBS@ + # defines from autoconf; note that we don't use these at present. ACDEFS=@DEFS@