Codebase list splix / 1cd4015d-4c33-46f3-87f0-82c0d142f7db/main src / pstoqpdl.cpp
1cd4015d-4c33-46f3-87f0-82c0d142f7db/main

Tree @1cd4015d-4c33-46f3-87f0-82c0d142f7db/main (Download .tar.gz)

pstoqpdl.cpp @1cd4015d-4c33-46f3-87f0-82c0d142f7db/main

970703d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e6011e5
970703d
80e5ef3
970703d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0b7f07c
 
 
 
 
 
 
 
 
 
 
970703d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0b7f07c
970703d
 
0b7f07c
970703d
 
0b7f07c
970703d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0b7f07c
970703d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0b7f07c
970703d
 
 
 
 
 
 
 
0b7f07c
970703d
0b7f07c
 
 
970703d
0b7f07c
 
970703d
 
 
 
 
80e5ef3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
970703d
80e5ef3
 
970703d
 
 
030bc01
 
80e5ef3
 
 
970703d
 
 
 
80e5ef3
 
970703d
80e5ef3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
970703d
80e5ef3
 
 
 
 
 
970703d
 
80e5ef3
 
970703d
80e5ef3
 
970703d
 
80e5ef3
 
970703d
 
 
80e5ef3
970703d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
030bc01
 
970703d
 
 
 
 
/*
 * 	    pstoqpdl.cpp              (C) 2007-2008, Aurélien Croc (AP²C)
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; version 2 of the License.
 * 
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the
 *  Free Software Foundation, Inc.,
 *  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 *
 *  $Id: pstoqpdl.cpp 308 2013-04-08 06:52:15Z tillkamppeter $
 * 
 */
#include "ppdfile.h"
#include "errlog.h"
#include "version.h"
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/types.h>


/*
 * Appel des filtres
 * Filter call
 */
static char *_toLower(const char *data)
{
    char *tmp = new char[strlen(data) + 1];
    unsigned int i;

    for (i=0; data[i]; i++)
        tmp[i] = (char) tolower(data[i]);
    tmp[i] = 0;
    return tmp;
}

static int _linkFilters(const char *arg1, const char *arg2, const char *arg3,
    const char *arg4, const char *arg5) 
{
    int rasterInput[2], rasterOutput[2];
    int raster, splix;

    // Call pstoraster
    if (pipe(rasterInput) || pipe(rasterOutput)) {
        ERRORMSG(_("Cannot create pipe (%i)"), errno);
        return 0;
    }

    // Launch SpliX
    if (!(splix = fork())) {
        // SpliX code
        close(rasterInput[1]);
        close(rasterInput[0]);
        close(rasterOutput[1]);
        dup2(rasterOutput[0], STDIN_FILENO);
        close(rasterOutput[0]);
        execl(RASTERDIR "/" RASTERTOQPDL, RASTERDIR "/" RASTERTOQPDL, arg1, 
            arg2, arg3, arg4, arg5, (char *)NULL);
        ERRORMSG(_("Cannot execute rastertoqpdl (%i)"), errno);
        exit(0);
    }
    DEBUGMSG(_("SpliX launched with PID=%u"), splix);
    
    // Launch the raster
    dup2(rasterInput[1], STDOUT_FILENO);
    close(rasterOutput[0]);
    close(rasterInput[1]);
    if (!(raster = fork())) {
        // Raster code
        dup2(rasterInput[0], STDIN_FILENO);
        dup2(rasterOutput[1], STDOUT_FILENO);
        close(rasterInput[0]);
        close(rasterOutput[1]);
        if (access(RASTERDIR "/" GSTORASTER, F_OK) != -1) {
            // gstoraster filter exists
            execl(RASTERDIR "/" GSTORASTER, RASTERDIR "/" GSTORASTER, arg1, arg2, 
                arg3, arg4, arg5,(char *)NULL);
            ERRORMSG(_("Cannot execute gstoraster (%i)"), errno);
        } else {
            // use pstoraster if gstoraster doesn't exist
            execl(RASTERDIR "/" PSTORASTER, RASTERDIR "/" PSTORASTER, arg1, arg2, 
                arg3, arg4, arg5,(char *)NULL);
            ERRORMSG(_("Cannot execute %s (%i)"), PSTORASTER, errno);
        }
        exit(0);
    }
    DEBUGMSG(_("raster launched with PID=%u"), raster);
    close(rasterInput[0]);
    close(rasterOutput[1]);

    return splix;
}



