PostScript(PS)是主要用于电子产业和桌面出版领域的一种页面描述语言和编程语言。
PostScript语言的思想起源于John Warnock1976年在著名的计算机图形公司Evans and Sutherland时的想法。当时John Gaffney正在开发一个解释纽约港大型三维图形数据库的解释器。Gaffney设计了非常类似于Forth编程语言的Design System语言来处理图形。
1978年Evans and Sutherland要求Warnock离开旧金山湾到犹他州总部去,但是他并不想搬家到那里去。于是他后来加入了Xerox PARC与Martin Newell一起工作。他们重写了Design System开发出了用于VLSI设计和字体与图形打印研究的JaM(John and Martin)系统。这项工作后来发展成为一个名为InterPress的扩展系统。
在1982年12月Warnock和Chuck Geschke一起离开创建了Adobe Systems公司。他们开发了一种类似于InterPress名为PostScript的更简单的语言,这种产品在1984年推向市场。大概在这个时候,Steve Jobs参观了他们的工作,他敦促他们改进PostScript作为驱动激光打印机的语言,它添加到Canon打印机诞生了LaserWriter。
1985年3月,Apple LaserWriter是第一款带有PostScript的打印机,这也带来了1980年代中期的桌面印刷革命。它的技术优点和广泛应用使得PostScript成为打印应用领域影像输出的一个选择。直到1990年代,PostScript语言解释器,有时称作Raster image processor,曾经一度成为激光打印机的一个普通组成部分。
随着使用电子方式发布文档最终版本成为事实上的标准,PostScript就在这个领域不断地被它的后续版本Portable Document Format也就是PDF所超越,到了2001年更少有打印机支持PostScript,这主要是由于来自于非PostScript的廉价喷墨打印机的不断加剧的竞争(PostScript解释器将大幅度地增加打印机成本),以及在计算机上使用软件渲染PostScript图像的新方法可以用于任何的打印机,PDF就是这种方法之一。然而使用PostScript的激光打印机仍然可以大幅度地减少计算机在打印、从计算机到打印机传输渲染出的PostScript图像方面的工作量。
PostScript经历了两次主要的更新。第一版称为PostScript Level 1在1984年发布。PostScript Level 2在1991年发布,它有几项增强的特性:提升了速度和可靠性;支持RIP内的分割;支持解压缩,这就意味着如JPEG这样的图像能够直接在PostScript程序中进行处理;支持复合字体以及缓存重用内容的Form机制。PostScript Level 3在1997年年底出现,许多旧版操作符变成了基于字典的新版本,它提供了更好的颜色处理以及新的允许在程序内进行压缩和解压的过滤器、程序chunking以及先进的错误处理。
在PostScript出现之前,打印机设计成将字符——通常是ASCII字符——打印出来。有许多技术用于这项工作,但是大多数都有一个共性也就是字符在物理上很难更改,就像在打字机键上的金属或者光学平板那样的条带。
随着点阵打印机的流行发生的一些变化,在这些系统上字符是用一系列的点“画”出来的,这些点在打印机中定义为字体表。随着他们越来越复杂,点阵打印机开始包含有几种内置的字体,用户可以选择所用字体,有一些型号甚至允许用户下载自己的字符图形到打印机中。
点阵打印机也带有打印光栅图形的能力,图形在计算机上进行解释并且使用一系列的转义序列将它们按照一系列的点发送到打印机。这种打印机控制语言随着打印机的不同而不同,这就要求程序员创建许许多多的驱动程序。
真正的图形打印是名为绘图仪的特殊的设备所完成的,绘图仪的确是共享一种常见的语言——HPGL,但是除了打印图形之外并没有多大用途。另外,它们通常价格昂贵,速度较慢,所以使用很少。
PostScript将打印机和绘图仪的优点组合在一起从而打破了传统。同绘图仪一样,PostScript具有高质量的曲线处理能力并且控制语言简单能够用于不同品牌的打印机;同点阵打印机一样,PostScript提供了一个生成文本和光栅图形的简单方法。与它们二者不同的是,PostScript能够将所有这些不同的内容放在同一页上,这样就比以前的打印机或者绘图仪提供了更具灵活性。
PostScript已经超出了普通的打印机控制语言,并成为一个完善的编程语言。许多应用程序能够将文档传送到一个PostScript程序中,它的输出结果就是原始文档。这个程序能够发送到打印机中的解释器上得到打印文档,或者发送到另外一个应用程序在屏幕上显示文档。由于文档程序与目的地无关,所以就被称为“与设备无关”。
PostScrip也非常擅长于实现栅格化;所有的东西,甚至是文本都可以用直线和三阶贝塞尔曲线表示,贝塞尔曲线以前只有在CAD应用中才能见到,它允许任意的缩放、旋转或者其他变换。当解释PostScript程序的时候,解释器将这些指令转换成所需的点形成输出内容。
同PostScript一样复杂的是它的字体处理。丰富的字体系统使用PS基本图形将字符画成艺术线条,艺术线条能够在任意的分辨率生成。尽管这听起来是很直观的概念,但是需要考虑许许多多的拓扑图形问题。
其中一个问题是字体在小尺寸的时候实际上并不是进行线性缩放,如果那样的话字体的某些部分就会不成比例地过大或者过小从而字体看起来不太正确。PostScript使用与字形曲线保存在一起的(Hints)避免了这个问题的发生,它们基本上是水平或者竖直方向条带上一些附加信息,用以标识光栅图像生成器需要维护的字体中的重要特征。甚至在很低的分辨率的时候字体也是非常好看;通称为Adobe的Type 1 Font。Type 1是一个高效的仅仅用来保存字形信息的简化PS系统,而不是一个完善的语言,PDF也是一种类似的情况。Adobe向那些打算在自己的字体中添加隐含信息的厂商征收高额的Type 1技术授权使用费用。那些不愿意使用隐含信息或者不愿支付费用的用户只能使用Type 3 Font。Type 3字体允许使用除了标准的隐含信息之外的PostScript语言的所有复杂特性,后来又添加了一些其他的不同特点。
许多人认为授权的费用过于高昂,并且Adobe也不愿采用更具吸引力的费率,这样就导致了Apple在1991年左右开发了他们自己的系统TrueType。紧随着TrueType的发布,Adobe就公开了Type 1字体的规范。如Altsys Fontographer(1995年1月被Macromedia收购,自从2005年5月归FontLab所有)这样的零售系统加入了创建Type 1字体的能力。从那时开始,就出现了许多免费Type 1字体,例如TeX排版系统中所用字体就是这种格式。
在1990年代早期还有其他几种基于字形的字体系统,如Bitstream和METAFONT开发的系统,但是它们都不包括通用的打印解决方案,所以并没有得到广泛应用。
在1990年代,Adobe和微软公司一同开发OpenType,它基本上是Type 1和TrueType格式功能的超集。当打印到PostScript输出设备的时候,OpenType字体中不需要的部分就会被丢弃,驱动程序送到设备的内容与传送TrueType或者Type 1字体完全一样,根据OpenType字体中的外形不同而有所不同。
在1980年代,Adobe利润的绝大部分都来自于用于打印机的PostScript实现(称为光栅图像处理器或者)的高昂授权费用。RIP相当昂贵,并且通常只在少数一些特定的硬件上运行。1980年代中期随着许多基于RISC的新平台出现,Adobe经常是在支持新机器方面落后一步。
因此第三方的PostScript实现变得很普遍,尤其是在授权费用是关键症结的低端打印机或者新硬件激发更快速度要求的高端排版设备领域更加常用。一方面,微软公司和苹果公司联合起来努力将Adobe从独霸打印机的位置拉下马,微软公司将它购买的TrueImage PostScript解释器授权给苹果公司,苹果公司将它的新字体格式TrueType授权给微软公司。(苹果公司终止了与Adobe保持一致以及它的打印机使用Adobe公司真正的PostScript的策略,但是TrueType在微软视窗和Macintosh上都成为了标准的outline font。)一些第三方的PostScript的克隆产品仍在广泛使用,尤其是在作为惠普黑白激光打印机标准Phoenix Page的中仍在广泛使用。
许多基本的廉价激光打印机不支持PostScript,它们的驱动程序根本不使用PostScript。当需要在这样的打印机上使用PostScript时可以使用名为Ghostscript的PostScript解释器,这是一个自由软件。Ghostscript使用主计算机的CPU进行光栅化处理、将结果作为一个大幅的位图发送到计算机这样一种方式在非PostScript打印机上打印PostScript文档。Ghostscript也可以在计算机显示器上预览PostScript文档以及将PostScript转换成如TIFF和PNG这样的光栅图形或者如PDF这样的矢量格式。
分辨率非常高的设备,如imagesetter或者CTP platesetter超过2500dpi的分辨率也很常见,仍然需要带有大量内存和磁盘空间的外部光栅图像处理器。许多称为数字印刷的高端激光打印机系统也使用外部光栅图像处理器将容易升级的计算机系统与特定的打印硬件分开。如EFI 页面存档备份,存于互联网档案馆和Xitron 页面存档备份,存于互联网档案馆这样的公司专业从事这样的光栅图像处理器软件开发。
随着PostScript成为打印输出的事实标准,很自然人们也希望将它用来描述屏幕输出。1980年代后期CPU性能的快速提升以及人们对于视窗系统兴趣的逐渐增加,促使人们多次试图开发使用PostScript作为主要的显示技术的显示系统。
使用PS作为显示系统有许多优点,其中之一就是在其他系统上用户不仅仅要为屏幕显示保留位图,而且要为打印机保留Type 1字体,在显示器上使用PS只需要保留一套从而可以弥补这个缺点。另外一个优点是就是允许“dumbling down”打印机。当LaserWriter发布的时候它是苹果公司产品线中功能最为强大也是最为昂贵的机器,这样它就需要相当大的处理能力和内存以在合理的时间内生成高达300dpi分辨率的页面。与之形成对比的是,使用NeXT平台的400dpi打印机根本都没有CPU,相反它是使用计算机的CPU进行页面生成,然后将生成的页面位图传送到打印机。
但是使用PostScript作为视窗系统的一个更为主要的优点是他让用户使用一组图形处理子程序就可以开发桌面印刷和其他大量使用图形的应用程序,在视窗上进行描画的程序同样也可以不经任何转换直接在打印机上描画。传统系统上的桌面印刷应用程序要求程序员在各个平台的图形系统上构建图形用户界面(如Macintosh上的QuickDraw和微软视窗上的图形设备接口(GDI))编辑器,然后编写另外的程序将图形转换成正确的PostScript语言用于打印。这样的工作通常就会消耗项目的大部分编程工作,并且是程序错误的主要来源。
使用PostScript作为显示技术的两个主要的例子是Display PostScript()和NeWS,它们两者戏剧性地在在哪里应用显示逻辑发生了分歧,在DPS中view系统留给了OS去处理,然而在NeWS上整个显示系统是用用PS写成的并且在一个单一的复杂解释器中运行。
PostScript是一种图灵完全的编程语言,通常PostScript程序不是人为生成的,而是由其他程序生成的。然而,仍然可以使用手工编制的PostScript程序生成图形或者进行计算。
PostScript是一种基于堆栈的解释语言,它类似于Forth语言但是使用从Lisp语言派生出的数据结构。这种语言的语法使用逆波兰表示法,这就意味着不需要括号进行分割,但是因为需要记住堆栈结构,所以需要进行训练才能阅读这种程序。大部分(其他程序中称为)从堆栈中读取变量,并且将运算结构放到堆栈中。如数字这样的具有将它们自身副本放到堆栈的效果。
例如:
3 4 add 5 1 sub mul
将执行 (3 + 4) × (5 - 1)这样的计算。
让我们详细地分析一下这是如何完成的:
3和4都是符号,它们将自己放到堆栈中,在这两个命令之后,堆栈将变成这样:
43
add是一个运算符,它将堆栈中最上面的两个元素取出(在我们的例子中是3和4)、将它们相加、然后将结果放到堆栈上:
7
下面又是两个符号,它们将把堆栈变成这样(需要注意的是操作仅仅局限在堆栈顶部,下面的元素不受影响):
157
另外一个运算符sub,从堆栈顶取出两个元素、第二个减去第一个、然后将结果放到堆栈:
47
很显然mul同其他两个运算符一样,从堆栈取出两个元素、将它们的乘积放到堆栈:
28
Named variables
上面的例子只是一个古老的逆波兰表示法计算,当然PostScript也使用变量。详细地说就是它有一个用来查找所有不是符号的东西;如果查到的话,那个名字下保存的值就会压缩到栈中(或者更应该说是——参见后面的内容);找不到就返回错误。将一个变量放到字典中需要使用运算符,它用一个名字和一个值作为参数,通过在前面使用斜线构建一个名字。因此
/x1 15 def
首先将名字“x1”放到堆栈上、然后是值15、然后执行def,它将从堆栈中取出“x1”和15,并且将15写到字典中“x1”的下面。后面出现的“x1”(注意不要与“/x1”混淆)将会将15放到堆栈而变量并不改变。下面的代码会将x1的值增加2:
/x1 x1 2 add def
堆栈运算符
PostScript有几个操作符用于重组或者控制堆栈:复制(dup)、丢弃(pop)和交换(exch)在堆栈顶部进行操作,然而roll旋转堆栈中的某一部分,copy复制某个特定的部分,index允许象数组那样访问堆栈。
“{”和“}”提供了一些编程的工具。“{”将解释器切换到模式,所有的东西甚至是运算符和其他的可执行对象都放到堆栈中,其中一个例外就是“}”,它将堆栈中从“{”开始的所有内容,绑定成一个(匿名)处理过程,然后将它放到堆栈上。
这种结构有几种不同的用途,如子程序定义(匿名程序赋给一个变量)、循环、条件等等:
x1 0 eq { 0 } { 1 x1 div } ifelse
这段代码首先使用eq测试x1是否是0;根据结果的不同将或者放到堆栈上。在此之后,将两个过程放到堆栈上,然后执行ifelse,它从堆栈中取出三个参数,如果第三个参数是就执行第二个否则就执行第一个。总之,如果x1是0结果就是0, 其他情况结果就是1/x1。
在生成图形的时候,PostScript使用普通的笛卡尔坐标系。
100 200 moveto 300 400 lineto stroke
将“光标”移到坐标点(100, 200)然后画线到(300, 400)。
50 70 moveto 100 200 50 80 100 100 curveto stroke
生成一个从(50, 70)到(100, 100)的立方贝塞尔曲线,控制点是(100, 200)和(50, 80)。
250 250 moveto (Wikipedia) show
在位置(250, 250)使用预先选择的字体画出文本“Wikipedia”,字体选择可以使用例如/Courier findfont 12 scalefont setfont这样的命令串。
图形最初在“用户坐标系”中创建,在复制到确定最后输出的“设备坐标系”之前它们可以进行旋转、缩放或者扭曲等变换。
200 300 translate 45 rotate
将用户坐标系中的内容上移200点、右移300点并且复制到设备坐标系时旋转45度。
字符“%”用来在PostScript程序中表示注释。作为一个通用的约定,每个PostScript都以字符“%!”开始这样所有的设备都会将它解释为PostScript。
本条目部分或全部内容出自以GFDL授权发布的《自由在线电脑词典》(FOLDOC)。