8

このメソッドを使用して pdf を変更しようとしています (最初のコード ブロック - PDFStreamParser を使用して PDFOperator を反復し、必要に応じて COSString を更新します):

http://www.coderanch.com/t/556009/open-source/PdfBox-Replace-String-double-pdf

一部の UTF-8 文字 (分音記号) に問題があります: 更新したいテキストを印刷すると、「Societ? ?ii Na?ionale」のように表示されます (「?」は 0002 または 0004 のようなコードです)。 )。

面白いことは次のとおりです。

  1. 更新されたpdfファイルを書き込むと、文字が正しく表示されます(検出して置き換えることはできませんでしたが)
  2. PDFTextStripper の getText(...) を使用してテキストを削除しようとすると、テキストが完全に抽出されます。
  3. 私は2つのpdfboxバージョンを試しました:1.5.0(上記のように動作します)と1.8.1(最終的に書かれたpdfファイルは特殊文字を正しく表示せず、ドキュメントに「null」文字列が表示されます)

すべての UTF-8 文字が正しく表示されるように、pdf の更新 (または少なくとも試してください...) に使用されるクラスに対して何ができますか (構成できますか?)

編集:

スクリーンショット:ここに画像の説明を入力

編集2:

PDFTextStripper とそのスーパークラスの pdfbox ソース コードを検索したところ、テキストがどのように抽出されたかがわかりました。

processStream メソッドの先頭に

graphicsState = new PDGraphicsState(aPage.findCropBox());

processEncodedText でテキストを削除する場合、PDFont クラスのインスタンスは次のように使用されます。

final PDFont font = graphicsState.getTextState().getFont();

テキストは次のように byte[] から抽出されます。

String c = font.encode( string, i, codeLength );

新しい問題は、同じ 2 行のコードで PDFont クラスをインスタンス化すると、「null」フォント クラスが取得されるため、.encode(...) メソッドを使用できないことです。これらのクラスのソース コードは次のとおりです http://grepcode.com/file/repo1.maven.org/maven2/org.apache.pdfbox/pdfbox/1.5.0/org/apache/pdfbox/util/PDFTextStripper.java

私は今もっと掘り下げています...

4

2 に答える 2

20

文字列内のテキストを単に置き換えることはできません。私はこれを軽く言いません。私は何年も前に Acrobat で作業していて、最初のバージョンでテキスト検索ツールを使用していたので、テキスト エンコーディングの問題についてかなり深い理解を持っています。主な問題は、PDF のすべての文字列が何らかの方法でエンコードされていることです。これは、Unicode が一般に利用可能になる前に PDF が作成され、PostScript に歴史があったためです。PosctScript は、フォントのエンコード方法が非常に柔軟であることを好み、再エンコードを奨励しました。

それでは、一歩下がって全体像を理解しましょう。

テキスト演算子で表示される PDF の文字列の文字は、デフォルトで、一連の 8 ビット文字としてエンコードされます。各バイトにどのグリフを描画するかを決定するために、そのバイトはそのフォントのエンコード ベクトルを介してプッシュされます。エンコーディング ベクトルはバイトをグリフ名にマップし、フォントで検索してページに描画します。この説明は半分真実であることに注意してください (詳細は後述)。

PDF を生成するほとんどのアプリは親切で、 や などの標準エンコーディングを使用するだけStandardEncodingWinAnsiEncodingあり、そのほとんどはかなり合理的です。他の人は、標準エンコーディングとエンコーディングされたものとの違いであるエンコーディング デルタとともに標準エンコーディングを使用します。

一部のアプリは、生成する PDF をより節約しようとするため、使用するグリフを調べて、フォントのサブセットを埋め込むことを決定します。大文字と小文字のローマ字と数字のみを使用する場合、それらの要素を使用せずにフォントを再構築し、同様にインデックスを再作成して、バイト 0x00 がグリフ 'a' に移動し、0x01 がグリフ「b」など。

ここで半分真実に戻ります。文字 ID (または CID) によってエンコードされるフォントのクラスがあり、TrueType および OpenType フォントはそのカテゴリに分類されます。この場合、Unicode にアクセスできますが、文字列 (現在は UTF16BE) がフォントからグリフを取得するために使用される CID にマップされるエンコード手順があります。特に正当な理由もなく、Adobe は PostScript 関数を使用してマッピングを行います。繰り返しますが、これは 3/4 の真実です。中国語、日本語、および韓国語のフォントの古い管理にも異なるエンコーディングがあるためです。

したがって、PDF フォントの文字列に簡単に文字を入れる前に、いくつかの質問をする必要があります。

  1. 私のグリフはフォントにありますか?
  2. 私のグリフはエンコーディングにありますか?
  3. 私のグリフのエンコーディングは何ですか?

そして、それらのいずれかがあなたの期待とは異なる場合があります。たとえば、Ä (ディレシス) を入れたい場合は、フォントにグリフがあるかどうかを確認する必要があります (フォントがサブセットであるため、グリフがない場合があります)。その場合、フォントには、グリフを含まないおかしなエンコーディングが含まれている可能性があります。最後に、Ä に使用する実際のバイト値は標準ではない場合があります。

そのため、誰かが PDF コンテンツのテキストのチャンクを単純に置き換えようとしているのを見ると、苦痛の世界しか見えません。ほとんどの正常な PDF では、これは 90% の確率で機能しますが、風変わりな PDF ではうまくいきます。PDF のテキスト レンダリングの癖は非常に難しいため、書き込み専用の形式と考える方が簡単な場合があります。

于 2013-04-12T14:12:44.320 に答える
1

最後に、pdf ファイル内のフォントを抽出するプロセスは非常に複雑であることがわかります。フォントを明示的に使用できなかったので、PDFStreamEngine のコードと OperatorProcessor を拡張するクラスを検索し、PDFont オブジェクトがマップに作成された方法を見つけました (分音記号を抽出するために必要なコードのチャンクをほとんどコピーしました)。 . そのため、その後、parser.getTokens() を介して対話するときに検出されたフォントを使用して、「文字列」内の各文字に対して encode(...) メソッドを呼び出しました。

于 2013-04-16T08:29:40.140 に答える