Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I create a dynamic job ticket for Xerox printers?

I am programmatically creating PDF files in Python and Reportlab Toolkit, each containing several thousand documents, each document with a variable amount of pages.

My problem is that I need to instruct the printer which media type each page should be printed on (pre-printed letterhead for the first page of a document for example). It seems that I need to generate some kind of job ticket which hold this kind of information.

I've had some success with creating JDF job tickets, but these only run on my organisation's newest printers which run Xerox Freeflow Server version 8.

Ideally, I need a solution which also works with our Freeflow server version 7 and Xerox DocuSP printers. I have tried unsuccessfully to send JDF tickets to these printers.

Is there another type of ticketing system I could use, or a way to get all of our printers recognising JDF files?

like image 628
nakedfanatic Avatar asked May 18 '11 21:05

nakedfanatic


1 Answers

I've run into the same problem. Eventually, I found out that I was going about it the wrong way, caused by a misunderstanding of the PDF format. We think of PDF files as WYSIWYG for printers. This is not the case. In any kind of print flow, the PDF file gets converted to some intermediate format, PostScript, TIFF images, or PCL usually.

This may happen on your local machine, which is why you need a driver, or on the printer itself. If it happens on the printer, you are just transferring your PDF file to a different computer with the appropriate conversion system set up.

This is all fine and dandy, except that PDF does not define page order which is very counterintuitive for a print ready format. This means there is no first page of your document and you won't be able to natively define it in any way shape or form.

You have two solutions:

  1. Pick a printer architecture and use its unique method of setting the media type, which is a pain, and nonportable.

  2. Convert to a format that allows for setting media type and includes the idea of page ordering, such as PostScript. Then add in your media commands and send this file along to your printer. If your printer has a driver for reading your chosen intermediate format, it should convert the commands to its version of media switching. This is more portable but still not perfect.

This is similar to the idea of converting your C program to assembly to port it to a new architecture. It mostly works, but you have to fiddle each system into operation.

A hypothetical pipeline would be:

Create your PDF file > run it through a PDF-to-PostScript conversion utility or library > run through a custom lexer to add media type commands at each new page > send to PostScript file to printer

It's a lot of work, but that's about the only thing your going to find that will solve your problem.

Sample

%{
char paper[] = 'yourPaper';
%}
%option 8bit outfile="scanner.c"
%option nounput nomain noyywrap
%option warn

%%
showpage { printf("showpage\nsetpagedevice MediaType '%s'", paper); }
%%
int main(int argc, char **argv);

int main (argc,argv)
int argc;
char **argv;
{
    yylex();
    return 0;
}

The above is a very simplistic lexer to find every showpage command obtained from stdin and output a showpage setpagedevice command set. The setpagedevice MediaType command is the printer agnostic way of setting the type of paper to use for a page.

To compile the code using flex and GCC:

flex -Cf scanner.l
gcc -O -o lineCount.exe scanner.c

It accepts input via stdin and outputs to stdout.

A more complete lexer is listed below. It uses GNU getopts for command line options, and has two rules, so that it will set the page device for the first page as well. It may not perfectly grab the pages, and it only has one variable for the paper type, so the functionality is limited. On the other hand, it is very open for however you want it to determine the page device to use.

Either new rules to recognize what type of page it is looking at, or an additional input file with one line per page are the two that come to mind immediately.

/*
 * This file is part of flex.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * Neither the name of the University nor the names of its contributors
 * may be used to endorse or promote products derived from this software
 * without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE.
 */

     /**************************************************
        Start of definitions section

    ***************************************************/

%{
/* A template scanner file to build "scanner.c". */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
/*#include "parser.h" */

//put your variables here
char FileName[256];
FILE *outfile;
char inputName[256];
char paper[] = 'yourPaper';

// flags for command line options
static int specificFile_flag = 0;
static int output_flag = 0;
static int help_flag = 0;

%}


%option 8bit outfile="scanner.c"
%option nounput nomain noyywrap
%option warn

%%
    /************************************************
        start of rules section

    *************************************************/


    /* These flex patterns will eat all input */
