7

我通常将ghostscript其视为命令行工具;然而,我从未停止对那里存在的大量设置和选项感到惊讶——这是因为它ghostscript是一个成熟的 PostScript 语言解释器(我经常忘记)。

例如,在查询 Ghostscript 以获取输出设备的默认选项/设置(例如 'pdfwrite' 或 'tiffg4');学习如何检索给定输出设备的默认选项。但是,我想知道的是 - 这些选项与所谓的 PostScript 字典有关吗?

或者,换句话说——什么是 PostScript 字典?以及有哪些设施ghostscript可以查询(并可能)修改这些数据?

4

5 回答 5

10

用最简单的术语来说:在 PostScript 中,字典是 键(名称)+ 值对的列表。字典允许 PostScript 解释器查找键是否存在并获取其值以在任何过程中使用它。解释器还可以创建键、存储或修改值,甚至创建完整的自定义字典(由 PostScript 代码处理)。键通常是类型名称(但它们也可以是任何其他类型,但null除外)。

对于 PostScript 解释器的任何实现,必须始终存在其中两个字典:

  • systemdict 这个包含预定义的 PostScript 操作符(以及使它们执行 PostScript 规范所期望的操作的实现)。

  • userdict 它包含 PostScript 程序的变量和过程(将“过程”视为由语言定义的运算符和程序定义的值和参数组合而成的函数或子例程)。

关于名称的一个词:名称是其他编程语言的唯一标识符(并且它们区分大小写)。这些标识符可以是变量或过程名称。它们可以由 ASCII 的 256 个字符的任意组合组成(但它们不是字符串)。

您可能知道,PostScript 是一种面向堆栈的语言。它使用了几个堆栈:

  • 操作数堆栈 此堆栈保存每个操作数和中间操作的每个结果(将最后一个结果临时转入操作数堆栈的最顶部元素)。

  • 字典栈 顾名思义:这个栈只保存字典。因此,堆栈定义了任何键/名称查找的当前上下文。

  • 执行栈 这一个包含可执行对象,即主要是当前正在执行的程序文件。如果解释器中断了当前对象的执行,它会将被中断的对象放到这个堆栈中。在一个对象完全执行后,它会从堆栈中移除,并从现在最顶层的那个继续执行。

  • 图形状态堆栈 该堆栈承载当前用于弹出图形元素的上下文:当前线宽设置、当前字体、当前颜色或灰度值、当前路径... 当前图形状态可以保存(gsave)并在以后恢复(grestore)。最顶层的图形状态始终是当前图形状态

所有这些堆栈都是相互独立的。然而,操作数、字典和图形状态堆栈都在 PostScript 程序的控制之下(也就是说,可以被它操纵)。执行堆栈是解释器的唯一属性。

对于每个堆栈都有一定的限制(如可以存储在其上的元素数量等)。PostScript 知道可以操作堆栈的运算符:将新元素放入堆栈,删除最顶部的元素(pop),复制最顶部的元素(dup),打乱堆栈上元素的顺序(roll),交换两个顶部-大多数元素(exch),还有更多(PostScript 编程的一个很好的介绍是 Adob​​e 的“蓝皮书”)。

正如我已经说过的,字典有自己的堆栈,其中包含 PostScript 解释器可能使用的所有字典。

在该堆栈上可能有一个单独的字体字典,或者 PostScript 程序想要创建(使用dict关键字)并私下使用的任意数量的字典,或者特定于某个 P​​ostScript 解释器的一些字典,例如 Ghostscript。

systemdict永远是最底层的;以上是userdict. 这两个不能从字典堆栈中删除,而所有其他的都可以受制于任何堆栈操作运算符(例如pop从堆栈中删除最顶部的元素)。

每当解释器查找一个名字时,它都会在字典中搜索那个名字,从最上面的字典开始。因此userdict之前搜索过systemdict。一旦找到名称(键),解释器就会停止搜索并使用该键(或者更确切地说,它保存的值)。这种体系结构的结果是 PostScript 程序员可以systemdict用他自己的变体覆盖任何预定义的 PostScript 运算符。

此外,某些字典可以用于 PS 程序“私有”(不可访问,例如字体字典)或“只读”。


更新 ——更多答案:

于 2012-06-21T14:00:00.047 回答
8

其他答案已经涵盖了“什么是字典?” 你问题的一部分。现在让我们转向“Ghostscript 如何访问它们?”

也许问题应该是:“我(高级用户、开发人员、极客……)如何访问它们?”

