PDFからフォントを抽出する

アドビのWebサイトにある多くのメガバイトのPDFReferenceよりも優れたフォーマット情報はないことをすぐに言う必要があります。 C ++で書く人には、既製のソリューション-XPDFがあります。 Linuxでは、これはAdobe製品の最も完全な機能を備えた代替品です。 このテーマに関するロシア語の資料は表面的なものであり、実際の作業ではなく、知人だけに役立ちます。 しかし、皆さんが既にそれらに精通しており、PDFReferenceに精通していることを願っています。 PDFのTrueTypeフォントからフォントを抽出する特定の簡単な例を説明することにしました。なぜなら、この質問はネットワーク上で非常に頻繁に聞こえ、未回答のままだからです。 私は、エラーなしでソースなしで動作するこのようなプログラムを1つだけ知っています。 抽出されたフォントを使用することは必ずしも合法ではなく、文書からのテキストは埋め込みフォントでのみ表示できることを思い出してください。



この質問に興味がある人は、PDFが見出し、相互参照表(XRef)、本文、およびトレーラー(トレーラー)で構成されていることを知っています。 タイトル以外のすべての要素は、ドキュメント全体に部分的におよびいくつかのコピーに散在する可能性があります。 まず、外部参照テーブルを読む必要があります。 クラスにすることをお勧めします。 テーブルのアドレスを見つけるために、%% EOFタグに到達するまでファイルを最後から読み取ります。 startxrefタグを逆読みし続けます。 これで、このタグに続く番号を読み取ることができます。

ファイルの終わりの例を次に示します。



startxref

173

%% EOF

番号173は、ファイルデータの先頭から最初のXRefテーブルの先頭までのオフセットです。 このポイントに移動すると、次のようなものが表示されます。

外部参照

7628 42

0000000016 00000 n

0000001195 00000 f

などなど。



7628(これは、ページ数に関する情報が記録される最初のオブジェクトの名前であり、他の多くのものも同様です)には注意を払いません。 また、42はテーブルのこの部分のレコード数です。 さらに、非常に簡単です。最初の単語を10バイトのバッファーに読み込み、スペースをスキップして5バイトのバッファーを読み込み、1文字を読み込みます。 そして42回。 整数に変換された文字列には次の意味があります-データの先頭から参照オブジェクトへのオフセット、世代番号。 最後の文字は次のように解釈されます。n-オブジェクトが使用され、f-オブジェクトは使用されませんが、先ほど述べたように、XRefテーブルにはファイルストリームに拡張子がある場合があります。 それらを見つける方法? トレーラタグは常にテーブルの後に続きます。 それが満たされたら、行/前を探す必要があります-もしあれば、次の表へのオフセットが続きます。



/前4025745



したがって、複数のテーブルがある場合は、すべてのテーブルを読み取ります。 次のトレーラーに/ Prevスイッチがない場合は、読み終えることができます。 最後のテーブルの記号は、レコード0000000000 65535 fで始まることもあります。 表を逆読みし、最後の表は文書自体の作成時に現れた最初の表であり、最後の編集後の表は最初の表であると言わなければなりません。



データを使用して、ドキュメント内の任意の参照オブジェクトに移動できます。 確かに、アドレスが外部参照に含まれていない直接オブジェクトがまだありますが、それについては後で詳しく説明します。 これで、ドキュメントのオブジェクトを反復処理して、それらのタイプを確認し、私たちの心が望むものを実行できます。 オブジェクトは次のように始まります。



7626 0オブジェクト

オブジェクトの内容

endobj



7626はオブジェクトの番号(名前)、0は世代番号であり、このオブジェクトのリンクテーブルの同様の値と一致する必要があります。 私が理解しているように、オブジェクトが変更され、編集されると、世代番号も増加します。 フォントを探します。そのためには、オブジェクトの辞書を読み取る必要があります。これは、タグ<< ... >>で囲まれた語彙素です。 辞書の要素がそのような構造を持っている場合、例えば:



/ FirstChar 32



ここで、スラッシュの後の単語がキーであり、スペースの後のオプションの値が値です。 解析するとき、値には、他の辞書を含む、ネストのデータを含めることができることを覚えておく必要があります。 したがって、フォントを抽出する特定のタスクに取り組んでいる場合、再帰は再帰なしで手に入れられます。 指定された値には、次のタイプのネストまたはネストされていない要素も含まれます。



(...)-テキスト文字列

<...>-16進文字列

[...]-配列



値の文字列は、次のスラッシュまたは改行まで続きます。 フォントオブジェクトを識別するには、辞書で組み合わせを見つける必要があります。



/タイプ/フォント

次に、シーケンス辞書の内容に従ってTruetypeフォントをフィルタリングします。

/サブタイプ/ TrueType



フォントを抽出するだけなので、残りのキーは無視します。 ただし、このオブジェクトではフォント自体が見つからない可能性が最も高くなります。 不要なキーのセットのみ。 それらの1つを読みます。



/ FontDescriptor 1675 0 R



そのようなキーが欠落している場合、フォントは外部であり、文書に埋め込まれていません。 次はこのオブジェクトの世代番号であり、記号Rはこれがリンクであることを意味します。 既にXRefテーブルを読み込んでおり、1675の番号のオブジェクトのオフセットを検索することにより、フォントデータに移動できます。True、このオプションは可能です。



/ FontDescriptor <<辞書および/またはフォントデータ>>



直接のオブジェクトへのリンクをたどっていると仮定します。 彼の辞書には次のキーが含まれている必要があります。



/タイプ/ FontDescriptor



このオブジェクトには、フォントに関する多くの有用な情報もありますが、フォント自体は存在しません。 私のせいではない-アドビに対するすべての主張。 このようなキーが必要です



/ FontFile2 1676 0 R



おなじみのデザイン。 次のオブジェクトに移動します。 すべてが正しければ、これはストリーミングオブジェクトです。 ストリームディクショナリと、stream ... endstreamタグで囲まれたバイナリデータで構成されます。 ここでは、バイナリデータの存在は既成のテキストパーサーの使用を許可しないと言わなければなりません。 私は多くのことを試してみたので、最初から自分で書きました。 ストリームディクショナリにはストリーム長の/長さスイッチがあるため、バイナリデータを一度に読み取ることができます。 抽出されたストリームを拡張子TTFのファイルに保存しようとすると、システムはこれがフォントではないことを通知します。 そうです、あなたはそれを解く必要があります。



フォントは多くの場合zipを使用して圧縮されますが、忠実にするために/ FlateDecodeキーの存在によってこれを確認できます。 Delphiで作業する場合は、標準のZLibを使用します。 キー/ Length1を使用して、ストリームディクショナリから非圧縮データのバッファサイズを取得できます。 ドキュメントに組み込まれているフォントには、ドキュメントで使用されているグリフのみが含まれていることを知っておく必要があります。



これらのヒントの後、片方の手で16進表示を、もう片方の手でPDFReferenceを取得し、独自のAcrobatRiderのコストがかかると思います。



All Articles