EndSetup { printf("showpage\nsetpagedevice MediaType '%s'", paper); }
showpage { printf("showpage\nsetpagedevice MediaType '%s'", paper); }


%%
    /****************************************************
        Start of code section


    *****************************************************/

int main(int argc, char **argv);

int main (argc,argv)
int argc;
char **argv;
{
    /****************************************************
        The main method drives the program. It gets the filename from the
        command line, and opens the initial files to write to. Then it calls the lexer.
        After the lexer returns, the main method finishes out the report file,
        closes all of the open files, and prints out to the command line to let the
        user know it is finished.
    ****************************************************/

    int c;

    // The GNU getopt library is used to parse the command line for flags
    // afterwards, the final option is assumed to be the input file

    while (1) {
        static struct option long_options[] = {
            /* These options set a flag. */
            {"help",   no_argument,     &help_flag, 1},
            /* These options don't set a flag. We distinguish them by their indices. */

            {"useStdOut", no_argument,       0, 'o'},
            {0, 0, 0, 0}
        };
           /* getopt_long stores the option index here. */
        int option_index = 0;
        c = getopt_long (argc, argv, "o",
            long_options, &option_index);

        /* Detect the end of the options. */
        if (c == -1)
            break;

        switch (c) {
            case 0:
               /* If this option set a flag, do nothing else now. */
               if (long_options[option_index].flag != 0)
                 break;
               printf ("option %s", long_options[option_index].name);
               if (optarg)
                 printf (" with arg %s", optarg);
               printf ("\n");
               break;

            case 'o':
               output_flag = 1;
               break;


            case '?':
               /* getopt_long already printed an error message. */
               break;

            default:
               abort ();
            }
    }

    if (help_flag == 1) {
        printf("proper syntax is: traySwitch.exe [OPTIONS]... INFILE OUTFILE\n");
        printf("adds tray switching information to postscript file\n\n");
        printf("Option list: \n");
        printf("-o                        sets output to stdout\n");
        printf("--help                   print help to screen\n");
        printf("\n");
        printf("inputfile example: traySwitch.exe test.ps\n");
        printf("If infile is left out, then stdin is used for input.\n");
        printf("If outfile is a filename, then that file is used.\n");
        printf("If there is no outfile, then infile-EDIT.ps is used.\n");
        printf("There cannot be an outfile without an infile.\n");
        return 0;
    }

    //Get the filename off the command line and redirect it to input
    //if there is no filename or it is a - then use stdin.


    if (optind < argc) {
        FILE *file;

        file = fopen(argv[optind], "rb");
        if (!file) {
            fprintf(stderr, "Flex could not open %s\n",argv[optind]);
            exit(1);
        }
        yyin = file;
        strcpy(inputName, argv[optind]);
    }
    else {
        printf("no input file set, using stdin. Press ctrl-c to quit");
        yyin = stdin;
        strcpy(inputName, "\b\b\b\b\bagainst stdin");
    }

    //Increment current place in argument list
    optind++;


    /********************************************
        If no input name, then output set to stdout.
        If no output name then copy input name and add -EDIT.csv.
        If input name is '-' then output set to stdout,
        otherwise use output name.

    *********************************************/
    if (optind > argc) {
        yyout = stdout;
    }
    else if (output_flag == 1) {
        yyout = stdout;
    }
    else if (optind < argc){
        outfile = fopen(argv[optind], "wb");
        if (!outfile) {
            fprintf(stderr, "Flex could not open %s\n",FileName);
            exit(1);
        }
        yyout = outfile;
    }
    else {
        strncpy(FileName, argv[optind-1], strlen(argv[optind-1])-4);
        FileName[strlen(argv[optind-1])-4] = '\0';
        strcat(FileName, "-EDIT.ps");
        outfile = fopen(FileName, "wb");
        if (!outfile) {
            fprintf(stderr, "Flex could not open %s\n",FileName);
            exit(1);
        }
        yyout = outfile;
    }

    yylex();
    if (output_flag == 0) {
        fclose(yyout);
    }
    printf("Flex program finished running file %s\n", inputName);
    return 0;
}
like image 136
Spencer Rathbun Avatar answered Sep 20 '22 11:09

Spencer Rathbun