/*
 * Lecture des fichiers CRD / CSA
 * CSA / CRD read
 */
static char *_readCMSFile(PPDFile& ppd, const char *manufacturer, bool csa)
{
    unsigned long xResolution=0, yResolution=0, size;
    PPDValue resolution;
    const char *file;
    char *tmp, *res;
    struct stat fi;
    FILE *handle;

    // Get the base filename
    file = ppd.get("CMSFile", "General");
    if (!file || !(*file))
        return NULL;

    // Get the resolution
    resolution = ppd.get("Resolution");
    if (resolution == "1200dpi")
        xResolution = yResolution = 1200;
    else if (resolution == "600dpi")
        xResolution = yResolution = 600;
    else if (resolution == "1200x600dpi") {
        xResolution = 1200;
        yResolution = 600;
    } else if (resolution == "300dpi") 
        xResolution = yResolution = 300;

    // Get the real filename
    size = strlen(CUPSPROFILE) + strlen(manufacturer) + strlen(file) + 64;
    tmp = new char[size];
    if (xResolution)
        snprintf(tmp, size, CUPSPROFILE "/%s/%s-%lux%lucms%s", manufacturer,
            file, xResolution, yResolution, csa ? "2" : "");
    if (!xResolution || access(tmp, R_OK))
        snprintf(tmp, size, CUPSPROFILE "/%s/%scms%s", manufacturer,
            file, csa ? "2" : "");

    // Check if it exists, open it and read it
    if (stat(tmp, &fi) || !(handle = fopen(tmp, "r"))) {
        ERRORMSG(_("Cannot open CMS file %s (%i)"), tmp, errno);
        delete[] tmp;
        return NULL;
    }
    if (!fi.st_size) {
        ERRORMSG(_("CMS file %s is empty"), tmp);
        delete[] tmp;
        fclose(handle);
        return NULL;
    }
    res = new char[fi.st_size + 1];
    if (!fread(res, 1, fi.st_size, handle)) {
        ERRORMSG(_("Cannot read CMS file %s (%i)"), tmp, errno);
        delete[] tmp;
        delete[] res;
        fclose(handle);
        return NULL;
    }
    res[fi.st_size] = 0;
    fclose(handle);
    delete[] tmp;

    return res;
}



/*
 * PROGRAMME PRINCIPAL
 * MAIN ROUTINE
 */
