PostScript 常見問題解答/PostScript 程式設計
很少有人想編輯 HPGL 或 PCL。PostScript 是一種由某些雷射印表機使用的另一種控制語言。在大多數情況下,PostScript 檔案是根據某種人類可讀文件以演算法方式生成的。如果可能,獲取原始文件。
視覺化編輯需要解釋 PS 檔案、編輯物件以及生成新的 PostScript 檔案。很少有應用程式支援 PostScript 圖形模型的所有功能。不支援的功能將丟失或被近似。作為一種程式語言,PostScript 可以根據執行環境採取不同的分支。未採取的分支將被直譯器丟棄,在編輯器中不留任何痕跡。當印表機驅動程式生成 PS 檔案時,它不關心保留高階結構。除了修復拼寫錯誤或更改頁碼之外,要進行其他操作可能非常困難。
許多主流圖形編輯器可以匯入 PS 檔案。內建直譯器的質量各不相同,通常限於 1 級。PDF 匯入過濾器往往效果更好;先嚐試將 PS 檔案轉換為 PDF。
如果 PS 檔案包含太多視覺化編輯器不支援的原語,則可以使用 Ghostscript 中的 pstoedit 實用程式將 PostScript 檔案簡化為一系列路徑操作。
EnFocus Software 的 Tailor 似乎是唯一可用的專有 PostScript 編輯器。(它很久以前就停止了)。CGS 還有一款名為 PDF Tuner 的軟體,可以編輯 PostScript 和 PDF 檔案。這款軟體一直在不斷開發中。
手動編輯需要對 PostScript 語言有很好的瞭解,以及一個強大的文字編輯器。有時使用者會建立超過 100M 的 PS 檔案。這些檔案通常包含二進位制資料;有時它們取決於資料的確切大小。文字編輯器不應該擴充套件製表符或標準化行尾。檔案的十六進位制檢視可能很方便。
重新定義運算子和過程是一種強大的技術,可以改變 PS 檔案的行為。新的程式碼可以包含在 RIP 啟動指令碼中,由驅動程式從 PPD 複製,或者由輸入過濾器直接新增到檔案中。token 運算子有助於在運算子重新定義不起作用時,將控制權從 PostScript 直譯器中奪走。
習語識別是一種自動化技術,可以在繫結 PS 過程時修補它。儘管它最初是為了在遺留 PostScript 程式中新增平滑陰影而設計的,但它也可以用於修復錯誤。
固定格式表格可以在任何圖形編輯器中建立,幷包含任何演示圖形。可以使用佔位符 EPS 檔案預留可變內容欄位。
可以使用標準的 Unix 文字工具將佔位符 EPS 檔案替換為可變內容。多年來,類似的技術一直用於 OPI 工作流程。
或者,佔位符 EPS 檔案可以變得智慧並自我列印。可變內容可以從 PostScript VM 或外部檔案檢索。
可變格式文件需要文字重新排版和重新分頁。您可以選擇使用可用的資源進行 直接 PostScript 文字格式化,或者在更高層次的頁面佈局語言(TeX、groff)中建立報告,然後將其轉換為 PostScript 或 PDF。
在大多數情況下,不可能替換從標準 PostScript 驅動程式中收集的 PostScript 文件中的單詞。驅動程式可能會為了字距調整而將單詞分解,而不會使用 xshow,使用十六進位制字串,或者將文字行轉換為取樣影像。後者是將亞洲字型列印在羅馬印表機上的常用方法。
與普遍看法相反,PostScript 檔案不能連線以獲得組合的結果。
# won't work cat page1.ps page2.ps page3.ps > threepages.ps
將檔案作為單獨的 Ghostscript 引數也不會有幫助。
# won't work gs -sDEVICE=pswrite -sOutputFile=threepages.ps page1.ps page2.ps page3.ps
PostScript 程式會更改 PostScript 直譯器狀態,並且必須在執行下一個程式之前撤消這些更改。首先,編寫以下標題。
%!
/begin_file
{ /save_state save def % save state of PS interpreter
currentfile
0 (% $$$ EOF Mark $$$) /SubFileDecode filter cvx exec % safequard against flushfile, etc.
} bind def
/end_file
{ clear cleardictstack % clear after the file
save_state restore % restore the state
} bind def
將每個 PostScript 檔案包含在以下包裝器中,並將它們追加到標題。
begin_file % Include your file here. % $$$ EOF Mark $$$ % don't delete this line end_file
即使原始檔案符合 DSC 標準,結果也不會符合 DSC 標準。
EPS 檔案的合成是透過將這些檔案 放置到一個容器 EPS 檔案中來完成的。
在 作業伺服器 模式下執行的 PostScript 直譯器(大多數印表機,Ghostscript 8.50 或更高版本,使用 -dJOBSERVER)將以 ^D 字元分隔的多個作業視為獨立作業,並將其透過管道傳遞到輸入流中。
一般來說,不可能連線多個 PS 程式以獲得組合的結果。以下程式將阻止所有嘗試向其追加內容的操作。這種技術最常在 OCF 字型安裝程式中找到。
systemdict begin (%stdin) (r) file flushfile
單位元組 PS 字型可以包含許多字形,但一次只能訪問其中的 256 個。將字元程式碼對映到字形名稱的 256 個元素陣列稱為編碼向量。PostScript 語言有幾個內建的編碼向量。您可以(並且應該始終)重新編碼您的字型。ISOLatin1Encoding 可能是一個不錯的起點。要重新編碼字型,您需要執行以下操作
/Courier findfont % load the font, for instance, Courier 0 dict copy begin % copy it to a new dictionary /Encoding ISOLatin1Encoding def % replace encoding vector /MyCourier /FontName def % replace font name currentdict end dup /FID undef % remove internal data /MyCourier exch definefont pop % define the new font
重新編碼的字型可以像任何其他字型一樣使用。
有幾種方法可以一次列印超過 256 個字形。
- 建立幾個重新編碼的字型,並在需要時選擇它們。
- 對稀有字元使用 glyphshow
- 從幾個重新編碼的字型建立 OCF 字型。OCF 支援所有可以想象的編碼方案。
- 從 CMap 和 Font 或 CIDFont 資源建立複合字體。
常用方法是在應用程式中進行文字格式化。應用程式會發出反映最終格式的 PostScript 程式碼 - 現在只需將內容轉儲到 x、y 座標即可。如果應用程式覆蓋了預設的字間距/字內距(例如,用於對齊或字距調整),它應該使用 PostScript 的 ashow、widthshow、awidthshow、kshow、xshow、yshow 或 xyshow 運算子,這些運算子接受一個完整的文字字串,以及一個單獨的規範來定位元素。不規範的替代方案,只是對單個字母和使用 moveto 分隔的小單詞片段使用 show,會阻礙文字提取程式和精餾器。
要在 PostScript 中執行文字格式化器的常用功能,例如連字元化、多欄文字、腳註、參考文獻、詞彙表等,需要在 PostScript 中實現合適的演算法,並將它們與要渲染的檔案一起提供,或者包含在檔案中,或者預先下載。現有的實現包括 David Byram-Wigfield 的 TinyDict、Graham Freeman 的 Quikscript 和 Don Lancaster 的 Gonzo Utilities。這三者都功能齊全,具有對齊、分欄、分頁和許多其他功能。更簡單的構建塊包括 Chapman Flack 的 Markup,它可以用作這些工具的前端,或者僅用於執行簡單的左/中/右未填充/未對齊文字設定,以及 Hyphenate,這是對 TeX 連字元化演算法的實現,許多特定於語言的模式已為此而編譯。總的來說,這些在 PostScript 本身中執行大部分計算的方法可以被稱為(Byram-Wigfield 的術語)直接 PostScript,並且 Anastigmatix 直接 PostScript 頁面 進一步描述並比較了它們。
自動 字距調整 需要在大多數字體附帶的 Adobe 字型度量 (AFM) 檔案中找到的資訊,因此要在 PostScript 中執行此操作需要下載相應的 AFM 檔案以及一些用於解析它們的 PostScript 程式碼(語法很簡單)。目前似乎還沒有提供執行此操作的直接 PostScript 資源。所有現有的系統都允許手動字距調整,這通常足夠了,因為字距調整對於大型顯示字型最為重要,而大型顯示字型只佔典型文件的一小部分。
設計並不侷限於兩種方法,即應用程式僅發出純 PostScript 或完整的直接 PostScript。第一種方法往往可以節省印表機上的計算時間,但會以發出大型、不可編輯的 PostScript 檔案以及更長的傳輸時間到印表機為代價,而直接方法可以具有緊湊、可編輯的檔案(具有固定的實現程式碼前導,這些程式碼可以預先下載一次)並在印表機上執行更多計算。大多數應用程式都會選擇折衷方案,在應用程式中執行部分工作並在發出的 PostScript 中包含前導,這些前導提供用於在印表機本身完成工作的過程。甚至可以設計一個應用程式,使用現有的直接 PostScript 資源之一作為其前導,並以這種形式發出文件。
如何放置多張圖片的副本?
[edit | edit source]圖片可以是取樣影像或 EPS 檔案。
PostScript 總是向前讀取標準輸入流。無法重新定位檔案或將字元推回。下一張圖片需要一份新的資料副本。為了重複使用圖片,我們需要將資料從輸入流複製到可重複使用的物件中。
少量資料可以儲存在 PostScript 字串中,但字串長度限制為 64K-1。更多資料可以儲存為字串陣列。陣列的長度也限制為 64K-1,但這足以耗盡大多數印表機的記憶體。實際上,低端印表機可能只有 256K 的可用記憶體。
編碼過濾器可用於壓縮圖片資料。在 3 級 PostScript 中,大多數編碼過濾器是可選的。
PostScript 3 級引入了可重複使用的流。它們快取輸入資料,並在讀取到檔案末尾後可以重新定位。在無磁碟印表機上,可重複使用的流在記憶體檔案系統中實現。
一些印表機和大多數基於主機的 RIP 具有可寫檔案系統。
為了避免多次渲染,PostScript 2 級引入了表單。它是圍繞一個過程的包裝器,該過程提示 PostScript 直譯器如何快取渲染結果。表單過程可以執行多次,並且需要可重複使用的資料來源。表單很少使用,許多 Adobe OEM 為表單快取選擇非常小的預設大小。
如何重新定義運算子?
[edit | edit source]最簡單的方法是使用 bind 運算子。
/foo { bar } bind def
不建議在生產環境中使用這種方法,因為 foo 可能已被重新定義為過程。以下方法在所有情況下都有效。
/baz /foo load def
/foo { baz bar } bind def
Ghostscript 還提供了特定於實現的運算子重新定義方式。請參閱 Ghostscript 原始碼中對 odef 運算子的註釋。
良好的重新定義應儘可能保留原始運算子的許多特性。以下對半色調運算子的簡單重新定義可能會導致一些意想不到的問題。
/sethalftone { pop } bind def
/setscreen { pop pop pop } bind def
/setcolorscreen { 12 { pop } repeat } bind def
首先,半色調可以從當前檔案讀取資料。其次,錯誤處理方面的差異可能很大。早期版本的 Mac OS X 的庫存安裝生成了以下程式碼
featurebegin { 30 60 setscreen % no function!
} featurecleanup
無論 featurecleanup 如何,上面的重新定義都會破壞堆疊並導致 PostScript 錯誤。以下是一些更好的重新定義
/sethalftone_orig /sethalftone load def
/setscreen_orig /setscreen load def
/setcolorscreen_orig /setcolorscreen load def
/sethalftone { gsave sethalftone_orig grestore } bind def
/setscreen { gsave setscreen_orig grestore } bind def
/setcolorscreen { gsave setcolorscreen_orig grestore } bind def
如何連線字串?
[edit | edit source]PostScript 沒有內建的字串連線運算子。以下過程(從 GNU Ghostscript 複製)似乎是最短的。
/concatstrings % (a) (b) -> (ab)
{ exch dup length
2 index length add string
dup dup 4 2 roll copy length
4 -1 roll putinterval
} bind def
多個字串的連線可以比反覆呼叫 concatstrings 更有效地完成。為方便迭代,字串儲存在陣列中。
/concatstringarray % [(a) (b) ... (z)] --> (ab...z)
{ 0 1 index { length add } forall string
0 3 2 roll
{ 3 copy putinterval
length add
}
forall pop
} bind def
最小值和最大值函式在哪裡?
[edit | edit source]PostScript 沒有內建的 min 和 max 運算子,但它們可以輕鬆地用過程編碼。
/min { 2 copy gt { exch } if pop } bind def
/max { 2 copy lt { exch } if pop } bind def
Ghostscript 在 systemdict 中具有 .min 和 .max 運算子。為了向後相容,Ghostscript 還提供了定義為以下內容的 min 和 max 過程
/max { .max } bind def
/min { .min } bind def
如何對陣列進行排序?
[edit | edit source]Ghostscript 在 gs_init.ps 中有一個 氣泡排序 過程。
% <array> <lt-proc> .sort <array>
/.sort
{ 1 index length 1 sub -1 1
{ 2 index exch 2 copy get 3 copy % arr proc arr i arr[i] arr i arr[i]
0 1 3 index 1 sub
{ 3 index 1 index get % arr proc arr i arr[i] arr imax amax j arr[j]
2 index 1 index 10 index exec
{ % ... amax < arr[j]
4 2 roll
}
if pop pop
}
for % arr proc arr i arr[i] arr imax amax
4 -1 roll exch 4 1 roll put put
}
for
pop
} bind def
net.anastigmatix.Order 提供插入排序、快速排序、堆排序、陣列最小值、最大值以及同時最小值和最大值,以及任意順序統計資訊
/net.anastigmatix.Order /ProcSet findresource begin [7 49 73 58 30 72 44 78 23 9 40 65 92 42 87] //PolyCmp QuickSort
這個 希爾排序 過程對任何其元素可以透過過程比較和交換的元素進行排序。
%! % Shell sort in PostScript % Copyright (c) 2002 by Alex Cherepanov. All rights reserved. % Distributed under GPL, http://www.gnu.org/licenses/gpl.txt % % Shell sort procedure based on compare and exchange operation % < i > < j > exch_less <bool> compares keys at positions i and j % exchange if not in order, retutn *i<*j % <len> is the number of elements % /shellsort % {} len -> - { dup dup 2 idiv % {} len m p { dup 0 eq { exit } if exch % {} len p m 15 le { dup 2 idiv } { dup } ifelse 16#fffffffe and 1 add % {} len p m' 1 1 4 index 3 index sub % {} len p m' 1 1 len-_m { 1 index neg 1 % {} len p m' is -m 1 { 1 sub % {} len p m' ii-1 2 copy add % {} len p m' ii-1 m+ii-1 5 index exec { exit } if } for } for exch 2 idiv % {} len m' p' } loop pop pop pop pop % - } bind def % % Sample unsorted array % /sample_array [ 1 8 76 3 7 0 7 8 55 86 5 58 57 55 3 6 9 6 66 4 3 4 8 65 8 8 55 4 5 88 55 3 6 7 44 5 7 4 7 43 3 ] def
%
% Sample array compare and exchange
% The elements at positions i and j are compared and exchanged
%
% if (*i<*j)
% return true
% (*i,*j) = (*j,*i)
% return false
%
/array_exch_less % i j -> bool
{ 6 index 3 1 roll % [] i j % get the element just below {exch}
2 index exch % [] i [] j
4 copy % [] i [] j [] i [] j
get % [] i [] j [] i *j
3 1 roll get % [] i [] j *j *i
2 copy ge % [] i [] j *j *i *i<*j
{ pop pop pop pop pop pop //true
}
{ exch % [] i [] j *i *j
4 1 roll % [] i *j [] j *i
put put //false
}
ifelse
} bind def
%
% Sort the array
%
/array_sort % [unsorted] -> [sorted]
{ //array_exch_less 1 index length shellsort
} bind def
%
% Print the sorted array
%
sample_array array_sort ==
如何顯示版權和其他符號?
[edit | edit source]從 2 級開始,glyphshow 運算子允許顯示一個命名的字形
% display a "registered trademark" symbol /registered glyphshow
在哪裡可以獲取更多 PostScript 程式碼示例?
[edit | edit source]關於 PostScript 的書籍包含許多簡單的 PS 程式。
Ghostscript 發行版在示例目錄中包含一些示例 PostScript 檔案。Ghostscript 的很大一部分是用 PostScript 語言實現的,包括 PDF 1.4 直譯器。
Adobe 釋出了一些 3 級功能的示例程式。
免費示例庫包含許多優秀的(和糟糕的)PostScript 檔案。該庫收集了有趣的手動編碼或從應用程式中收集的 PostScript、PDF、PCL 和 TIFF 檔案示例。
要了解排版過程,請參閱“實用 PostScript”數字排版的初學者指南,90 頁(電子書 416k PDF)。[[1]]
如何除錯 PostScript 程式?
[edit | edit source]你應該儘快學習的第一項技能是如何解釋 PostScript 錯誤訊息。它們並不總是容易理解。錯誤報告因產品而異。一些產品不會提供 PostScript 錯誤詳細資訊(例如 EPS 匯入到 Photoshop),最好避免將它們用於任何學習目的。
標準 PostScript 錯誤格式類似於:
PS>0 1 2 3 4 5 put %%[ Error: typecheck; OffendingCommand: put ]%% PS><< >> image %%[ Error: undefined; OffendingCommand: image ]%%
你會看到這包括錯誤名稱和導致錯誤的命令。請不要將此描述為“錯誤命令”錯誤,因為所有訊息都這麼說,並記住錯誤名稱和錯誤命令都很重要。後面的訊息意味著在影像字典中找不到必需的鍵。
如果你碰巧使用的是 Ghostscript,你可能會得到更多細節。請注意,錯誤訊息包括堆疊和運算子名稱。
GS>0 1 2 3 4 5 put Error: /typecheck in --put-- Operand stack: 0 1 2 3 4 5 Execution stack: %interp_exit .runexec2 --nostringval-- --nostringval-- --nostringval-- 2 %stopped_push --nostringval-- --nostringval-- %loop_continue 2 3 %oparray_pop --nostringval-- --nostringval-- false 1 %stopped_push .runexec2 --nostringval-- --nostringval-- --nostringval-- 2 %stopped_push --nostringval-- --nostringval-- --nostringval-- Dictionary stack: --dict:1044/1123(ro)(G)-- --dict:0/20(G)-- --dict:69/200(L)-- Current allocation mode is local Current file position is 16
你可以檢視運算子的描述以及堆疊以檢視你的運算元,並且通常可以看出它為什麼在抱怨。然後你就可以(有時)找出原始程式碼中問題的所在。請記住,失敗的 PostScript 運算子不會改變運算元堆疊。
Ghostscript 在命令列引數傳遞的檔案中發生錯誤時退出。使用運算子 run 來保持會話並互動式地檢查運算元堆疊。
$ gs GS> (foo.ps) run
使用 = 和 == 命令來列印有關運算元堆疊上物件的資訊。要檢視字典的內容,將字典推送到堆疊上,然後使用 {== ==} forall。例如,要檢視使用者字典的內容,使用 userdict {== ==} forall。
嘗試在不同的直譯器上執行程式。不同的錯誤訊息可能會揭示更多關於問題的資訊。 Ghostscript 在使用 -dOSTACKPRINT 和 -dESTACKPRINT 選項執行時,可以分別列印運算元和執行堆疊的詳細轉儲。堆疊的頂部元素最後列印。
錯誤處理程式是一個 PostScript 過程,它在 PostScript 直譯器遇到錯誤時執行。它最初由 PS 直譯器安裝,但可以由作業替換。PostScript 驅動程式提供的錯誤處理程式非常基本 - 刪除它。在 Ghostscript 上,你將獲得使用預設錯誤處理程式的更好的錯誤訊息。在其他直譯器上,你可以使用 Adobe 提供的 ehandler.ps。
如果問題仍然不明確,嘗試透過刪除或註釋掉程式碼片段來建立最小的仍然存在問題的程式。使用 { ... } pop 結構是停用 PostScript 程式碼部分的便捷方法。將每個版本的 檔案儲存在不同的名稱下,以便進行多級撤消。當檔案被簡化為一個單一過程時,嘗試用內聯程式碼替換它。當過程被埋在其他程式碼中或多次重新定義時,嘗試在執行位置載入它並列印。例如:/foo load ==。
你可以透過在過程或重新定義運算子中新增列印運算子來跟蹤 PostScript 程式。 Ghostscript 包含一個指令碼 traceop.ps,它可以幫助你在運算子上設定跟蹤。在將指令碼包含到 Postscript 程式的最前面之後,在你想開始跟蹤對運算子 foo 的所有呼叫時,放置 /foo traceop。然後修改過程 /tracebefore 和 /traceafter 以列印一些相關的診斷資訊。例如,/tracebefore { count traceprint } def 將在進入 /foo 之前列印整個堆疊。(/traceprint 基本上執行一個 {print ==only } for,如上所述。)然後正常執行運算子 /foo。如果程式在光柵裝置上無法正確渲染,那麼在 PS 到 PDF 的轉換過程中很可能也會出現同樣的問題。PDF 文件保留了更多資訊,可以被解釋為圖形操作的跟蹤。
LaserTalk 曾經是 Adobe 開發人員工具包的一部分。它是一個 PostScript 印表機的視覺化前端。LaserTalk 只跟蹤了執行的頂層。
PSAlter 來自 Quite Software,是市場上唯一的視覺化 PostScript 偵錯程式。
如何包含一個 EPS 檔案?
[edit | edit source]EPS 格式在 Adobe 技術說明 5002 中有說明,Encapsulated PostScript File Format Specification (PDF 0.2M) 和 PostScript Language Reference Manual 的第二版。規範包括建立 EPS 檔案的指南(它們只是包含幾個必需的標題註釋並承諾不執行某些操作的 PostScript 程式),以及匯入 EPS 檔案的指南。EPS 檔案文字可以簡單地貼上到封閉的 PostScript 程式中,位於 %%BeginDocument: 和 %%EndDocument 註釋之間。(%%BeginDocument: 關鍵字可以後跟描述性文字,例如 EPS 檔名。)封閉程式有責任在插入的 EPS 之前建立一個合適的狀態,並在之後恢復之前狀態。程式應該
- 使用
save對狀態進行快照 - 將
showpage重新定義為無操作 - 將顏色空間、顏色、線帽、線寬、線連線、斜角限制、虛線模式、當前路徑、套印和筆觸調整模式設定為指定的預設值
- 呈現一個空的運算數堆疊和預設的字典堆疊(但包含無操作的
showpage) - 計算並設定一個座標變換,將 EPS 影像放在它想要的地方
- 設定一個與影像的邊界框匹配的剪下路徑
在插入的 EPS 程式碼之後,封閉程式應該丟棄 EPS 程式碼可能留在運算數和字典堆疊上的任何內容,恢復之前的內容,然後在先前的 save 物件上執行 restore,這將撤消所有其他準備工作。
輸出 PostScript 的應用程式通常會省略在每個插入 EPS 影像的地方執行所有這些操作的程式碼,並且它們經常會偷工減料,省略了做出簡化假設的程式碼。特別是在手動編寫 PostScript 時,使用例如 Anastigmatix StatEPSF、ReadyEPSF、ExecEPSF 過程會更方便,它們會自動執行必要的步驟。以下程式碼是將 EPS 放在 (100, 550) 的位置,旋轉 0 度,在兩個軸上縮放 1 所需的全部內容
% in the document setup:
/net.anastigmatix.Import /ProcSet findresource begin
% at the point of import:
{ StatEPSF 100 550 0 1 1 ReadyEPSF ExecEPSF }
currentfile exch exec
%%BeginDocument: helloworld.eps
... the EPS file contents go here
%%EndDocument
當然,沒有任何東西可以阻止應用程式以這種方式生成 PostScript。
一些 EPS 檔案包含預覽影像。在 DOS/Windows 格式中,它們是二進位制資料,在將 EPS 文字貼上到另一個程式時必須將其剝離。EPSI 預覽格式採用 PostScript 註釋的形式,可以刪除以節省空間,但即使保留也不會造成問題。
PostScript 是否支援用於 CJK 字型的 Unicode?
[edit | edit source]PostScript 並沒有專門支援 Unicode。它(從第 2 級開始)包含對多位元組(2、3 或 4 位元組)字型的通用支援。Unicode 只是多位元組編碼的一種特殊情況。沒有真正的 Unicode 字型,但你可以使用支援 Unicode 範圍的多位元組 CID 字型。
沒有免費可重新分發的 Unicode CMaps。它們可以從 MS Windows 內碼表和相應的 Adobe CMaps 推匯出。
開發人員經常尋找一種“簡單”的方法,只需包含 Unicode 字串,而無需檢查範圍、語言等,但這只是一個白日夢。
一些 PostScript 引擎也提供對沒有內部 CID 對映的 TrueType 字型的支援。在這種情況下,這些字型不需要 CID 對映,但只需要一個讀取過濾器來解碼儲存位元組序列的字串的 Unicode 編碼流;可以採用幾種解碼過濾器,包括支援 UTF-8 和 UTF-16 的那些,因為 PostScript 的“read”運算子只需要過濾器返回任何方便的整數,該整數用作字型字典中字形的索引。
過濾器可以在 PostScript Level 2 中被連結並像其他檔案物件一樣被 read 運算子使用。請注意,大多數 PostScript 應用程式期望 bytesavailable 是 read 在不等待或遇到檔案結尾(或字串結尾)的情況下可以返回的整數數量。
然後,read 運算子不僅限於返回範圍為 0..255 的整數,因此 read 的實際返回值是程式碼單元(或程式碼點或字形 ID),使用任何方便的編碼,這種編碼被支援為所選字型的字形索引,並且 read 運算子實際上將從其源(檔案、字串或過程)讀取解碼過濾器所需的儘可能多的位元組。其他標準過濾器支援資料解壓縮,或從任何來源解碼十六進位制或 ASCII85 序列。
因此,與其使用 forall 運算子列舉字串中的字元,不如將字串傳遞給 Unicode 解碼過濾器,並使用 read 迴圈從過濾器物件中列舉字元(或字形索引),然後使用返回的整數索引在複合字體中查詢字形來渲染字元。如果 PostScript 引擎不支援 Unicode 或 TrueType 的本機支援,你將不得不將 TrueType 字型轉換為 CID 對映字型,並使用一個過濾器,該過濾器將返回可與載入到文件序言或作為資源傳輸到列印文件之前的 CID 對映字型一起使用的 CID 值。
你可能還需要一個佈局引擎(如 Pango)將 Unicode 程式碼點處理成一系列字形 ID,並預先計算它們在 PostScript 渲染的文件中的位置,這些位置將在 PostScript 引擎使用相關的過濾器進行編碼和解碼。這種文字佈局引擎在任何情況下都需要支援 BiDi 演算法,以及渲染複雜指令碼、連字、上下文形式或字型中描述的變體,這些變體用在你的文件設計中……