PostScript

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 以及先進的錯誤處理。

在列印中的應用

2.1 PostScript 之前

在 PostScript 出現之前，印表機設計成將字元 —— 通常是 ASCII 字元 —— 打印出來。有許多技術用於這項工作，但是大多數都有一個共性也就是字元在物理上很難更改，就像在打字機鍵上的金屬或者光學平板那樣的條帶。

隨著點陣印表機的流行發生的一些變化，在這些系統上字元是用一系列的點 “畫” 出來的，這些點在印表機中定義為字體表。隨著他們越來越複雜，點陣印表機開始包含有幾種內建的字型，使用者可以選擇所用字型，有一些型號甚至允許使用者下載自己的字元圖形到印表機中。

點陣印表機也帶有列印光柵圖形的能力，圖形在計算機上進行解釋並且使用一系列的轉義序列將它們按照一系列的點發送到印表機。這種印表機控制語言隨著印表機的不同而不同，這就要求程式設計師建立許許多多的驅動程式。

真正的圖形列印是名為繪圖儀的特殊的裝置所完成的，繪圖儀的確是共用一種常見的語言 ——HPGL，但是除了列印圖形之外並沒有多大用途。另外，它們通常價格昂貴，速度較慢，所以使用很少。

2.2 PostScript 列印

PostScript 將印表機和繪圖儀的優點組合在一起從而打破了傳統。同繪圖儀一樣，PostScript 具有高質量的曲線處理能力並且控制語言簡單能夠用於不同品牌的印表機；同點陣印表機一樣，PostScript 提供了一個生成文字和光柵圖形的簡單方法。與它們二者不同的是，PostScript 能夠將所有這些不同的內容放在同一頁上，這樣就比以前的印表機或者繪圖儀提供了更具靈活性。

PostScript 已經超出了普通的印表機控制語言，併成為一個完善的程式語言。許多應用程式能夠將文件傳送到一個 PostScript 程式中，它的輸出結果就是原始文件。這個程式能夠傳送到印表機中的直譯器上得到列印文件，或者傳送到另外一個應用程式在螢幕上顯示文件。由於文件程式與目的地無關，所以就被稱為 “與裝置無關”。

PostScrip 也非常擅長於實現柵格化；所有的東西，甚至是文字都可以用直線和三階貝塞爾曲線表示，貝塞爾曲線以前只有在 CAD 應用中才能見到，它允許任意的縮放、旋轉或者其他變換。當解釋 PostScript 程式的時候，直譯器將這些指令轉換成所需的點形成輸出內容。

2.3 字型處理

同 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 字型中的外形不同而有所不同。

2.4 其他實現

在 1980 年代，Adobe 利潤的絕大部分都來自於用於印表機的 PostScript 實現（稱為光柵影像處理器或者 RIP）的高昂授權費用。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（DPS）和 NeWS，它們兩者戲劇性地在在哪裡應用顯示邏輯發生了分歧，在 DPS 中 view 系統留給了 OS 去處理，然而在 NeWS 上整個顯示系統是用用 PS 寫成的並且在一個單一的複雜直譯器中執行。

PostScript 語言

PostScript 是一種圖靈完全的程式語言，通常 PostScript 程式不是人為生成的，而是由其他程式生成的。然而，仍然可以使用手工編制的 PostScript 程式生成圖形或者進行計算。

PostScript 是一種基於堆疊的解釋語言，它類似於 Forth 語言但是使用從 Lisp 語言派生出的資料結構。這種語言的語法使用逆波蘭表示法，這就意味著不需要括號進行分割，但是因為需要記住堆疊結構，所以需要進行訓練才能閱讀這種程式。大部分運算子（其他程式中稱為函式）從堆疊中讀取變數，並且將運算結構放到堆疊中。如數字這樣的符號字面值具有將它們自身副本放到堆疊的效果。

4.1 演算法

例如：

3 4 add 5 1 sub mul

將執行 (3 + 4) × (5 - 1) 這樣的計算。

讓我們詳細地分析一下這是如何完成的：

3 和 4 都是符號，它們將自己放到堆疊中，在這兩個命令之後，堆疊將變成這樣：

4

3

add 是一個運算子，它將堆疊中最上面的兩個元素取出（在我們的例子中是 3 和 4）、將它們相加、然後將結果放到堆疊上：

7

下面又是兩個符號，它們將把堆疊變成這樣（需要注意的是操作僅僅侷限在堆疊頂部，下面的元素不受影響）：

1

5

7

另外一個運算子 sub，從堆疊頂取出兩個元素、第二個減去第一個、然後將結果放到堆疊：

4

7

很顯然 mul 同其他兩個運算子一樣，從堆疊取出兩個元素、將它們的乘積放到堆疊：

28

4.2 命名變數

上面的例子只是一個古老的逆波蘭表示法計算，當然 PostScript 也使用變數。詳細地說就是它有一個字典用來查詢所有不是符號的東西；如果查到的話，那個名字下儲存的值就會壓縮到棧中（或者更應該說是執行 —— 參見後面的內容）；找不到就返回錯誤。將一個變數放到字典中需要使用 def 運算子，它用一個名字和一個值作為引數，透過在前面使用斜線構建一個名字。因此

/x1 15 def

首先將名字 “x1” 放到堆疊上、然後是值 15、然後執行 def，它將從堆疊中取出 “x1” 和 15，並且將 15 寫到字典中 “x1” 的下面。後面出現的 “x1”（注意不要與 “／x1” 混淆）將會將 15 放到堆疊而變數並不改變。下面的程式碼會將 x1 的值增加 2：

/x1 x1 2 add def

4.3 堆疊運算子

PostScript 有幾個運算子用於重組或者控制堆疊：複製（dup）、丟棄（pop）和交換（exch）在堆疊頂部進行操作，然而 roll 旋轉堆疊中的某一部分，copy 複製某個特定的部分，index 允許象陣列那樣訪問堆疊。

4.4 處理過程定義

「{」和「}」提供了一些程式設計的工具。「{」將直譯器切換到延遲執行模式，所有的東西甚至是運算子和其他的可執行物件都放到堆疊中，其中一個例外就是「}」，它將堆疊中從「{」開始的所有內容，繫結成一個（匿名）處理過程，然後將它放到堆疊上。

這種結構有幾種不同的用途，如子程式定義（匿名程式賦給一個變數）、迴圈、條件等等：

x1 0 eq {0} {1 x1 div} ifelse

這段程式碼首先使用 eq 測試 x1 是否是 0；根據結果的不同將真或者假放到堆疊上。在此之後，將兩個過程放到堆疊上，然後執行 ifelse，它從堆疊中取出三個引數，如果第三個引數是真就執行第二個否則就執行第一個。總之，如果 x1 是 0 結果就是 0， 其他情況結果就是 1/x1。

4.5 圖形操作

在生成圖形的時候，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。