您可以通过编写一个简单的 PostScript 程序单行程序来打印出 PostScript 解释器(可能是 Ghostscript)已知的任何可访问字典的内容 - 或者只需调用解释器(Ghostscript)并将程序代码移交给命令行 ( -c ...)。

为此,您只需要知道相应字典的名称。

让我们看一个有趣的内部 Ghostscript 字典,称为.distillersettings

gs \
 -dNODISPLAY \
 -c ".distillersettings {exch ==only ( ) print ==} forall quit"

结果:

/default -dict-
/prepress -dict-
/PSL2Printer -dict-
/ebook -dict-
/screen -dict-
/printer -dict-

乍一看,这可能不会告诉你太多。但是您可能会认出该字典中的一些键名:/prepress, /printer, /screen, /ebook...

-sDEVICE=pdfwrite所有这些您都可以在 Ghostscript 命令行上使用,以在您希望通过(Ghostscript 'Distiller'-类似功能)进行输出时请求一组预定义的设置。要请求这样一组设置,只需添加-dPDFSETTINGS=/printer到命令行。

现在再看一眼,您会发现.distillersettings字典的内容本质上是一组 6 个以上的字典。它是一本“字典中的字典”。

默认情况下不打印字典内容(不使用上面的 PostScript 代码)。但是,如果您需要它们,您可以使用特定于 Ghostscript 的过程,而不是上述命令===中的标准 PostScript 语言运算符。==此过程的行为与==execpt 相同,它还扩展字典并打印其中包含的所有键:值对。

小心这个===过程:-dict-你试图扩张的东西可能很长,可能会导致你失去视力。:-)

然而,在我们目前的情况下,它仍然是可以管理的:

gs \
 -dNODISPLAY \
 -c ".distillersettings {exch ==only ( ) print ===} forall quit"