int main(int argc, char **argv)
{
    const char *jobid, *user, *title, *options, *ppdFile, *file;
    const char *paperType, *manufacturer;
    unsigned long copies;
    bool pageSetup=false;
    char buffer[1024];
    char *crd, *csa;
    int pid, err;
    PPDFile ppd;

    // Check the given arguments
    if (argc != 6 && argc != 7) {
        fprintf(stderr, _("Usage: %s job-id user title copies options "
            "[file]\n"), argv[0]);
        return 1;
    }
    jobid = argv[1];
    user = argv[2];
    title = argv[3];
    options = argv[5];
    file = argc == 7 ? argv[6] : NULL;
    copies = strtol(argv[4], (char **)NULL, 10);
    ppdFile = getenv("PPD");

    // Get more information on the SpliX environment (for debugging)
    DEBUGMSG(_("PS => SpliX filter V. %s by Aurélien Croc (AP²C)"), VERSION);
    DEBUGMSG(_("More information at: http://splix.ap2c.org"));

    // Open the given file
    if (file && !freopen(file, "r", stdin)) {
        ERRORMSG(_("Cannot open file %s"), file);
        return errno;
    }

    // Open the PPD file and get paper information
    if (!ppd.open(ppdFile, PPDVERSION, options))
        return 1;
    manufacturer = _toLower(ppd.get("Manufacturer"));
    paperType = ppd.get("MediaType");
    if (!(strcasecmp(paperType, "OFF")))
        paperType = "NORMAL";

    // Call the other filters
    if (!(pid = _linkFilters(argv[1], argv[2], argv[3], argv[4], argv[5]))) {
        ERRORMSG(_("Filter error.. Cannot continue"));
        delete[] manufacturer;
        return 1;
    }

    // Get the CRD and CSA information and send the PostScript data
    crd = _readCMSFile(ppd, manufacturer, false);
    csa = _readCMSFile(ppd, manufacturer, true);
    if (!crd || !csa) {
        WARNMSG(_("CMS data are missing. Color correction aborted"));
        if (crd) {
            delete[] crd;
            crd = NULL;
        }
        if (csa) {
            delete[] csa;
            csa = NULL;
        }
        while (!(feof(stdin))) {
            fgets((char *)&buffer, sizeof(buffer), stdin);
            fprintf(stdout, "%s", (char *)&buffer); 
        }
    } else {

        // Insert the MediaChoice and colour correction information into
        // the postscript header.
        //
        // Look for a "%%Creator" line in the postscript header, and
        // insert the information before it.
        //
        // Postscript that is created by pdftops from content from Apple 
        // iOS devices (iPad etc) seems not to have a "%%Creator" line in
        // the header, so we insert a dummy one. Without this, pstoqpdl
        // seems to crash ghostscript.
        //
        // NB: according to the PostScript Document Structuring Conventions
        // (DSC) specification the end of the postscript header should be
        // the "%%EndComments" line - see:
        // http://partners.adobe.com/public/developer/en/ps/5001.DSC_Spec.pdf


        // search each line in the postscript header
        while (!(feof(stdin))) {

            // read a line of the input file
            if (!fgets((char *)&buffer, sizeof(buffer), stdin))
                break;

            if (!(memcmp("%%Creator", (char *)&buffer, 9)) ||
                !(memcmp("%%LanguageLevel:", (char *)&buffer, 16))) {
                // found a "%%Creator" line

                // emit the MediaChoice and colour correction information
                if (paperType)
                    fprintf(stdout, "/MediaChoice (%s) def\n", paperType);
                fprintf(stdout, "%s", crd);
                fprintf(stdout, "%s", csa);

                // emit the original "%%Creator" line
                fprintf(stdout, "%s", (char *)&buffer); 

                // stop scanning the header
                break;
            }


            if (!(memcmp("%%EndComments", (char *)&buffer, 13))) {
                // reached end of header without finding a "%%Creator" line

                // emit the MediaChoice and colour correction information
                if (paperType)
                    fprintf(stdout, "/MediaChoice (%s) def\n", paperType);
                fprintf(stdout, "%s", crd);
                fprintf(stdout, "%s", csa);

                // emit a dummy "%%Creator" line
                DEBUGMSG(_("inserting dummy \"Creator\" entry in postscript header"));
                fprintf(stdout, "%s", "%%Creator: SpliX pstoqpdl filter");

                // emit the original "%%EndComments" line
                fprintf(stdout, "%s", (char *)&buffer);

                // stop scanning the header
                break;
            }


            if (!(memcmp("%%BeginPro", (char *)&buffer, 10)) ||
                !(memcmp("%%BeginRes", (char *)&buffer, 10))) {
                // we shouldn't find either of these lines in the header

                ERRORMSG(_("End of PostScript header not found"));

                // emit the line that was found
                fprintf(stdout, "%s", (char *)&buffer); 

                // stop scanning the header
                break;
            }

            // encountered some other kind of header line - just emit it
            fprintf(stdout, "%s", (char *)&buffer); 
        }


        // Check for each page
        while (!(feof(stdin))) {
            if (!fgets((char *)&buffer, sizeof(buffer), stdin))
                break;
            if (!(memcmp("%%Page:", (char *)&buffer, 7))) {
                char tmp[sizeof(buffer)];

                if (!fgets((char *)&tmp, sizeof(tmp), stdin)) {
                    fprintf(stdout, "%s", (char *)&buffer);
                    break;
                }
                if (!(memcmp("%%BeginPageSetup", (char *)&tmp, 16)))
                    pageSetup = true;
                else
                    fprintf(stdout, "%s", csa);
                fprintf(stdout, "%s", (char *)&buffer);
                fprintf(stdout, "%s", (char *)&tmp);
            } else if (pageSetup && !(memcmp("%%EndPageSetup", 
                (char *)&buffer, 14))) {
                fprintf(stdout, "%s", (char *)&buffer);
                fprintf(stdout, "%s", csa);
                pageSetup = false;
            } else 
                fprintf(stdout, "%s", (char *)&buffer);
        }
    }


    // Close the output and wait for Splix to be finished
    fclose(stdout);
    waitpid(pid, &err, 0);

    if (crd)
        delete[] crd;
    if (csa)
        delete[] csa;
    if (manufacturer)
        delete[] manufacturer;
    return WEXITSTATUS(err);
}

/* vim: set expandtab tabstop=4 shiftwidth=4 smarttab tw=80 cin enc=utf8: */