前回の続きです。
PDFの文字列描画命令は、TJ、Tj演算子のオペランド文字列のエンコードとキャラクタセットは、先だって実行されたTmオペレータのフォントの指定に従っています。
たとえば、
/C2_0 1 Tf 0 Tc 4.093 0 Td <0DFA0F6703D303E903B703BF03B1029406120370037703C3029403BB069E0F17037708370996053D>Tj
みたいな感じ。
- 1行目のTfオペレータでフォントを指定し、
- 2行目で文字のスペーシングとテキストの位置を指定
- 3行目で文字列描画
ちなみに、たいていのPDFではエディタで直接PDFを開いてもこういうコードは書いてなくて、圧縮されたコンテントストリームとして格納されています。36641 0 obj <</First 2311/Length 6988/Filter/FlateDecode/N 200/Type/ObjStm>>stream バイナリ endstream
上記の例だとバイナリの部分は、FlateDecodeというフィルタで圧縮されていると書かれており、zlibを使えば解凍できるはずです。PDFではBase64のフィルタなどが定義されています。CGPDFScannerをつかって特定のオペレータとオペランドの情報を取得すればいいと思いますが、フィルタを適用した後の生のストリームを取り出すこともできます。
Core GraphicsのPDFパーサ機能を使えば、CGPDFPageRef page = CGPDFDocumentGetPage ( pdfDocument, pageNum );でページオブジェクトを取得して、
CGPDFContentStreamRef stream= CGPDFContentStreamCreateWithPage(page); CFArrayRef array = CGPDFContentStreamGetStreams(stream);ページに含まれるコンテントストリームの配列を取得し、
CGPDFStreamRef o = CFArrayGetValueAtIndex(array, 0 ); CFDataRef data = CGPDFStreamCopyData(O, CGPDFDataFormatRaw);CGPDFStreamCopyData()で生のデータを取得できます。ストリームはJPEGデータであることもあるので、実際に使う場合は、事前にCGPDFStreamGetDictionary()をつかってストリームの種類を判別しておく必要があります。
PDFの描画の仕組み上、TfオペレータはTjオペレータより前に出現するので、CGPDFScannerをつかって、Tfオペレータを検出して、あらかじめエンコーディングの情報を得ておき、直後に出現したTjオペレータのオペランドを適切にデコードしてやればテキスト情報が取得できます。
ここから本題の、PDFにおけるフォントと文字エンコーディングを調べる方法になるのですが、コードの準備がまだなので、次回書きます。
その代わりといっては何ですが、今回私が調査に使った資料とツールを紹介しておきます。
PDFの国際規格 ISO 32000-1 の企画書
PDF Reference and Adobe Extensions to the PDF Specification
700ページ超の大部ですが、今回のような用途の場合、7章と9章を読めば大方の情報は得られます。
CJKV日中韓越情報処理
通称フグ本。
プログラマのための文字コード技術入門
(それにしても、WEB+DBPress+シリーズは名著揃いですね!)
PDFの構造を表示するAppleのサンプルツール
Voyeur-PDF
below氏がMacOSX 10.6.x用にビルドできるようにしたもの。http://github.com/below/PDF-Voyeur
↓こういう本が出るようです。期待。
[asin:4873115493:detail]