现在的输出是:

 /default << /Optimize false /DoThumbnails false /PreserveEPSInfo true /ColorConversionStrategy /LeaveColorUnchanged /DownsampleMonoImages false /EmbedAllFonts true /CannotEmbedFontPolicy /Warning /PreserveOPIComments true /GrayACSImageDict << /HSamples [2 1 1 2] /VSamples [2 1 1 2] /QFactor 0.9 /Blend 1 >> /DownsampleColorImages false /PreserveOverprintSettings true /CreateJobTicket false /AutoRotatePages /PageByPage /NeverEmbed [/Courier /Courier-Bold /Courier-Oblique /Courier-BoldOblique /Helvetica /Helvetica-Bold /Helvetica-Oblique /Helvetica-BoldOblique /Times-Roman /Times-Bold /Times-Italic /Times-BoldItalic /Symbol /ZapfDingbats] /ColorACSImageDict << /HSamples [2 1 1 2] /VSamples [2 1 1 2] /QFactor 0.9 /Blend 1 >> /DownsampleGrayImages false /UCRandBGInfo /Preserve >>
 /prepress << /DoThumbnails true /MonoImageResolution 1200 /ColorImageDownsampleType /Bicubic /PreserveEPSInfo true /ColorConversionStrategy /LeaveColorUnchanged /GrayImageDownsampleType /Bicubic /EmbedAllFonts true /CannotEmbedFontPolicy /Error /PreserveOPIComments true /GrayImageResolution 300 /GrayACSImageDict << /ColorTransform 1 /QFactor 0.15 /Blend 1 /HSamples [1 1 1 1] /VSamples [1 1 1 1] >> /ColorImageResolution 300 /PreserveOverprintSettings true /CreateJobTicket true /AutoRotatePages /None /MonoImageDownsampleType /Bicubic /NeverEmbed [] /ColorACSImageDict << /ColorTransform 1 /QFactor 0.15 /Blend 1 /HSamples [1 1 1 1] /VSamples [1 1 1 1] >> /CompatibilityLevel 1.4 /UCRandBGInfo /Preserve >>
 /PSL2Printer << /DoThumbnails false /CompatibilityLevel 1.2 /TransferFunctionInfo /Preserve /MonoImageResolution 1200 /PreserveEPSInfo true /CompressFonts true /ColorImageDownsampleType /Bicubic /GrayImageDownsampleType /Bicubic /ColorConversionStrategy /LeaveColorUnchanged /EmbedAllFonts true /ColorACSImageDict << /ColorTransform 1 /QFactor 0.15 /Blend 1 /HSamples [1 1 1 1] /VSamples [1 1 1 1] >> /CannotEmbedFontPolicy /Error /PreserveOPIComments true /CompressPages true /GrayImageResolution 600 /GrayACSImageDict << /ColorTransform 1 /QFactor 0.15 /Blend 1 /HSamples [1 1 1 1] /VSamples [1 1 1 1] >> /ColorImageResolution 600 /PreserveOverprintSettings true /AutoRotatePages /None /MonoImageDownsampleType /Bicubic /ASCII85EncodePages true /MaxViewerMemorySize 8000000 /NeverEmbed [] /PreserveHalftoneInfo true /UCRandBGInfo /Preserve >>
 /ebook << /DoThumbnails false /MonoImageResolution 300 /ColorImageDownsampleType /Bicubic /PreserveEPSInfo false /ColorConversionStrategy /sRGB /GrayImageDownsampleType /Bicubic /EmbedAllFonts true /CannotEmbedFontPolicy /Warning /PreserveOPIComments false /GrayImageResolution 150 /GrayACSImageDict << /ColorTransform 1 /QFactor 0.76 /Blend 1 /HSamples [2 1 1 2] /VSamples [2 1 1 2] >> /ColorImageResolution 150 /PreserveOverprintSettings false /CreateJobTicket false /AutoRotatePages /All /MonoImageDownsampleType /Bicubic /NeverEmbed [/Courier /Courier-Bold /Courier-Oblique /Courier-BoldOblique /Helvetica /Helvetica-Bold /Helvetica-Oblique /Helvetica-BoldOblique /Times-Roman /Times-Bold /Times-Italic /Times-BoldItalic /Symbol /ZapfDingbats] /ColorACSImageDict << /ColorTransform 1 /QFactor 0.76 /Blend 1 /HSamples [2 1 1 2] /VSamples [2 1 1 2] >> /CompatibilityLevel 1.4 /UCRandBGInfo /Remove >>
 /screen << /DoThumbnails false /MonoImageResolution 300 /ColorImageDownsampleType /Average /PreserveEPSInfo false /ColorConversionStrategy /sRGB /GrayImageDownsampleType /Average /EmbedAllFonts true /CannotEmbedFontPolicy /Warning /PreserveOPIComments false /GrayImageResolution 72 /GrayACSImageDict << /ColorTransform 1 /QFactor 0.76 /Blend 1 /HSamples [2 1 1 2] /VSamples [2 1 1 2] >> /ColorImageResolution 72 /PreserveOverprintSettings false /CreateJobTicket false /AutoRotatePages /PageByPage /MonoImageDownsampleType /Average /NeverEmbed [/Courier /Courier-Bold /Courier-Oblique /Courier-BoldOblique /Helvetica /Helvetica-Bold /Helvetica-Oblique /Helvetica-BoldOblique /Times-Roman /Times-Bold /Times-Italic /Times-BoldItalic /Symbol /ZapfDingbats] /ColorACSImageDict << /ColorTransform 1 /QFactor 0.76 /Blend 1 /HSamples [2 1 1 2] /VSamples [2 1 1 2] >> /CompatibilityLevel 1.3 /UCRandBGInfo /Remove >>
 /printer << /DoThumbnails false /MonoImageResolution 1200 /ColorImageDownsampleType /Bicubic /PreserveEPSInfo true /ColorConversionStrategy /UseDeviceIndependentColor /GrayImageDownsampleType /Bicubic /EmbedAllFonts true /CannotEmbedFontPolicy /Warning /PreserveOPIComments true /GrayImageResolution 300 /GrayACSImageDict << /ColorTransform 1 /QFactor 0.4 /Blend 1 /HSamples [1 1 1 1] /VSamples [1 1 1 1] >> /ColorImageResolution 300 /PreserveOverprintSettings true /CreateJobTicket true /AutoRotatePages /None /MonoImageDownsampleType /Bicubic /NeverEmbed [] /ColorACSImageDict << /ColorTransform 1 /QFactor 0.4 /Blend 1 /HSamples [1 1 1 1] /VSamples [1 1 1 1] >> /CompatibilityLevel 1.4 /UCRandBGInfo /Preserve >>

还是不怎么好看。所以让我们试着让它变得更好。我们可以这样做的方法是修改我们的 PostScript 代码:我们现在告诉它访问.distillersettings字典并从中获取其中一个键的值(让我们使用/screen)。由于我们知道该值是另一个字典,因此我们知道我们将获得另一组 key:value 对,我们将能够以与之前相同的方式对其进行格式化:

