什么是PostScript词典,以及如何访问它们(通过Ghostscript)?

时间:2012-06-21 12:03:36

标签: dictionary stack ghostscript postscript

我通常将ghostscript视为命令行工具;但是,我从不会对那里存在的大量设置和选项感到惊讶 - 这是因为ghostscript是一个完整的PostScript语言解释器(我经常忘记)。

例如,Querying Ghostscript for the default options/settings of an output device (such as 'pdfwrite' or 'tiffg4');一个人学习如何检索给定输出设备的默认选项。但是,我想知道的是 - 这些选项是否与所谓的PostScript词典相关?

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

5 个答案:

答案 0 :(得分:8)

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

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

  • <强> systemdict 这个包含预定义的PostScript操作符(以及使它们按照PostScript规范的要求执行的实现)。

  • <强> userdict 这个包含PostScript程序的变量和过程(将'过程'视为由语言定义的运算符和程序定义的值和参数组合构成的函数或子例程)。

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

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

  • 操作数堆栈 该堆栈保存每个操作数和中间操作的每个结果(将最后一个结果暂时转换为操作数堆栈的最顶层元素)。

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

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

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

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

对于每个堆栈,存在某些限制(关于可以存储在其上的元素的数量等)。 PostScript知道可以操作堆栈的操作符:在堆栈上放置一个新元素,删除最顶层的元素( pop ),复制最顶层的元素( {{1调整堆栈中元素的顺序( dup ),交换两个top-moste元素( roll ),以及更多(PostScript编程的一个很好的介绍是来自Adobe的'Bluebook')。

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

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

dict始终是最底层的一个;在此之上是systemdict。这两个不能从字典堆栈中删除,所有其他的都可以受任何堆栈操作操作符(例如 userdict )从堆栈中删除最顶层元素。

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

此外,一些词典可以用于PS程序“私人”(无法访问,如字体词典)或“只读”。


更新 - 更多答案:

答案 1 :(得分:5)

其他答案已经涵盖了“什么是字典?”部分问题。现在让我们转向“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'Distiller'相似的功能)输出时,您可以在Ghostscript命令行上使用所有这些来请求预定义的设置集。要请求这样的一组设置,只需将-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)。由于我们知道该值是另一个字典,因此我们知道我们将获得另一组键:值对,我们将能够以与之前相同的方式进行格式化:

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

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

在任何情况下,现在您只需使用-dPDFSETTINGS=/screen而不是枚举此/screen字典中嵌入的所有单个参数,就可以知道您在输入时节省了什么......

如果您想要一般'屏幕'质量输出,您还知道需要覆盖哪一个值,但区别在于所有字体嵌入:< / p>

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内部。 : - )

答案 2 :(得分:5)

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

调用ghostscript时,-d-s选项会在systemdict中创建初始定义。这样您就可以parameterized invocation of your postscript program

使用-dname[=token]将值设置为null或数字(或任何其他单个postscript标记)。使用-sname=string设置字符串值(在大多数情况下都可以使用,也可以使用名称)。

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

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

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

  • -typename-创建对象,例如dict
  • length举报对象大小
  • put插入元素
  • get检索元素
  • copy使用其他对象的内容填充对象
  • forall对每个元素执行某些操作
  • *load备用检索元素(对于词典,load使用where执行搜索,然后执行get;对于数组,aload会溢出整个内容操作数堆栈上的数组)
  • *store替代插入元素(对于字典,store使用where执行搜索,然后搜索put(如果找到),或def(如果不是);数组,astore从堆栈中的对象填充数组)

到这个套件,词典添加

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

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

答案 3 :(得分:4)

如果您想获取 systemdict userdict 词典中包含的其他词典列表,请运行:

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

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

您会找到FontmaplocaldictAdobeGlyphListuserparams.eexec_param_dict.substitutefamilies,{{1}等名称},EncodingDirectorycolorspacedict.distillerparamkeysdevicedict,...

使用这些名称中的每一个,您可以通过运行f.e。来查找或多或少有趣的信息和关于Ghostscript内部的信息:

.symbol_list

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

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

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

答案 4 :(得分:2)

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

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

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

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