PDF 檔案內文字串 (Stream) 的編碼方式

PDF格式研究

簡介

檔案結構

Stream 編碼

轉為XML

相關工具

OpenPDF

訊息

相關網站

參考文獻

最新修改

簡體版

English

本文介紹了如何將 PDF 中的 stream 欄位轉換為純文字的方法,尤其著重在中文文字的編碼轉換方式上。

簡介

PDF 是一種樹狀結構的文件,stream 是 PDF 中的一個重要的基本元件,因為所有的文字、影像等物件都是被編碼後放到 stream 物件之中,以下是一個範例片段

BT
/F1 24 Tf
100 100 Td
(Hello World) Tj
ET

就是將 Hello World 等字串放到 stream 當中的一個範例。

中文的編碼方式

由於 PDF 是一個跨語言、跨平台的文件格式,因此、所支援的編碼方式非常多樣,包含 Windows 標準 WinAnsiEncoding 字集,繁體中文的 BIG5 以及其擴充版本的倚天字集、簡體中文的 GB2312 字集、日文的 EUC 字集與 Shift-JIS 字集等等,其中、共有 14 種字集是預設在 Acrobat PDF Reader 中就有的,但並不包含中文、日文、韓文等亞洲字集,因此、需要使用到這些多國語言的環境時時,通常需要加入語言的特別安裝,這些安裝中有一個很重要的目錄稱為 CMap ,這是用來作語言編碼對照的檔案,例如:CMap/ETenms-B5-H 是繁體中文的倚天擴充字集對應到 Unicode 的編碼檔,以下是該檔案的一個小片段,

2 begincodespacerange
  <00>   <80>
  <A140> <FEFE>
endcodespacerange

1 beginnotdefrange
<00> <1f> 13648
endnotdefrange

100 begincidrange
<20> <7e> 1
<a140> <a158> 99
<a159> <a15c> 13743
<a15d> <a17e> 128
<a1a1> <a1f5> 162
<a1f6> <a1f6> 248
<a1f7> <a1f7> 247
<a1f8> <a1fe> 249
...

其中的 begincodespacerange 段落說明編碼的範圍第一段是由 00 到 80,第二段是由 A140 到 FEFE ,熟悉 big5 編碼的人應該就曉得這正是 big5 碼的編碼範圍,而第二段的 beginnotdefrange 代表 00 到 1F 是未使用的編碼區段。

第三段的 begincidrange 是真正的編碼對應表,其對應方式是一段一段的對應,例如:<a140> <a158> 99 代表

a140 這個碼被對應到 99
a141 這個碼被對應到 100
a142 這個碼被對應到 101
...

如此、各種編碼方式之間將可以正確正確的對應到標準的 PDF 預設字集 CID 上。

PDF 的預設字集 CID 並不是採用最廣為使用的 Unicode 字集,而是由 Adobe 公司所自行編碼的字集,稱為 Character Idientity 字集,簡稱為 CID 字集,所有的其他字集都會透過 CMap 檔案被對映到這個 CID 字集上,以便在顯示的時取得正確的字形,對於繁體中文而言,PDF 主要使用的除了標準的 CID 字集之外,最常被使用的就是 ETenms-B5-H 這個 CMap 所代表的字集,這是 BIG5 字集的倚天擴充版,關於這個字集的相關資訊可以在 Adobe 的協力開發網站上下載,網址是:

http://partners.adobe.com/public/developer/en/pdf/chinese_t.zip

破解文字編碼

在 PDF 中的中文編碼,並非都固定採用統一個方式,對於繁體中文而言,有時會用 ETenms-B5-H 來編,有時會用 CID 直接編碼,
有時又會用嵌入的方式直接將對映表 CMap 插入在 PDF 檔中成為一個物件,然後用該嵌入式對映表來編碼,因此、要取出 PDF 檔案
中的文字,是相當困難的一件工作,必需對 PDF 的格式有徹底的了解才行。

以下我們再舉一個範例以說明中文編碼與解碼的問題。

4 0 obj
<< /Type /Page
/Parent 3 0 R
/MediaBox [0 0 612 792]
/Contents 5 0 R
/Resources << /ProcSet 6 0 R
/Font << /F1 7 0 R >>
>>
>>
endobj
5 0 obj
<< /Length 73 >>
stream
BT
/F1 24 Tf
100 100 Td
<bd75a457add3a448a4c6b0d1a6d2a4e5c46dbadeb27aa874b2ce> Tj
ET
endstream
endobj
6 0 obj
[/PDF /Text]
endobj
7 0 obj
<< /Type /Font
/Subtype /Type0
/BaseFont /#bc#d0#b7#a2#c5#e9,Bold
/Encoding /ETenms-B5-H
>>
endobj

上述範例中的 &lt;BD75A457ADD3A448A4C6B0D1A6D2A4E5C46DBADEB27AA874B2CE&gt; 其實是『線上個人化參考文獻管理系統』這段文字
以 BIG5 編碼法編成十六進位後的結果。

