如何为施乐打印机创建动态作业票?
我正在用Python和Reportlab工具包来程序化地创建PDF文件,每个文件里有几千个文档,而每个文档的页数又不一样。
我遇到的问题是,我需要告诉打印机每一页应该用什么样的纸张来打印(比如,文档的第一页需要用预印的信头纸)。看起来我需要生成一种工作单,这里面包含这些信息。
我在创建JDF工作单方面有一些成功,但这些工作单只能在我们组织最新的打印机上运行,这些打印机使用的是Xerox Freeflow Server 8版本。
理想情况下,我需要一个解决方案,能够同时适用于我们的Freeflow Server 7版本和Xerox DocuSP打印机。我尝试过把JDF工作单发送到这些打印机,但没有成功。
有没有其他类型的工作单系统可以使用,或者有什么办法让我们所有的打印机都能识别JDF文件?
3 个回答
你应该去问你的打印机供应商(比如说是施乐)关于他们的DocuSp打印机支持JDF的具体情况。
也许你会幸运地得到这些信息。
除了JDF,没有其他标准的作业单格式。虽然还有一些特定于不同厂商的方法,但施乐可能也有他们自己的一套。去问问他们吧。
我也遇到过同样的问题。最后我发现自己走了弯路,主要是对PDF格式的误解。我们通常把PDF文件看作是打印机的所见即所得(WYSIWYG),但实际上并不是这样。在任何打印流程中,PDF文件都会被转换成某种中间格式,比如PostScript、TIFF图像,或者通常的PCL。
这种转换可能发生在你的本地计算机上,这就是为什么你需要驱动程序,或者在打印机本身上。如果是在打印机上发生的,你实际上是把PDF文件传输到另一台设置了适当转换系统的计算机上。
这听起来没什么问题,但有一点很反直觉,那就是PDF并没有定义页面顺序,这对于一个准备打印的格式来说非常不合理。这意味着你的文档没有“第一页”,你无法以任何方式原生定义它。
你有两个解决方案:
选择一种打印机架构,并使用它独特的设置介质类型的方法,这很麻烦,而且不具可移植性。
转换为一种允许设置介质类型并包含页面顺序概念的格式,比如PostScript。然后添加你的介质命令,并将这个文件发送给打印机。如果你的打印机有读取你选择的中间格式的驱动程序,它应该能将命令转换为它自己的介质切换版本。这种方法更具可移植性,但仍然不是完美的。
这有点像将你的C程序转换为汇编语言,以便移植到新的架构上。大体上是可行的,但你需要调整每个系统才能正常工作。
一个假设的流程是:
创建你的PDF文件 > 通过PDF到PostScript的转换工具或库处理它 > 通过自定义词法分析器在每个新页面添加介质类型命令 > 将PostScript文件发送到打印机
这工作量很大,但这可能是解决你问题的唯一办法。
示例
%{
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;
}
上面的代码是一个非常简单的词法分析器,用于找到从标准输入获取的每个showpage命令,并输出一个showpage setpagedevice命令集。setpagedevice的MediaType命令是一种与打印机无关的设置页面使用纸张类型的方法。
flex -Cf scanner.l
gcc -O -o lineCount.exe scanner.c
它通过标准输入接收输入,并输出到标准输出。
下面是一个更完整的词法分析器。它使用GNU getopts来处理命令行选项,并有两个规则,这样它也会为第一页设置页面设备。它可能无法完美抓取页面,并且只有一个纸张类型的变量,所以功能有限。另一方面,它非常开放,可以根据你想要的方式来确定使用的页面设备。
可以考虑的新规则是识别它正在查看的页面类型,或者是一个额外的输入文件,每行对应一页。
/*
* 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;
}
我在Xerox支持论坛上收到了"RogerK-Xerox"的回复。
Xerox使用一种基于XML的票据系统,叫做Xerox打印指令格式(XPIF)。你可以通过打开你的Xerox自定义打印驱动程序,设置一些打印属性,然后导出Xerox作业票据来了解这种格式是怎么工作的。具体操作是选择打印驱动程序上的“高级”选项卡,点击Xerox作业票据旁边的'+',然后选择'导出Xerox作业票据...',最后点击'导出...'按钮。
为了获得XPIF编程指南的完整访问权限,我认为你需要在http://www.xerox-solutions.net/Partners上注册。
我尝试了上述方法,确实生成了一个包含作业票据指令的XML文件,这个文件可以重新加载到打印驱动程序中。现在我在寻找一种方法,可以将这些文件与打印机热文件夹一起使用,这样更符合我们当前的工作流程。打印机需要知道哪个XPIF票据对应哪个PDF文件。
似乎可以通过简单地将XPIF文件和PDF文件合并,把XPIF文件放在PDF文件的开头。然后这个文件可以拖入热文件夹,Xerox打印机就能分辨出作业票据和PDF文件。
我测试了这个方法,效果如预期 :-)。在PDF文件开头添加一些任意的XML数据会导致它在Adobe Acrobat中无法打开。不过,令人惊讶的是,这种文件在Evince文档查看器中可以正常打开。