gs \
 -q \
 -dNODISPLAY \
 -c ".distillersettings /screen get {exch ==only ( ) print ===} forall quit"

现在这看起来更好,不是吗?看看自己:

/DoThumbnails false
/MonoImageResolution 300
/ColorImageDownsampleType /Average
/PreserveEPSInfo false
/ColorConversionStrategy /sRGB
/GrayImageDownsampleType /Average
/EmbedAllFonts true
/CannotEmbedFontPolicy /Warning
/PreserveOPIComments false
/GrayImageResolution 72
/GrayACSImageDict -dict-
/ColorImageResolution 72
/PreserveOverprintSettings false
/CreateJobTicket false
/AutoRotatePages /PageByPage
/MonoImageDownsampleType /Average
/NeverEmbed [/Courier /Courier-Bold /Courier-Oblique /Courier-BoldOblique /Helvetica     /Helvetica-Bold /Helvetica-Oblique /Helvetica-BoldOblique /Times-Roman /Times-Bold /Times-Italic /Times-BoldItalic /Symbol /ZapfDingbats]
/ColorACSImageDict -dict-
/CompatibilityLevel 1.3
/UCRandBGInfo /Remove

正如您敏锐的眼光可能已经发现的那样:一些关键值又是字典。您可以再次使用上述命令,这次用 a===代替第二个==来解决/GrayACSImageDict -dict-诸如此类可能一直隐藏的谜团......

无论如何,现在您知道通过简单地使用-dPDFSETTINGS=/screen而不是枚举嵌入在此/screen字典中的所有单个参数来节省键入的内容...

如果您想要一般的“屏幕”质量输出, 您还知道需要覆盖的单个值,但不同之处在于所有字体都被嵌入:

gs \
 -o out.pdf \
 -sDEVICE=pdfwrite \
 -dPDFSETTINGS=/screen \
 -c "<</NeverEmbed [ ] /AlwaysEmbed [/Courier /Courier-Bold /Courier-Oblique /Courier-BoldOblique /Helvetica /Helvetica-Bold /Helvetica-Oblique /Helvetica-BoldOblique /Times-Roman /Times-Bold /Times-Italic /Times-BoldItalic /Symbol /ZapfDingbats]>> setdistillerparams" \
 -f input.pdf

只要您知道它使用的字典的名称,您就可以通过这种方式探索很多关于 Ghostscript 内部的有趣事物。:-)

于 2012-06-21T15:43:32.487 回答
6

已经有很多好的答案,但没有人提到这一点:

调用 ghostscript 时,-d-s选项在 systemdict 中创建初始定义。这允许您对postscript 程序进行参数化调用

用于-dname[=token]将值设置为 null 或数字(或任何其他单个 postscript 标记)。用于-sname=string设置字符串值(在大多数情况下,它与名称一样有效)。

您可以使用正确的运算符在某种程度上操纵所有堆栈。

  • token从字符串或文件推送到操作数堆栈(这是解释器循环用来消耗程序流的内容,因此无论是通过文件输入代码还是直接从键盘输入代码,这都是您使用的内容)
  • pop从操作数堆栈中丢弃
  • begin推送到字典堆栈
  • end从字典堆栈中弹出
  • run, exec,%procedure-invocation推送到执行堆栈
  • exit,stop弹出或清除执行堆栈
  • gsave在图形堆栈上推送 gstate
  • grestore弹出图形堆栈
  • save推送所有 VM 内容的副本(所有字典和数组,但不是字符串)
  • restore将内存倒回保存状态(将所有字典和数组恢复到以前的状态)

字典作为复合对象,继承了所有复合对象共有的许多运算符。

  • -typename-创建对象,例如dict
  • length报告对象大小
  • put插入一个元素
  • get检索一个元素
  • copy用另一个对象的内容填充一个对象
  • forall对每个元素做一些事情
  • *load备用检索元素(对于字典,使用然后load执行搜索;对于数组,将数组的全部内容溢出到操作数堆栈上)wheregetaload
  • *store备用插入元素(对于字典,如果找到,则store执行搜索,where然后执行搜索;对于数组,从堆栈上的对象填充数组)putdefastore