但是我怎麼知到該段落所使用的編碼法是 BIG5 呢,當我們想寫一個程式去處理這些文字編碼時,就必需要先知到該 PDF 檔案是使用何種編碼法,但是、哪理有紀載這樣的資訊呢?

答案是在 Tf 這個代表字形的標記中,請仔細看上面的範例,其中的 /F1 24 Tf 所代表的就是後面文字段落所採用的字形資訊,代表 &lt;BD75A457ADD3A448A4C6B0D1A6D2A4E5C46DBADEB27AA874B2CE&gt; 這段資訊顯示時應該使用 F1 的字形,而且字形顯示時
的大小設定為 15.75。

要知道 /F1 字形所使用的編碼法,必需逆向追蹤該段落的父節點物件,由於 PDF 中並沒有記載逆向追蹤的資訊,因此、我們必需從上而下正向追蹤過來,才有辦法破解這個秘密。

首先、由於 PDF 是一個印表語言,因此最重要的物件是頁面,也就是範例中的 4 0 obj,屬性 /Type /Page ?明了這是一個頁面,另一個屬性 /Font 7 0 R ,記載了該頁所使用的字形是 /F1,字形資訊儲存在 7 0 這個物件當中,追蹤 7 0 obj 就可以看到下列段落

7 0 obj
<< /Type /Font
/Subtype /Type0
/BaseFont /#bc#d0#b7#a2#c5#e9,Bold
/Encoding /ETenms-B5-H
>>

其中的 /Encoding 屬性說明了該頁面所使用的是 /ETenms-B5-H 的編碼法。

在取得編碼法之後,我們就可以利用 /Contents 這個屬性,得知該頁面的文字內容位於 5 0 R 之中,追蹤 5 0 obj 後就發現下列段落,因此、我們就知道應該用 ETenms-B5-H 這個 BIG5 的對映表來解碼。

5 0 obj
<< /Length 73 >>
stream
BT
/F1 24 Tf
100 100 Td
<bd75a457add3a448a4c6b0d1a6d2a4e5c46dbadeb27aa874b2ce> Tj
ET
endstream

若您要真正寫程式處理 PDF 檔案中的文字時,必須先解壓縮,然後再對 &lt;…&gt; 中的十六進位數字進行解碼,以對應到目標的 CID 編碼,然後在進行處理,但 CID 編碼法畢竟是 Adobe 公司私有的格式,並不容易作處理,因此、我們通長會將這個編碼再度轉換為 Unicode的標準編碼,然後再交給支援 Unicode 的函式庫去處理,像 Java 裏面的函式庫就可以輕易的處理 Unicode 編碼。

要將繁體中文 CID 轉為 unicode ,其對映表檔案是 Adobe-CNS1-UCS2 ,有關轉換為 unicode 的資訊也可在 Adobe 協力開發網http://partners.adobe.com/public/developer/en/pdf/chinese_t.zip 這個網址中找到。

另外、有時轉換為 unicode 的表格會被內嵌在 PDF 檔案中,然後在 /Font 物件中的 /ToUnicode 欄位內指定其物件編號,以下範例說明了這種情況,其中的 12 0 obj 是該嵌入式的 Cmap,可以用來將編碼轉換為 Unicode。

7 0 obj
<< /Type /Font
/Subtype /Type0
/BaseFont /#bc#d0#b7#a2#c5#e9,Bold
/Encoding /ETenms-B5-H
/ToUnicode 12 0 R
>>
...
12 0 R

12 0 obj<< /Length 3407>>
stream
...
100 beginbfchar
<01> <56DE>
<02> <60F3>
<03> <5169>
...
endbfchar
...
endstream
endobj

最後、有些 PDF 文件會將中文字放在 (…) 中以原始位元碼表示,而不是用 16 進位放在 &lt;…&gt; 中,此時,就需要將其內容直接取出,然後用 Encoding 與 ToUnicode 所指定的方式解碼,而不需要透過 16 進位了。 (但是要注意其中的跳出字元\n \t \b ….\ddd 等用法,這些字必需先被轉換成位元組的形式,才能處理)。

結語

PostScript 是為了印表機而發展出來的語言,PDF也繼承了這樣的特性,因此、具有很好的列印品質,但要做加工則相當不易,本文探討了 PDF 的格式,並說明處理中文 PDF 時所經常遇到的一些問題與解決辦法,希望能對您有所幫助。

參考文獻

  1. Portable Document Format Version 1.6,fifth edition,AdobeR Adobe Systems Incorporated - 網址:http://partners.adobe.com/public/developer/en/pdf/PDFReference16.pdf
  2. Adobe Developer Resource - 網址:[[http://partners.adobe.com/public/developer/acrobat/index_advanced.html]]
  3. Portable Document Format, in Wikipedia - 網址:http://en.wikipedia.org/wiki/pdf?qin=pdf&tg=%E7%99%BE%E7%A7%91&q=&s=&hl=&lr=

Facebook

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License