ぽんぽこ日記

プログラミング、読書、日々の生活

アジア言語圏のPDFのテキスト抽出 3

フォント情報から文字コードを得る方法です。

まず、Font情報はそのフォントを使用するページのResourceとして登録されているので、その情報を取り出します。

  CGPDFPageRef page;

  // page ページオブジェクトを取得。。。

  CGPDFDictionaryRef pageDict  =  CGPDFPageGetDictionary(page);
  CGPDFDictionaryRef resourceDict  =  NULL;
  CGPDFDictionaryRef fontDict  =  NULL;
  // フォント辞書をスキャン
  if(CGPDFDictionaryGetDictionary(pageDict, "Resources", &resourceDict ) ) {
    if(CGPDFDictionaryGetDictionary(resourceDict, "Font", &fontDict ) ) {
      CGPDFDictionaryApplyFunction(fontDict,enumerateFontsInDictionary,self);
    }
  }

enumerateFontsInDictionaryコールバック関数はこんな感じ。

void  enumerateFontsInDictionary(const char *key, CGPDFObjectRef value, void *info) {
  if(CGPDFObjectGetType(value) != kCGPDFObjectTypeDictionary){
    return;
  }
....
}

コールバック関数の引数の「key」には、PDFのフォント指定演算子で参照されるフォント名が入っています。前回エントリの例でいうと、「C2_0」です。

この関数で得られた、PDFシステムが各文字列を印字・表示する際に使用するフォント情報のプロパティに応じて、文字列をデコードします。

フォントがEncoding項目が'Identity-H'もしくは'Identity-V'で、なおかつ 'ToUnicode'ストリームを持っている場合



この場合、文字列として渡されるのはshort型のCIDの配列なので、CIDからUnicodeへの変換テーブルをToUnicodeストリームの内容から得ます。

ToUnicodeストリームを取り出したら、中身のバイト列を得ます。

NSData* data= (NSData*)CGPDFStreamCopyData(toUnicodeStream,CGPDFDataFormatRaw );

[data byytes]で取り出されるバイト列は、cidToUnicodeCMapとよばれる変換情報がかかれた文字列なので、パースしてCIDからUnicodeへの変換を得ます。

例)

%!PS-Adobe-3.0 Resource-CMap
<<中略>>
67 beginbfchar
<0002> <0020>
<0012> <0030>
...
endbfchar

1 beginbfrange
<000e> <0010> <002c>
endbfrange
endcmap
CMapName currentdict /CMap defineresource pop
end
end

beginbfcharから endbfcharまでの行は1カラム目のCID番号と2カラム目のUnicodeが1対1で対応しています。
beginbfrangeからendbfrangeまでは、1カラム目が範囲の始まり、2カラム目が範囲の終わり、3カラム目が範囲の始まりのCIDに対応するUnicode値になります。

たとえば、上のtoUnicodeCMapの例では、CID値が0x000fな値があったとすると、bfrangeの1行目<000e>〜<0010>の範囲に入り、

 0x002c + ( 0x000f - 0x000e ) = 0x002d

が得られます。


フォントのEncoding項目が'Identity-H'もしくは'Identity-V'で、なおかつ 'ToUnicode'ストリームを持っていない場合

CJKVのフォントの多くがこれに相当します。
このばあい、ToUnicodeCMapを外部ファイルから取得する必要があります。CIDとUnicodeの変換は国ごとに異なっているので、取得すべきToUnicodeCMapを同定する必要があります。
これは、DecsendantFonts項目のCIDSystemInfo項目から得ます。
CIDSystemInfoは、Registy,Ordering,Supplementの3項目が格納されていますが、このうち、Registy,Orderingをハイフン「-」でつないだものを用いて同定します。

例)
Adobe-CNS1
Adobe-Japan1

これらプロジェクトで配布されているファイルは、CID番号の順に対応するunicode値が書かれています。配列に格納してCID値でアクセスすればよいでしょう。

※このマッピングファイルはxpdf,popplerといったオープンソースプロジェクトから配布されているものが入手しやすいようですが、使用にあたっては。配布条件を確認してください。

フォントのEncoding項目が'Identity-H'もしくは'Identity-V'で無い場合

Encoding項目に応じてデコードします。各Encodingの詳細はPDF企画書「PDF32000_2008.pdf」のTable 118に定義されているので、NSStringが持つデコード方式や、必要に応じてiconvを使ってunicodeに変換するとよいでしょう。

↓こういう本が出るようです。期待。

PDF構造解説

PDF構造解説

Amazon