SDB:Using Your Own Filters to Print with CUPS
情况
您想使用自定义过滤器进行 CUPS 打印或调试过滤问题。
本文面向有经验的 Linux 用户。
要求
您应该对打印系统有基本的了解,并且熟悉 CUPS(请参阅 SDB:CUPS in a Nutshell)、bash 脚本和常用的命令行工具。
此处的一些细节可能略有陈旧(具体取决于 CUPS 版本),但总体而言,这些内容仍然有效。
本文档描述了如何在 Linux 下使用自己的过滤器进行 CUPS 打印,直至 2.x 版本,以及传统的过滤系统和后端。
如今的无驱动程序打印工作流程则大不相同。
CUPS 过滤器系统背景信息
CUPS 默认过滤器系统通常会产生非常好的结果,并提供多种可能性来调整打印输出以满足您的要求。但是,在某些特殊情况下,可能需要自定义过滤器。
过滤器激活顺序
CUPS 默认过滤通常通过 /usr/share/cups/mime/mime.types 或 /etc/cups/mime.types 以及 /usr/share/cups/mime/mime.convs 或 /etc/cups/mime.convs 中定义的条目来工作。在适当的打印队列中,PPD 文件中的 *cupsFilter 条目会被使用。
特定 Linux 系统上特定打印机型号的特定打印作业的实际过滤取决于各种条件,请参阅 SDB:CUPS in a Nutshell 中的“过滤器系统做什么以及它是如何工作的”和 SDB:How to Report a Printing Issue 中的“背景信息”。
要确定特定 Linux 系统上特定打印机型号的特定打印作业的实际过滤,请检查 CUPS 日志消息,位于 /var/log/cups/error_log 中 - 例如,要获得概览,您可以运行类似“grep PID /var/log/cups/error_log”的命令 - 有关详细信息,请参阅 SDB:How to Report a Printing Issue 中的“通常提供 CUPS 调试消息”。
以下是当使用 PostScript 打印机并且使用包含在 Ghostscript 中的打印机驱动程序时,传统打印数据格式 PostScript 的过滤工作方式的示例。
PostScript 打印机
打印 PostScript 格式的文档
- 根据 /usr/share/cups/mime/mime.types 或 /etc/cups/mime.types 中的条目,PostScript 格式的数据具有 MIME 类型 application/postscript。
根据 /usr/share/cups/mime/mime.convs 或 /etc/cups/mime.convs 中的条目“application/postscript application/vnd.cups-postscript 66 pstops”,具有 MIME 类型 application/postscript 的数据通过 CUPS 过滤器 pstops(即,通过 /usr/lib/cups/filter/pstops)转换为具有 MIME 类型 application/vnd.cups-postscript 的数据。
CUPS 内部为此转换的成本为 66 个单位。 - 具有 MIME 类型 application/vnd.cups-postscript 的数据被发送到 PostScript 打印机。
打印纯文本
- 根据 /usr/share/cups/mime/mime.types 或 /etc/cups/mime.types 中的条目,纯文本具有 MIME 类型 text/plain(请参阅 SDB:Plain Text versus Locale)。
根据 /usr/share/cups/mime/mime.convs 或 /etc/cups/mime.convs 中的条目“text/plain application/postscript 33 texttops”,具有 mime 类型 text/plain 的数据通过 CUPS 过滤器 texttops(即,通过 /usr/lib/cups/filter/texttops)转换为具有 mime 类型 application/postscript 的数据。
CUPS 内部为此转换的成本为 33 个单位。 - 如上所述,具有 MIME 类型 application/postscript 的数据通过 CUPS 过滤器 /usr/lib/cups/filter/pstops 转换为具有 MIME 类型 application/vnd.cups-postscript 的数据,成本为 66。
加上第一次转换,总成本为 99 个单位。 - 具有 MIME 类型 application/vnd.cups-postscript 的数据被发送到 PostScript 打印机。
非 PostScript 打印机(例如,PCL 打印机)
打印 PostScript 格式的文档
- 如上所述,具有 MIME 类型 application/postscript 的数据通过 CUPS 过滤器 /usr/lib/cups/filter/pstops 转换为具有 MIME 类型 application/vnd.cups-postscript 的数据。
- 根据 PPD 文件中的 *cupsFilter 条目,例如 Foomatic PPD 文件中的条目
*cupsFilter: "application/vnd.cups-postscript 0 foomatic-rip"
具有 MIME 类型 application/vnd.cups-postscript 的数据通过 Foomatic 过滤器 /usr/lib/cups/filter/foomatic-rip 转换为特定于打印机的数据(例如,对于 PCL 打印机的 PCL 数据)。 - 然后将特定于打印机的数据发送到打印机。
打印纯文本
- 如上所述,具有 MIME 类型 text/plain 的数据通过 CUPS 过滤器 /usr/lib/cups/filter/texttops 转换为具有 MIME 类型 application/postscript 的数据。
- 具有 MIME 类型 application/postscript 的数据通过 CUPS 过滤器 /usr/lib/cups/filter/pstops 转换为具有 MIME 类型 application/vnd.cups-postscript 的数据。
- 具有 MIME 类型 application/vnd.cups-postscript 的数据通过 Foomatic 过滤器 /usr/lib/cups/filter/foomatic-rip 转换为特定于打印机的数据。
- 然后将特定于打印机的数据发送到打印机。
过滤器选项设置的可能性
请参阅 https://:631/help/options.html 或 http://www.cups.org/documentation.php/doc-1.3/options.html
将输入发送到文件的过滤器,用于调试
为了调试,以便可以检查特定过滤程序获得的输入,可以使用自制过滤器 /usr/lib/cups/filter/get_filter_input,该过滤器将输入发送到文件,例如如下
#! /bin/bash
# Have debug info in /var/log/cups/error_log:
set -x
# Set the output file name:
this_script_basename=$( basename ${BASH_SOURCE[0]} )
output_file="/tmp/$this_script_basename.input"
# Have the input at fd0 (stdin) in any case:
test -n "$6" && exec <"$6"
echo "INFO: sending data to $output_file ..." 1>&2
# Forward the data from stdin to the output file:
if dd of="$output_file"
then echo "INFO: sent data to $output_file" 1>&2
exit 0
else echo "ERROR: failed to send data to $output_file" 1>&2
exit 1
fi
参考 SDB:使用您自己的后端进行 CUPS 打印 中的“将输入发送到文件的后端,用于调试”。
将此脚本安装为 /usr/lib/cups/filter/get_filter_input,具有与其它过滤器相同的拥有者、组和权限(通常为“rwxr-xr-x root root”)。
要获取特定过滤程序的输入,需要将该过滤程序替换为 /usr/lib/cups/filter/get_filter_input,如下所示
首先以 root 身份保存原始的特定过滤程序
mv /usr/lib/cups/filter/somefilter /usr/lib/cups/filter/somefilter.original
然后将 /usr/lib/cups/filter/get_filter_input 用作 /usr/lib/cups/filter/somefilter
cp -p /usr/lib/cups/filter/get_filter_input /usr/lib/cups/filter/somefilter
现在打印一个单独的测试打印作业,您想检查 /usr/lib/cups/filter/somefilter 获得的输入,该输入存储在 /tmp/somefilter.input 文件中。
由于 /usr/lib/cups/filter/get_filter_input 不在 stdout 上输出任何内容,因此后续过滤器将不会获得输入,因此打印该测试打印作业将报告失败,因为后续过滤器将失败。
要恢复原始过滤,请恢复原始的特定过滤程序
mv -f /usr/lib/cups/filter/somefilter.original /usr/lib/cups/filter/somefilter
这样,您可以逐步获取每个过滤程序获得的输入,该过滤程序用于处理特定类型的打印作业原始数据。
要获取在您的特定系统上处理特定类型的打印作业数据运行的特定过滤程序,请检查您的特定 CUPS 调试消息(请参阅 SDB:如何报告打印问题 中的“通常提供 CUPS 调试消息”),例如,您可以运行(以 root 身份)
grep PID /var/log/cups/error_log
请参阅上面的“过滤器激活顺序”。
应用示例
以打印机特定编码打印纯文本
您想使用点阵打印机在连续纸上填写带有碳复写纸的表格。为此,点阵打印机队列必须将纯文本转发到打印机,但字符编码必须自定义为打印机的编码(请参阅 SDB:纯文本与区域设置)。
在 PostScript+PCL 打印机上可选的 PCL 打印
PostScript 打印机可能无法打印极其复杂的 PostScript 文档。特别是如果打印机没有足够的内存,打印嵌入在 PostScript 文档中的高分辨率或颜色深度光栅图形可能是不可能的(请参阅 SDB:购买打印机和兼容性)。
1200x1200 dpi 位图图形需要的内存是 300x300 dpi 图形十六倍。32 位颜色深度需要的内存是 1 位黑白图像的 32 倍。因此,1200x1200 dpi 位图图形,具有 32 位颜色深度,需要的内存比相同图形在 1 位黑白和 300x300 dpi 分辨率下多 500 多倍。
直接的解决方案是在用于创建 PostScript 文件的应用程序中减少分辨率和颜色深度值。
打印系统可以将有问题 PostScript 文档转换为 PCL 数据(如果需要,分辨率或颜色深度较小),如上所述。要打印,PCL 数据需要具有足够内存的打印机,具体取决于分辨率和颜色深度。PostScript 打印机通常也可以通过 PCL 进行寻址。大多数 PostScript+PCL 打印机自动检测数据类型并在 PostScript 和 PCL 模式之间切换。
最简单的方法是为 PostScript+PCL 打印机创建一个额外的队列。此队列始终通过使用兼容的 PCL 打印机的 PPD 文件来生成 PCL 数据。
使用多个队列的缺点是需要查询所有队列才能显示该打印机上所有等待或活动的打印作业。虽然对于单个打印机或独立系统来说不是问题,但在多个用户使用的多个网络打印机的情况下,使用每个打印机多个队列可能会过于复杂。因此,对于每个 PostScript+PCL 打印机应该只有一个队列,该队列可以交替生成 PCL 数据,以启用通过 PCL 打印有问题 PostScript 文档(如果需要,分辨率和颜色深度较小)。
在 PostScript 打印机上使用 Ghostscript 进行 PostScript 预处理
如果打印机的 PostScript 解释器支持的 PostScript 版本(例如,版本 2)低于文档要求的版本(版本 3),PostScript 打印机将无法打印某些 PostScript 文档。
直接的解决方案是在用于生成 PostScript 文档的应用程序中相应地设置 PostScript 版本。但是,这并非总是可能的。
更通用、更简单的解决方案是为打印机创建一个额外的队列。此队列使用通用的 Foomatic PPD 文件,例如 /usr/share/cups/model/Postscript-level2.ppd.gz 或 /usr/share/cups/model/Generic/PostScript_Printer-Postscript.ppd.gz,因为这样可以通过 Ghostscript 进行预处理来生成 PostScript 版本 2。
PostScript 打印机无法正确打印(或根本无法打印)某些 PostScript 文档,因为它们缺少打印包含特殊字符(例如,欧元符号)或特定字形的 PostScript 文档所需的字体或字形。
最佳解决方案是在用于生成文档的应用程序中嵌入必要的字体。
在某些情况下,使用带有通用 Foomatic PPD 文件的额外队列有所帮助,如上所述,因为这样可以通过 Ghostscript 进行预处理来至少将 Ghostscript 字体集成到 PostScript 文档中。
假设通过额外的队列进行 Ghostscript 预处理,并且您的打印机是 PostScript+PCL 打印机,则需要三个队列用于同一个打印机(包括 PCL 打印的可能性)。上述已提及拥有每个打印机多个队列的缺点。因此,PostScript 预处理和 PCL 打印都应该可以通过单个队列实现。
将额外的过滤器阶段添加到默认 CUPS 过滤器系统
某些应用程序经常生成有问题或有故障的 PostScript 文档,这使得打印不可能或导致有故障的打印输出。在某些情况下,可以更正 PostScript 数据以更正或至少启用打印输出。如果可以自动使用脚本更正 PostScript 数据,则可以将更正脚本添加到默认 CUPS 过滤器系统作为额外的过滤器阶段。随后,将始终执行该脚本。因此,需要特别注意和彻底测试,以防止更正脚本在默认 CUPS 过滤器系统中造成比解决的问题更多的问题。
上述示例的步骤
以打印机特定编码打印纯文本
此处“纯文本”是指“以任何编码形式表示的文本的任何字节序列”,请参阅 SDB:纯文本与区域设置。
使用适合打印机型号的 Foomatic PPD 文件,像往常一样创建点阵打印机队列。
打开 PPD 文件 /etc/cups/ppd/queue.ppd 并插入行
*cupsFilter: "text/plain 0 TextToPrinter"
在以下行下方
*cupsFilter: "application/vnd.cups-postscript 0 foomatic-rip"
PPD 文件中 *cupsFilter 条目的目的是转换为特定于打印机的数据,然后将其发送到打印机。此特定条目直接通过 /usr/lib/cups/filter/TextToPrinter 将所有 MIME 类型为 text/plain 的数据转换为特定于打印机的数据,而无需其他过滤器的干预。因此,在此队列中打印 MIME 类型为 text/plain 的数据时,无法自定义打印输出,因为缺少必要的 CUPS 和 Foomatic 过滤器。
/usr/lib/cups/filter/TextToPrinter 是用于将纯文本转换为特定于打印机代码的过滤器脚本。此脚本必须精确调整到打印机型号。
许多点阵打印机支持与 IBM PC 兼容的字符编码。
假设您的纯文本采用 ISO-8859-1 编码。
您可以使用命令
recode "lat1..ibmpc"
将 ISO-8859-1 文本转换为与 IBM PC 兼容的字符代码。
如果打印机连接到第一个并行接口,请使用以下命令测试 recode "lat1..ibmpc" 是否生成正确的特定于打印机代码
echo -en "\rline 1\numlauts: ÄÖÜäöüß\nline 3\f" | recode "lat1..ibmpc" >/dev/lp0
如果不是,recode 提供了更多重编码可能性。最后,您可以使用“tr”转换单个字符或使用“sed”转换字符串。请参阅相关手册页。
此脚本显示可打印字符及其八进制代码
#! /bin/bash
# carriage return before printing
echo -en "\r"
# print printable 8-bit characters (CR, NL, TAB, BS, 32-126, 128-254)
echo -en "the special characters horizontal tab and backspace:\r\n"
echo -en "the next line consists of 5 horizontal tabs each followed by I\r\n"
echo -en "\tI\tI\tI\tI\tI\r\n"
echo -en "the next line consists of C backspace and =\r\n"
echo -en "C\b=\r\n"
echo -en "the printout of C backspace and = may look like an Euro sign\r\n"
echo -en "\nthe printable 7-bit octal codes (040-176) and characters:\r\n"
for i in 04 05 06 07 10 11 12 13 14 15 16
do for j in 0 1 2 3 4 5 6 7
do echo -en "${i}${j} \\0${i}${j} "
done
echo -en "\r\n"
done
for i in 170 171 172 173 174 175 176
do echo -en "${i} \\0${i} "
done
if test "$1" = "7"
then
# form feed after printing
echo -en "\r\f"
exit 0
fi
echo -en "\r\n"
if test "$1" = "a"
then
echo -en "\nthe 8-bit octal codes (200-237) and characters:\r\n"
for i in 20 21 22 23
do for j in 0 1 2 3 4 5 6 7
do echo -en "${i}${j} \\0${i}${j} "
done
echo -en "\r\n"
done
fi
echo -en "\nthe printable 8-bit octal codes (240-376) and characters:\r\n"
for i in 24 25 26 27 30 31 32 33 34 35 36
do for j in 0 1 2 3 4 5 6 7
do echo -en "${i}${j} \\0${i}${j} "
done
echo -en "\r\n"
done
for i in 370 371 372 373 374 375 376
do echo -en "${i} \\0${i} "
done
# form feed after printing
echo -en "\r\f"
不输入任何附加参数,输出通常是易于打印的 8 位代码。
通过引入“7”作为参数,将仅生成可打印的 7 位 ASCII 代码。参数“a”生成所有可打印的 8 位代码,但这可能会覆盖终端设置。因此,参数“a”不适合在屏幕上显示。
如果打印机连接到第一个并行接口,可以通过使用类似以下命令启动此脚本来找出所需的重编码:
Script a >/dev/lp0
输出将是集成在打印机中的字符集。这样,可以准确确定必要的字符编码。
如果上面的 recode 命令生成正确的打印机特定代码,/usr/lib/cups/filter/TextToPrinter 可能如下所示:
#! /bin/bash # see "man 7 filter" # debug info in /var/log/cups/error_log set -x # have the input at fd0 (stdin) in any case [ -n "$6" ] && exec <"$6" # carriage return before printing echo -en "\r" # printing recode "lat1..ibmpc" # form feed after printing echo -en "\f"
过滤器脚本的所有者、组和权限必须与 /usr/lib/cups/filter/ 中的其余过滤器匹配。
现在重新加载或重启 cupsd。
测试
可以使用以下命令打印 PostScript 测试页:
echo -en "line 1\numlauts: ÄÖÜäöüß\nline 3" | a2ps -1 -o - | lp -d queue lp -d queue /usr/share/ghostscript/*/examples/colorcir.ps
PostScript 由上述 CUPS 过滤器系统处理。因此,可以在 /var/log/cups/error_log 中找到上述 CUPS 过滤器调用。
I ... Started filter /usr/lib/cups/filter/pstops I ... Started filter /usr/lib/cups/filter/foomatic-rip
可以使用以下命令打印 ISO-8859-1 测试页:
echo -en "line 1\numlauts: ÄÖÜäöüß\nline 3" | lp -d queue lp -d queue /usr/lib/cups/filter/TextToPrinter
现在 /var/log/cups/error_log 仅包含过滤器调用:
I ... Started filter /usr/lib/cups/filter/TextToPrinter
如果在 /etc/cups/cupsd.conf 中激活了“LogLevel debug”,则可以从 /usr/lib/cups/filter/TextToPrinter 中看到调试输出,该输出位于 /var/log/cups/error_log 中。
D ... + '[' -n /var/spool/cups/... ']' D ... + exec D ... + echo -en '\r' D ... + recode lat1..ibmpc D ... + echo -en '\f'
可选
忽略除 MIME 类型为 text/plain 的数据之外的所有数据
如果您想使用点阵打印机通过打印纯文本的打印机特定代码来填充具有碳复写纸的连续纸表格,通常没有意义接受 MIME 类型不是 text/plain 的数据。
忽略 MIME 类型不是 text/plain 的所有数据
打开 PPD 文件并更改 MIME 类型 application/vnd.cups-postscript 的 *cupsFilter 条目,如下所示:
*cupsFilter: "application/vnd.cups-postscript 0 /bin/true"
通过这样做,对于 MIME 类型不是 text/plain 的所有数据,将在最后过滤阶段激活 /bin/true。这会记录一个成功的结论,而无需任何处理,并且随后会删除所有临时存储的数据。
忽略 MIME 类型为 text/plain 的所有数据,但相关的表单数据除外
如果您想使用点阵打印机通过打印纯文本的打印机特定代码来填充具有碳复写纸的连续纸表格,通常没有意义接受 MIME 类型为 text/plain 的数据,但相关的表单数据除外。
为了仅接受表单数据,必须将其区分开来,例如,在第一行使用特定的字符字符串,如“Foo...Bar”。在这种情况下,/usr/lib/cups/filter/TextToPrinter 可能如下所示:
#! /bin/bash # see "man 7 filter" # debug info in /var/log/cups/error_log set -x # pattern must match by "egrep -i" in first input line pattern="foo.*bar" # have the input at fd0 (stdin) in any case [ -n "$6" ] && exec <"$6" # testing read -t 1 -r line echo $line | egrep -i -q "$pattern" || exit 0 # carriage return before printing echo -en "\r" # printing echo $line | recode "lat1..ibmpc" recode "lat1..ibmpc" # form feed after printing echo -en "\f"
使用以下命令进行测试时:
echo -en "line 1\numlauts: ÄÖÜäöüß\nline 3" | lp -d queue
不打印任何内容,并且 /var/log/cups/error_log 包含:
... D ... + egrep -i -q 'foo.*bar' D ... + exit 0
但是,测试命令:
echo -en "line 1: FooBar\numlauts: ÄÖÜäöüß\nline 3" | lp -d queue
生成所需的输出。
如果过滤器脚本执行测试以检查输入数据是否是正确类型,以便仅接受可以正确处理的数据,则可以将过滤器脚本用作“System V 风格接口脚本”。请参阅“lpadmin”手册页。但是,由于 CUPS 2.2.0,“System V 风格接口脚本”不再支持,原因在于安全性。
在上述情况下(点阵打印机仅打印纯文本),足以在不使用 PPD 文件的情况下创建队列。相反,将上述过滤器脚本用作“System V 风格接口脚本”。
lpadmin -p queue -i /usr/lib/cups/filter/TextToPrinter ...
CUPS 实际执行的过滤器脚本是 /etc/cups/interfaces/queue,它是 /usr/lib/cups/filter/TextToPrinter 的副本。
任何类型的输入数据都仅由“System V 风格接口脚本”处理。因此,不可能自定义此队列中的打印输出,因为缺少必要的 CUPS 和 Foomatic 过滤器。
PostScript+PCL 打印机上的可选 PCL 打印
使用此特定打印机型号的制造商 PPD 文件来创建 PostScript+PCL 打印机的队列。或者,使用通用的 CUPS PPD 文件 /usr/share/cups/model/Postscript.ppd.gz 或通用的 Foomatic PPD 文件,如 /usr/share/cups/model/Postscript-level2.ppd.gz 或 /usr/share/cups/model/Generic/PostScript_Printer-Postscript.ppd.gz,将打印机作为通用的 PostScript 打印机运行。
如果您使用了通用的 Foomatic PPD 文件,请按如下方式更改 /etc/cups/ppd/queue.ppd:
*cupsFilter: "application/postscript-problematic 0 PsToPCL" *cupsFilter: "application/vnd.cups-postscript 0 foomatic-rip"
或者,将以下行插入 /etc/cups/ppd/queue.ppd,如通用 Foomatic PPD 文件中一样:
*cupsFilter: "application/postscript-problematic 0 PsToPCL" *cupsFilter: "application/vnd.cups-postscript 0 ToPrinter"
*cupsFilter 条目在 PPD 文件中的目的是转换为打印机特定的数据,然后将其发送到打印机。此特定条目通过 /usr/lib/cups/filter/PsToPCL 直接转换所有 MIME 类型为 application/postscript-problematic 的数据,而无需其他过滤器的干预。在以这种方式打印 MIME 类型为 application/postscript-problematic 的数据时,无法自定义打印输出,因为缺少必要的 CUPS 和 Foomatic 过滤器。
将新的 MIME 类型 application/postscript-problematic 作为单独的附加行插入 /usr/share/cups/mime/mime.types 或 /etc/cups/mime.types:
application/postscript-problematic
否则,CUPS 将不会接受此 MIME 类型。
/usr/lib/cups/filter/PsToPCL 是必须创建的过滤器脚本,用于将 PostScript 转换为打印机特定的代码。此脚本必须精确调整到打印机型号。
大多数 PostScript+PCL 打印机都理解打印语言 PCL5e,该语言由 Ghostscript 驱动程序 ljet4 和 lj4dith(用于 Floyd-Steinberg 抖动)以及 ljet4d(用于分辨率高达 600 dpi 的双面打印)生成。
如果打印机连接到第一个并行接口,请使用以下 Ghostscript 命令测试 ljet4(或其他 PCL5e 驱动程序)是否生成正确的打印机特定代码:
gs -q -dBATCH -dNOPAUSE -sDEVICE=ljet4 -sOutputFile=/dev/lp0 /usr/share/ghostscript/*/examples/colorcir.ps
如果不是这种情况,Ghostscript 提供了其他 PCL 驱动程序(请参阅 SDB 文章 SDB:Purchasing a Printer and Compatibility)。
如果使用上述“gs”命令正确打印了彩色椭圆,则将 /usr/lib/cups/filter/PsToPCL 过滤器转换为使用 ljet4 以 300 dpi 的分辨率将 MIME 类型为 application/postscript-problematic 的数据转换为 PCL5e 的方法可能如下所示:
#! /bin/bash # see "man 7 filter" # debug info in /var/log/cups/error_log set -x # have the input at fd0 (stdin) in any case [ -n "$6" ] && exec <"$6" # printing gs -q -dBATCH -dPARANOIDSAFER -dNOPAUSE -sDEVICE=ljet4 -r300 -sOutputFile=- -
所有其他数据具有 MIME 类型 application/vnd.cups-postscript 将由 /usr/lib/cups/filter/foomatic-rip 处理或由 /usr/lib/cups/filter/ToPrinter 直接发送到打印机。
/usr/lib/cups/filter/ToPrinter 可能如下所示:
#! /bin/bash # see "man 7 filter" # debug info in /var/log/cups/error_log set -x # have the input at fd0 (stdin) in any case [ -n "$6" ] && exec <"$6" # printing cat -
过滤器脚本的所有者、组和权限必须与 /usr/lib/cups/filter/ 中的其余过滤器匹配。
现在重新加载或重启 cupsd。
CUPS 选项:
-o document-format=application/postscript-problematic
允许您在命令行上将要打印的 PostScript 文档的 MIME 类型设置为 application/postscript-problematic。根据是否设置此选项,数据将使用特定的过滤器 /usr/lib/cups/filter/PsToPCL 处理,或使用通用的 CUPS 过滤器。
可以使用以下命令使用 /usr/lib/cups/filter/PsToPCL 打印 PostScript 测试页:
lp -d queue -o document-format=application/postscript-problematic /usr/share/ghostscript/*/examples/colorcir.ps
结果,/var/log/cups/error_log 包含:
I ... Started filter /usr/lib/cups/filter/PsToPCL ... D ... + '[' -n /var/spool/cups/... ']' D ... + exec D ... + gs -q -dBATCH -dPARANOIDSAFER -dNOPAUSE -sDEVICE=ljet4 -r300 -sOutputFile=- -
可选
您可以创建一个队列实例,其中该选项
-o document-format=application/postscript-problematic
已预设。
lpoptions -o document-format=application/postscript-problematic -p queue/problematic
通过这样做,您可以避免每次都必须在命令行中输入此选项,只需输入队列实例,例如:
lp -d queue/problematic /usr/share/ghostscript/*/examples/colorcir.ps
可选 PCL 打印的网络客户端程序
不幸的是,新的 MIME 类型 application/postscript-problematic 仅在本地主机上可用,而不在网络上可用。
要从运行本地 cupsd 的远程客户端打印:
要么将 MIME 类型添加到客户端主机上的 /usr/share/cups/mime/mime.types 或 /etc/cups/mime.types,
要么在打印命令中指定 CUPS 服务器:
lp -d queue -h server -o document-format=application/postscript-problematic
或者客户端主机具有“仅客户端”配置(没有本地运行的 cupsd,但在 /etc/cups/client.conf 中有一个 ServerName 条目)。
不幸的是,实例仅在本地主机上可用。因此,如果您想从远程客户端打印,则必须每次在命令行中显式输入该选项,或者必须在客户端主机上创建该实例。
将有问题 PDF 文档打印为 PCL
Ghostscript 也可以直接处理 PDF 文档,但前提是它们作为普通文件接收,而不是通过 stdin 接收。只有链中的第一个过滤器从 CUPS 节文件接收其输入,而 /usr/lib/cups/filter/PsToPCL 是唯一的过滤器。因此,可以按如下方式更改此过滤器,以便 Ghostscript 可以直接从 CUPS 节文件接收其输入:
#! /bin/bash # see "man 7 filter" # debug info in /var/log/cups/error_log set -x # set inputfile to where the input comes from inputfile="-" [ -n "$6" ] && inputfile="$6" # printing gs -q -dBATCH -dPARANOIDSAFER -dNOPAUSE -sDEVICE=ljet4 -r300 -sOutputFile=- $inputfile
使用 PJL 命令在 PostScript+PCL 打印机上从 PostScript 切换到 PCL
许多 PostScript+PCL 打印机都理解作业控制语言 PJL。如果您的打印机不会自动从 PostScript 切换到 PCL,但支持 PJL,则可以使用 PJL 命令强制切换。
可以扩展 /usr/lib/cups/filter/PsToPCL,以便在 PCL 数据之前和之后发送相应的 PJL 命令:
#! /bin/bash # see "man 7 filter" # debug info in /var/log/cups/error_log set -x # set inputfile to where the input comes from inputfile="-" [ -n "$6" ] && inputfile="$6" # switch to PCL and do a PCL reset echo -en "\033%-12345X@PJL ENTER LANGUAGE = PCL\n\033E" # printing gs -q -dBATCH -dPARANOIDSAFER -dNOPAUSE -sDEVICE=ljet4 -r300 -sOutputFile=- $inputfile # PCL reset and PJL end of job echo -en "\033E\033%-12345X\n"
同样,可以将其他作业控制语言中的控制命令发送到打印机。
使用 PJL 命令从 PCL 切换到 PostScript
在使用 PJL 命令从 PostScript 切换到 PCL 后,最后的 PJL 字符串 "\033%-12345X" 应该将打印机切换回其原始 PostScript 模式。要强制使用 PJL 命令从 PCL 切换到 PostScript,请按如下方式扩展 /usr/lib/cups/filter/ToPrinter:
#! /bin/bash # see "man 7 filter" # debug info in /var/log/cups/error_log set -x # have the input at fd0 (stdin) in any case [ -n "$6" ] && exec <"$6" # switch to PostScript echo -en "\033%-12345X@PJL ENTER LANGUAGE = POSTSCRIPT\n" # printing cat - # PostScript end of transmission and PJL end of job echo -en "\004\033%-12345X\n"
如果已使用制造商的打印机特定 PPD 文件创建了队列,则应将相应的作业控制命令包含在 PPD 中(作为 *JCL... 条目)。CUPS 会自动将这些命令发送到打印机,因此不需要任何额外的作业控制命令。
使用 PJL 命令在 PCL 模式下设置特定的打印选项
如果您的打印机理解 PCL 和 PJL,则可以使用 PJL 命令激活一些打印选项。PJL+PCL 打印作业的语法是:
\033%-12345X@PJL SET option-1 = value-1 @PJL SET option-2 = value-2 ... @PJL SET option-n = value-n @PJL ENTER LANGUAGE = PCL PCL-commands+data\033%-12345X
每个 PJL 打印作业必须以恰好一个“通用退出语言”命令 "\033%-12345X" 开头和结尾。每行 PJL 必须以恰好一个换行符 "\n" 结尾。可能的选项及其值取决于打印机型号。
如果打印机连接到第一个并行接口,请使用以下命令测试 PJL 命令是否按请求工作。此示例激活了省墨模式和手动确认打印(例如,以便能够插入特殊纸张):
echo -en "\033%-12345X@PJL SET ECONOMODE = ON\n@PJL SET MANUALFEED = ON\n@PJL ENTER LANGUAGE = PCL\n" >/dev/lp0 gs -q -dBATCH -dNOPAUSE -sDEVICE=ljet4 -sOutputFile=/dev/lp0 /usr/share/ghostscript/*/examples/colorcir.ps echo -en "\033%-12345X\n" >/dev/lp0
按如下方式扩展 /usr/lib/cups/filter/PsToPCL 以发送相应的 PJL 命令:
#! /bin/bash # see "man 7 filter" # debug info in /var/log/cups/error_log set -x # set inputfile to where the input comes from inputfile="-" [ -n "$6" ] && inputfile="$6" # PJL printer setup echo -en "\033%-12345X@PJL SET ECONOMODE = ON\n@PJL SET MANUALFEED = ON\n" # switch to PCL and do a PCL reset echo -en "@PJL ENTER LANGUAGE = PCL\n\033E" # printing gs -q -dBATCH -dPARANOIDSAFER -dNOPAUSE -sDEVICE=ljet4 -r300 -sOutputFile=- $inputfile # PCL reset and PJL end of job echo -en "\033E\033%-12345X\n"
在 PostScript 打印机上使用 Ghostscript 进行 PostScript 预处理
使用制造商的打印机特定 PPD 文件创建 PostScript 打印机的队列,或使用通用的 CUPS 或 Foomatic PPD 文件将打印机作为通用的 PostScript 打印机运行(如上所述)。
将新的 MIME 类型 application/postscript-pswrite 作为附加行插入:
application/postscript-pswrite
在 /usr/share/cups/mime/mime.types 或 /etc/cups/mime.types 中。
现在,将以下行插入:
application/postscript-pswrite application/postscript 33 PsWrite
在 /usr/share/cups/mime/mime.convs 或 /etc/cups/mime.convs 中。
通过这样做,所有 MIME 类型为 application/postscript-pswrite 的数据都将通过 /usr/lib/cups/filter/PsWrite 转换为 MIME 类型为 application/postscript 的数据。此过滤器适用于所有队列。
可以对 MIME 类型为 application/postscript-pswrite 的数据的打印输出进行大量自定义,因为 MIME 类型为 application/postscript 的数据会通过通用的 CUPS 和 Foomatic 过滤器。但是,/usr/lib/cups/filter/pstops 的可能性并不总是与 PostScript 预处理配合使用。但是,至少 PPD 文件中的打印机特定选项应该有效。
Ghostscript 驱动程序 pswrite 用于使用 Ghostscript 进行 PostScript 预处理。
/usr/lib/cups/filter/PsWrite 过滤器可能如下所示:
#! /bin/bash # see "man 7 filter" # debug info in /var/log/cups/error_log set -x # set inputfile to where the input comes from inputfile="-" [ -n "$6" ] && inputfile="$6" # printing gs -q -dBATCH -dPARANOIDSAFER -dNOPAUSE -sDEVICE=pswrite -sOutputFile=- $inputfile
在最新的 Ghostscript 版本中,“pswrite”已被“ps2write”取代,后者输出 PostScript level 2,因此对于最新的 Ghostscript 版本,必须使用“-sDEVICE=ps2write”。
与其通过“gs ...”直接调用 Ghostscript,不如使用像 /usr/bin/ps2ps 和 /usr/bin/ps2ps2 这样的脚本提供预定义的 Ghostscript 调用。对于旧的 Ghostscript 版本,这些脚本需要常规文件作为输入和输出(即,脚本必须像“ps2ps2 input.ps output.ps”一样调用),而在最新的 Ghostscript 版本中,它也适用于 stdin 和 stdout(即,脚本可以像“ps2ps2 - -”一样调用)。
在后一种情况下,/usr/lib/cups/filter/PsWrite 过滤器可以简化如下:
#! /bin/bash # see "man 7 filter" # debug info in /var/log/cups/error_log set -x # set inputfile to where the input comes from inputfile="-" [ -n "$6" ] && inputfile="$6" # printing ps2ps2 $inputfile -
过滤器脚本的所有者、组和权限必须与 /usr/lib/cups/filter/ 中的其余过滤器匹配。
现在重新加载或重启 cupsd。
CUPS 选项:
-o document-format=application/postscript-pswrite
允许您在命令行上将要打印的 PostScript 文档的 MIME 类型设置为 application/postscript-pswrite。
根据是否设置此选项,数据将使用特定的过滤器 /usr/lib/cups/filter/PsWrite 进行预处理,或者仅执行通用的 CUPS 过滤。由于 /usr/lib/cups/filter/PsWrite 是链中的第一个过滤器,因此它会直接从 CUPS 节文件接收其输入。因此,也可以预处理 PDF 文档。
可以使用 /usr/lib/cups/filter/PsWrite 使用以下命令打印 PostScript 测试页:
lp -d queue -o document-format=application/postscript-pswrite /usr/share/ghostscript/*/examples/colorcir.ps
结果,/var/log/cups/error_log 包含:
I ... Started filter /usr/lib/cups/filter/PsWrite I ... Started filter /usr/lib/cups/filter/pstops ... D ... + gs -q -dBATCH -dPARANOIDSAFER -dNOPAUSE -sDEVICE=pswrite -dLanguageLevel=1 -sOutputFile=- /var/spool/cups/...
可选
按照“PostScript+PCL 打印机上的可选 PCL 打印”部分中的描述,创建一个队列实例,其中该选项
-o document-format=application/postscript-pswrite
已预设。
按照“PostScript+PCL 打印机上的可选 PCL 打印”部分中的描述,从网络客户端进行 PostScript 预处理。
将额外的过滤器阶段添加到默认 CUPS 过滤器系统
将新的 mime 类型 application/postscript-prefiltered 添加到 /usr/share/cups/mime/mime.types 或 /etc/cups/mime.types,方法是附加以下行:
application/postscript-prefiltered
在 /usr/share/cups/mime/mime.convs 或 /etc/cups/mime.convs 中插入一条附加行,并修改“pstops”行如下:
application/postscript application/postscript-prefiltered 10 PsPrefilter application/postscript-prefiltered application/vnd.cups-postscript 66 pstops
这样,所有 mime 类型为 application/postscript 的数据都将使用 /usr/lib/cups/filter/PsPrefilter 进行预过滤,并转换为 mime 类型为 application/postscript-prefiltered 的数据。
随后,这些数据将由默认 CUPS 过滤器 CUPS-Filter /usr/lib/cups/filter/pstops 处理。
保留了所有自定义打印输出的选项,因为数据遍历了通常的 CUPS 和 Foomatic 过滤器。
这要求 /usr/lib/cups/filter/PsPrefilter 能够正确处理所有 mime 类型为 application/postscript 的数据。
/usr/lib/cups/filter/PsPrefilter 是您需要创建的过滤器脚本,用于预过滤 PostScript 数据。
例如,假设您使用的是旧的 CUPS 1.1 版本,并且想要解决旧的支持数据库文章“CUPS 中没有横向格式”(适用于 SuSE Linux 8.1)中描述的问题,其中必须将 DSC 注释“%%Orientation: Landscape”替换为“%%Orientation: Portrait”在某些应用程序程序的 PostScript 输出中,以解决该问题。
如果您想通过 PostScript 预过滤器脚本更改应用程序程序的 PostScript 输出,/usr/lib/cups/filter/PsPrefilter 可能如下所示:
#! /bin/bash # see "man 7 filter" # debug info in /var/log/cups/error_log set -x # have the input at fd0 (stdin) in any case [ -n "$6" ] && exec <"$6" # prefiltering sed -e 's/Orientation: Landscape/Orientation: Portrait/'
基于此示例,以下步骤表明了彻底测试以防止校正脚本导致比解决更多问题在默认 CUPS 过滤器系统中有多重要。
过滤器脚本必须与 /usr/lib/cups/filter/ 中的其他过滤器具有相同的所有者、组和访问权限。
必须重新加载或重启 cupsd。
测试
PostScript 打印测试,例如使用以下命令:
echo -en "Line 1\nUmlauts: ÄÖÜäöüß\nLine 3" | a2ps -1 -o - | lp -d queue lp -d queue /usr/share/ghostscript/*/examples/colorcir.ps
现在,/var/log/cups/error_log 应该包含以下过滤器调用:
I ... Started filter /usr/lib/cups/filter/PsPrefilter I ... Started filter /usr/lib/cups/filter/pstops
ISO-8859-1 文本打印测试,例如使用以下命令:
echo -en "Line 1\nUmlauts: ÄÖÜäöüß\nLine 3" | lp -d queue lp -d queue /usr/lib/cups/filter/PsPrefilter
现在,/var/log/cups/error_log 应该包含以下过滤器调用:
I ... Started filter /usr/lib/cups/filter/texttops I ... Started filter /usr/lib/cups/filter/PsPrefilter I ... Started filter /usr/lib/cups/filter/pstops
最后的测试应该提供一个错误的打印输出,错误地包含以下行:
sed -e 's/Orientation: Portrait/Orientation: Portrait/'
解释
/usr/lib/cups/filter/texttops 的 PostScript 输出包含来自 /usr/lib/cups/filter/PsPrefilter 的字符字符串“Orientation: Landscape”。但是,在后续的过滤器阶段,它被 /usr/lib/cups/filter/PsPrefilter 转换为字符字符串“Orientation: Portrait”,并以这种方式打印。
可以通过尽可能精确地指定要替换的字符字符串来改进 /usr/lib/cups/filter/PsPrefilter:
#! /bin/bash # see "man 7 filter" # debug info in /var/log/cups/error_log set -x # have the input at fd0 (stdin) in any case [ -n "$6" ] && exec <"$6" # prefiltering sed -e 's/^%%Orientation: Landscape$/%%Orientation: Portrait/'
重复测试
现在,失败的测试以及
echo '%%Orientation: Landscape' | a2ps -1 -r -o - | lp -d queue
都应该正确打印。
但是,在旧的 CUPS 1.1 版本中,
lp -d queue -o landscape /usr/lib/cups/filter/PsPrefilter
不会以横向模式打印,而是以纵向模式打印,尽管文本已经为横向模式正确定位。从 CUPS 版本 1.1.18 开始,这可以正确工作。
CUPS 在版本 1.1.18 之前的错误打印输出的原因是选项“-o landscape”将行添加到
%%Orientation: Landscape
/usr/lib/cups/filter/texttops 的 PostScript 输出中,这导致后续过滤器 /usr/lib/cups/filter/pstops 将表示旋转 90 度,以便以横向模式打印。但是,/usr/lib/cups/filter/PsPrefilter 阻止了这一点。
从 CUPS 版本 1.1.18 开始,CUPS 特定的行
%cupsRotation: 90
用于代替“%%Orientation”条目,以便提示 CUPS 过滤器系统将表示旋转 90 度。
CUPS 1.1.18 版本之前的过滤器进一步改进
在 CUPS 1.1.18 版本之前的版本中,防止 90 度旋转必须依赖于生成 PostScript 数据的程序。通常,生成程序在“%%Creator”行中指定,例如在 /usr/lib/cups/filter/texttops、a2ps、NetScape 和 Mozilla 中
%%Creator: texttops/CUPS ... %%Creator: a2ps version ... %%Creator: Mozilla (NetScape) ... %%Creator: Mozilla PostScript module ...
因此,可以通过将防止 90 度旋转限制为已知的存在问题的情况,并在所有其他情况下保持 PostScript 数据未修改,来改进 /usr/lib/cups/filter/PsPrefilter
#! /bin/bash
# see "man 7 filter"
# debug info in /var/log/cups/error_log
set -x
# have the input at fd0 (stdin) in any case
[ -n "$6" ] && exec <"$6"
# for simple testing with "egrep" have the input as regular file
cleanup() { EXIT_CODE=$? ; rm -f $INPUT &>/dev/null ; exit $EXIT_CODE ; }
trap 'cleanup' 0 1 2 3 15
MY_NAME=${0##*/}
INPUT=$( mktemp /var/spool/cups/tmp/$MY_NAME.XXXXXX ) || exit 1
cat - >$INPUT
# prefiltering only for particular PostScript "Creator" patterns
if egrep -q '^%%Creator: a2ps|^%%Creator: Mozilla' $INPUT
then sed -e 's/^%%Orientation: Landscape$/%%Orientation: Portrait/' $INPUT
exit $?
fi
# otherwise no prefiltering
cat $INPUT
最终测试
如上所述,测试行“%%Creator: a2ps”,以确保在 PostScript 数据由 /usr/lib/cups/filter/texttops 生成时,“sed”命令不会被错误执行
echo -e '%%Orientation: Landscape\n%%Creator: a2ps' | lp -d queue echo -e '%%Orientation: Landscape\n%%Creator: a2ps' | lp -d queue -o landscape echo -e '%%Orientation: Landscape\n%%Creator: a2ps' | a2ps -1 -o - | lp -d queue echo -e '%%Orientation: Landscape\n%%Creator: a2ps' | a2ps -1 -r -o - | lp -d queue
通常,关于所谓的“横向模式”打印,请参阅 SDB:Landscape Printing。
特定打印队列的自定义过滤器
上述过程通常描述了如何实现影响所有打印队列上所有打印作业的自定义过滤器,因为更改应用于常规配置文件(如 mime.types 和 mime.convs)。
实现仅对特定打印队列生效的基本思路是不通过影响所有打印作业或所有打印队列的常规配置文件来定义它,而是通过特定于打印队列的配置文件来定义它。
例如,上述描述的“System V 风格接口脚本”是特定于单个打印队列的。
对于常规打印队列,PPD 文件 /etc/cups/<queue_name>.ppd 是实现专门针对单个打印队列的自定义过滤器的唯一特定于打印队列的配置文件。
直到 CUPS < 1.3,“*cupsFilter:”条目是 PPD 文件中指定特定于打印队列的过滤器的唯一方法。 这种方法只能提供必须输出最终特定于打印机的格式的过滤器。 无法在转换链的各个步骤之间插入过滤器。 特别是,无法通过 PPD 文件中的“*cupsFilter:”条目预处理输入。
从 CUPS 1.3 开始,可以通过将“*cupsPreFilter:”条目添加到 PPD 文件来预处理输入,请参阅“CUPS PPD 扩展”文档,例如 CUPS 1.3 的文档 http://cups.org/documentation.php/doc-1.3/spec-ppd.html,但请注意,使用“*cupsPreFilter:”进行预处理不得更改数据类型(即输入和输出的 MIME 类型相同)。 例如,可以使用 Ghostscript 的 pswrite 或 ps2write 进行 PostScript 预处理,但与此相反,PDF 预处理不能这样工作,因为 pswrite 和 ps2write 输出 PostScript。 对于 PDF 预处理,可以使用 Ghostscript 的 pdfwrite,因为它输出 PDF,例如通过各种 /usr/bin/ps2pdf* 脚本。 尽管脚本名称仅指示 PostScript 输入,但它也适用于 PDF 输入,因为 Ghostscript 接受 PostScript 和 PDF 作为输入。
从 CUPS 1.5 开始,可以使用“*cupsFilter2:”条目代替“*cupsFilter:”,请参阅“CUPS PPD 扩展”文档,例如 CUPS 1.5 的文档 http://cups.org/documentation.php/doc-1.5/spec-ppd.html
特定于打印作业数据的自定义过滤器
上述过程通常描述了如何实现影响特定类型的所有打印作业数据(例如,所有 PostScript 数据)的自定义过滤器,因为更改是使用常规 MIME 类型(如“application/postscript”)应用的。
实现仅对特定打印作业数据应用自定义过滤器的基本思路是定义一个新的特殊 MIME 类型,该类型仅匹配特定的打印作业数据,然后仅为该特殊 MIME 类型创建自定义过滤器。
请参阅“man mime.types”了解如何定义 MIME 类型。
直到 CUPS 1.3,当多个 MIME 类型匹配打印作业数据时,类型名称按字母数字升序排序,并选择第一个类型。 例如,如果您定义了一个新的特殊 MIME 类型“application/postscript-special”,该类型仅匹配特殊类型的 PostScript,它将不起作用,因为通用 MIME 类型“application/postscript”将始终被选择,因为它也匹配特殊类型的 PostScript(因为它匹配任何 PostScript),并且“application/postscript”在“application/postscript-special”之前排序。
从 CUPS 1.4 开始,支持 MIME 类型的显式优先级设置(请查看“man mime.types”中的“TYPE MATCHING AND PRIORITY”,并参阅 http://cups.org/documentation.php/doc-1.4/man-mime.types.html)。
示例
假设应用程序“ACME CrazyPS”生成某种损坏/错误/奇怪的 PostScript,它无法按您需要的方式打印,并且您找到了修复该 PostScript 的方法,并且其 PostScript 标头如下
%!PS-Adobe-3.0 ... %%Creator: ACME CrazyPS
要设置一个特殊过滤器来仅修复该 PostScript,请定义一个特殊 MIME 类型(在 CUPS 的“.types”mime 类型描述文件中),该类型匹配 PostScript 文件(即以“%!”开头的的文件),该文件还必须包含“%%Creator: ACME CrazyPS”(在最初的 1024 个字节内),如下所示:
application/acme-crazy-postscript string(0,%!) + contains(0,1024,"%%Creator: ACME CrazyPS")
然后,定义一个转换规则(在 CUPS 的“.convs”mime 类型转换文件中),用于将该特殊类型的 PostScript 转换为可以由后续过滤器进一步处理的常规 PostScript
application/acme-crazy-postscript application/postscript 0 Fix-ACME-CrazyPS
创建新的过滤器 /usr/lib/cups/filter/Fix-ACME-CrazyPS,该过滤器实现将该特殊类型的 PostScript 转换为常规 PostScript 所需的内容。
最后,重新加载或重新启动 cupsd,以便它识别新的 MIME 类型、转换规则和过滤器。
由于从 PostScript 到 PDF 作为标准打印作业格式的转变(请参阅 Concepts printing),如果该特殊类型的 PostScript 可以直接修复并通过类似于以下内容的转换规则转换为 PDF,则可能更好:
application/acme-crazy-postscript application/pdf 0 ACME-CrazyPS-to-PDF
其中 /usr/lib/cups/filter/ACME-CrazyPS-to-PDF 实现了修复该特殊类型的 PostScript 以及将其转换为可以由后续过滤器进一步处理的常规 PDF。
限制和约束
对于 PostScript+PCL 打印机,不应将可选的 PCL 打印或 PostScript 或 PDF 预处理视为打印任何 PostScript 或 PDF 文档的万能药。
严格来说,使用 Ghostscript 进行 PostScript 或 PDF 预处理以使某些奇怪的 PostScript 或 PDF 打印是一种解决方法,正确的解决方案是修复生成奇怪的 PostScript 或 PDF 的那些应用程序。
使用 Ghostscript 进行 PostScript 或 PDF 预处理是一种解决方法,因为它可能导致未经验证的用户无法预料到的任意缺点。 根本原因在于,在从 PostScript/PDF 到 PostScript/PDF 的转换之后,Ghostscript 会得到一个全新的从头开始创建的 PostScript 或 PDF,除了其视觉外观外,它与原始 PostScript 或 PDF 没有共同之处,请参阅 http://bugs.ghostscript.com/show_bug.cgi?id=694853#c5 和 http://bugs.ghostscript.com/show_bug.cgi?id=695016#c1,其中包含以下内容(摘录):
Ghostscript 不会“修复”PDF 文件中的错误。 当您创建 PDF 文件作为输出时,它是一个全新的 PDF 文件,它不会继承原始文件的任何结构。
pdfwrite 的原始目标与 Adobe Acrobat Distiller 相同,即从 PostScript 输入生成 PDF 文件,PDF 文件应与输入具有相同的视觉外观。 Ghostscript 可以从任何有效的 Ghostscript 输入源(包括 PDF)生成 PDF 文件,但机制完全相同;输入被解释为生成一系列标记操作,然后处理这些操作以创建输出,在这种情况下是 PDF 文件。 再次,目标是相同的视觉外观。
ps2write 设备不是简单地“调整大小”您的 EPS 文件。 EPS 被完全解释,转换为图形原语,并传递给 ps2write 设备,该设备通过将这些图形原语转换回 PostScript 来创建全新的文件。
重要的是要理解这一点,因为尽管 Ghostscript 是一个 3 级解释器,但 ps2write 设备仅输出 2 级(因此 ps*2*write)。 输入中的任何 3 级结构都不会被保留。 在这种情况下,您的输入文件使用阴影模式,这是一种 3 级功能,经过 ps2write 后,这些模式将被渲染成图像。 这会增加文件大小并降低缩放对象的能力,它们不再是矢量原语。
但对于打印,相同的视觉外观意味着相同的打印输出,因此使用 Ghostscript 进行 PostScript 或 PDF 预处理不应导致真正的严重缺点(也许除了略低的质量,请参阅上述“渲染成图像”)。
因此,当特定用户使用特定类型的奇怪 PostScript 或 PDF 实现一个自定义过滤器,用于使用 Ghostscript 进行 PostScript 或 PDF 预处理,从而使他的特定类型的奇怪 PostScript 或 PDF 打印出符合他特定需求的 o.k. 时,这是一种合理的解决方法。
由于使用 Ghostscript 进行 PostScript 或 PDF 预处理只是一个解决方法,而不是解决方案,因此具有特定类型的奇怪 PostScript 或 PDF 的用户应将问题报告给生成该奇怪 PostScript 或 PDF 的应用程序的作者或供应商。
在任何情况下,Ghostscript 必须能够处理应用程序中的 PostScript 或 PDF。 如果 Ghostscript 无法处理它,它可能存在故障,无法打印。
有关如何使用 Ghostscript 测试 PostScript 或 PDF 文件是否似乎正确的信息,请参阅 SDB:How to Report a Printing Issue 中的“测试应用程序提交给 CUPS 的内容是否似乎正确”。