在这个套件中,字典添加

  • def放入当前字典(字典堆栈顶部)
  • known元素的查询字典
  • where在所有字典中查询元素
  • maxlengthPS Level 2 添加自动扩展字典和 gc 后不再有趣
  • dictstack将 dictstack 复制到一个数组中(也许你想自下而上搜索,你可以!)
  • 前面没有斜杠的名称/会自动load编辑,如果可执行,则执行
  • //whiletoken正在构造一个 postscript 对象,任何以双斜杠开头的名称都将被load编辑并替换到过程数组中。这非常强大,因为您可以模仿 Lisp 宏。

编辑:还有一件事。创建字典时,当您选择字典的大小时,需要权衡时间/空间。字典几乎肯定是作为哈希表实现的(除了最简单的解释器之外),大多数哈希函数可以在表大约半满时避免冲突(经验法则:使用双倍大小的字典来提高速度)。当然,由于 level-2,当您添加 size+1 个元素时,字典会自动增长,大概是通过分配一个新的 k*size 字典(其中 k 可能是 1.5 或 2);但是手动控制尺寸可以提高速度。在级别 1 中,如果您没有多次引用您的字典,您可以安装一个替换为dictfullinerrordict增长 dict 并重新执行 put (或 def 或其他)。由于 level-2 在内部执行此操作,因此它可以替换所有引用。

于 2012-07-06T00:07:16.323 回答
4

如果要获取包含在systemdictuserdict字典中的其他字典的列表,只需运行:

for _dict in userdict systemdict; \
   do \
   gs \
     -dNODISPLAY \
     -c "${_dict} {exch ==only ( ) print ==} forall quit"; \
done \
| awk '{print $1, $2}' \
| grep -- -dict- \
| sort

这将产生一个字典名称的排序列表,您可以调查这些字典名称以查找潜在的“有趣”名称。

你会发现这样的名字,如Fontmap, localdict, AdobeGlyphList, userparams, .eexec_param_dict, .substitutefamilies, EncodingDirectory, colorspacedict, .distillerparamkeys, devicedict, .symbol_list, ...

使用这些名称中的每一个,您都可以通过运行 fe 来查找有关 Ghostscript 内部的或多或少有趣的信息和花絮:

gs \
  -q \
  -dNODISPLAY \
  -c "Fontmap {exch ==only ( ) print ==} forall quit"

如您所见,甚至 Ghostscript 使用的Fontmap也存储在字典中。我在本地的结果摘录如下:

[....]
/Arial [/ArialMT]
/Arial,Bold [/Arial-BoldMT]
/AvantGarde-Book [/URWGothicL-Book]
/Bookman-Demi [/URWBookmanL-DemiBold]
/Calligraphic-Hiragana [(fhirw.gsf)]
/Calligraphic-Katakana [(fkarw.gsf)]
/Charter-Bold [/CharterBT-Bold]
/CharterBT-Bold [(bchb.pfa)]
/Courier [/NimbusMonL-Regu]
/Courier-Bold [/NimbusMonL-Bold]
/Courier-BoldOblique [/NimbusMonL-BoldObli]
/Courier-Oblique [/NimbusMonL-ReguObli]
/Helvetica [/NimbusSanL-Regu]
/Helvetica-Bold [/NimbusSanL-Bold]
/NewCenturySchlbk-Bold [/CenturySchL-Bold]
/Palatino-Roman [/URWPalladioL-Roma]
/Symbol [/StandardSymL]
/Times-Bold [/NimbusRomNo9L-Medi]
/TimesNewRoman,Bold [/TimesNewRomanPS-BoldMT]
/Utopia-Regular [(putr.pfa)]
/ZapfDingbats [/Dingbats]
[....]

注意事项:当您想要操作 Ghostscript 应该使用的 Fontmap文件(通常,或用于特定作业)时,上述文件格式实际上并不是您必须使用的文件格式。对于该格式,请阅读 Ghostscript 提供的示例 Fontmap 文件中的注释。上面的列表是 Ghostscript 存储在其内部字典中的字体图表示。

于 2012-06-21T18:21:06.233 回答
2

PostScript 中的字典是一个“容器”对象,它们本质上是一个对、一个键和一个值的列表。有关详细信息,请参阅 PostScript 语言参考手册,尤其是第三版中的第 3.3.9 节。

字典通常用于将一组参数传递给 PostScript 运算符或函数,例如图像运算符可以接受字典参数,但它们同样可以简单地存储。

字典可以具有访问权限,因此可以具有只读字典,其值可以检查但不能修改,并且字体字典可以是“无权访问”以防止在 PostScript 中提取轮廓数据。

字典中非只读或不可访问的条目可以随意修改。

于 2012-06-21T13:00:02.870 回答