0

iText 7 を使用して PDF ページを複製し、これらのページに番号を付けています。したがって、手動で番号を付ける必要はありません。しかし、生成された pdf ファイルの数値に問題があります。外観は次のとおりです。

発行イメージ

そして、私は何時間もそれについて考えましたが、まだ理解できません。

私のコード:

import com.itextpdf.io.font.FontConstants;
import com.itextpdf.kernel.font.PdfFontFactory;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfPage;
import com.itextpdf.kernel.pdf.PdfReader;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.kernel.pdf.canvas.PdfCanvas;

import java.io.File;
import java.io.IOException;

public class NumberingInJava {

public static final String SRC = "D:/temp/num_src.pdf";
public static final String DEST = "D:/temp/edited_numbering.pdf";

public static final String[] NUM4SAMPLE = {"02A", "03A", "03B", "03C", "04A", "08A"};

public static final double XCOOR = 230;
public static final double YCOOR = 795;//755

public static void main(String[] args) throws IOException {
    File file = new File(DEST);
    file.getParentFile().mkdirs();
    new NumberingInJava().manipulatePdf(SRC, DEST, NUM4SAMPLE);
}

private void manipulatePdf(String src, String dest, String[] numbering4what) throws IOException {

    //Initialize PDF document
    PdfDocument pdfDocToRead = new PdfDocument(new PdfReader(src));
    PdfDocument pdfDocToWrite = new PdfDocument(new PdfWriter(dest));

    for(String s : numbering4what) {
        println(s);
    }

    String number = null;
    PdfPage tempPage = null;
    for (int i=0; i<numbering4what.length; i++) {
        pdfDocToRead.copyPagesTo(1, 2, pdfDocToWrite);
        number = numbering4what[i];
        println(number);
        tempPage = pdfDocToWrite.getPage(2*(i+1)-1);

        numberingPage(tempPage, number);

        println("pdfDocToWrite.numberOfPages : "+pdfDocToWrite.getNumberOfPages());
    }

    pdfDocToRead.close();
    pdfDocToWrite.close();

    println("\nNumber added!");
}

private void numberingPage(PdfPage pdfPage, String number) throws IOException {
    println(pdfPage);
    PdfCanvas canvas = new PdfCanvas(pdfPage);
    canvas.beginText().setFontAndSize(PdfFontFactory.createFont(FontConstants.HELVETICA), 22)
            .moveText(XCOOR, YCOOR)
            .showText(number)
            .endText();

    println("number: "+number);

}

private void println(Object obj) {
    System.out.println(obj);
}
}

コンソール出力:

02A
03A
03B
03C
04A
08A
02A
com.itextpdf.kernel.pdf.PdfPage@cf768c
17:58:07,457 |-ch.qos.logback.classic.LoggerContext[default] の INFO - リソース [logback.groovy] が見つかりませんでした
17:58:07,458 |-ch.qos.logback.classic.LoggerContext の情報 [デフォルト] - リソース [logback-test.xml] が見つかりませんでした
17:58:07,458 |-ch.qos.logback.classic.LoggerContext[default] の INFO - [jar:file:/D:/Java_Packages/ext_lib/iText/itext7-7.0.1 でリソース [logback.xml] が見つかりました/itext7-itext-rups-7.0.1.jar!/logback.xml]
17:58:07,459 |-ch.qos.logback.classic.LoggerContext[default] の WARN - リソース [logback.xml] がクラスパスで複数回発生します。
17:58:07,459 |-WARN in ch.qos.logback.classic.LoggerContext[default] - リソース [logback.xml] は [jar:file:/D:/Java_Packages/ext_lib/iText/itext7-7.0.1] で発生します/itext7-itext-rups-7.0.1-jar-with-dependencies.jar!/logback.xml]
17:58:07,459 |-WARN in ch.qos.logback.classic.LoggerContext[default] - リソース [logback.xml] は [jar:file:/D:/Java_Packages/ext_lib/iText/itext7-7.0.1] で発生します/itext7-itext-rups-7.0.1-sources.jar!/logback.xml]
17:58:07,459 |-WARN in ch.qos.logback.classic.LoggerContext[default] - リソース [logback.xml] は [jar:file:/D:/Java_Packages/ext_lib/iText/itext7-7.0.1] で発生します/itext7-itext-rups-7.0.1.jar!/logback.xml]
17:58:07,501 |-ch.qos.logback.core.joran.spi.ConfigurationWatchList@8080bb の INFO - URL [jar:file:/D:/Java_Packages/ext_lib/iText/itext7-7.0.1/itext7-itext -rups-7.0.1.jar!/logback.xml] はファイル タイプではありません
17:58:07,662 |-ch.qos.logback.classic.joran.action.ConfigurationAction の INFO - デバッグ属性が設定されていません
17:58:07,829 |-ch.qos.logback.core.joran.action.AppenderAction の INFO - タイプ [com.itextpdf.rups.view.DebugAppender] のアペンダーをインスタンス化しようとしています
17:58:07,851 |-ch.qos.logback.core.joran.action.AppenderAction の INFO - [DEFAULT_APP] として名前のアペンダー
17:58:07,940 |-ch.qos.logback.core.joran.action.NestedComplexPropertyIA の INFO - [encoder] プロパティのデフォルト タイプ [ch.qos.logback.classic.encoder.PatternLayoutEncoder] を想定
17:58:08,045 |-ch.qos.logback.core.joran.action.AppenderAction の INFO - タイプ [com.itextpdf.rups.view.StyleAppender] のアペンダーをインスタンス化しようとしています
17:58:08,046 |-ch.qos.logback.core.joran.action.AppenderAction の INFO - [INFO_APP] として名前のアペンダー
17:58:08,062 |-ch.qos.logback.core.joran.action.NestedComplexPropertyIA の INFO - [encoder] プロパティのデフォルト タイプ [ch.qos.logback.classic.encoder.PatternLayoutEncoder] を想定
17:58:08,063 |-ch.qos.logback.core.joran.action.AppenderAction の INFO - タイプ [com.itextpdf.rups.view.DebugAppender] のアペンダーをインスタンス化しようとしています
17:58:08,063 |-ch.qos.logback.core.joran.action.AppenderAction の INFO - アペンダーに [DEBUG_APP] という名前を付ける
17:58:08,065 |-ch.qos.logback.core.joran.action.NestedComplexPropertyIA の INFO - [encoder] プロパティのデフォルト タイプ [ch.qos.logback.classic.encoder.PatternLayoutEncoder] を想定
17:58:08,066 |-ch.qos.logback.core.joran.action.AppenderAction の INFO - タイプ [com.itextpdf.rups.view.DebugAppender] のアペンダーをインスタンス化しようとしています
17:58:08,066 |-ch.qos.logback.core.joran.action.AppenderAction の INFO - [TRACE_APP] として名前のアペンダー
17:58:08,067 |-ch.qos.logback.core.joran.action.NestedComplexPropertyIA の INFO - [encoder] プロパティのデフォルト タイプ [ch.qos.logback.classic.encoder.PatternLayoutEncoder] を想定
17:58:08,069 |-ch.qos.logback.core.joran.action.AppenderAction の INFO - タイプ [com.itextpdf.rups.view.StyleAppender] のアペンダーをインスタンス化しようとしています
17:58:08,069 |-ch.qos.logback.core.joran.action.AppenderAction の INFO - [IMPORTANT_APP] として名前のアペンダー
17:58:08,075 |-ch.qos.logback.core.joran.action.NestedComplexPropertyIA の INFO - [encoder] プロパティのデフォルト タイプ [ch.qos.logback.classic.encoder.PatternLayoutEncoder] を想定
17:58:08,076 |-ch.qos.logback.classic.joran.action.LoggerAction の INFO - ロガー [com.itextpdf] の加法性を false に設定
17:58:08,077 |-ch.qos.logback.core.joran.action.AppenderRefAction の INFO - [IMPORTANT_APP] という名前のアペンダを Logger[com.itextpdf] に接続しています
17:58:08,078 |-ch.qos.logback.core.joran.action.AppenderRefAction の INFO - [INFO_APP] という名前のアペンダを Logger[com.itextpdf] に接続しています
17:58:08,078 |-ch.qos.logback.core.joran.action.AppenderRefAction の INFO - [DEBUG_APP] という名前のアペンダを Logger[com.itextpdf] に接続しています
17:58:08,078 |-ch.qos.logback.core.joran.action.AppenderRefAction の INFO - [TRACE_APP] という名前のアペンダを Logger[com.itextpdf] に接続しています
17:58:08,078 |-INFO in ch.qos.logback.classic.joran.action.RootLoggerAction - ROOT ロガーのレベルを TRACE に設定
17:58:08,078 |-ch.qos.logback.core.joran.action.AppenderRefAction の INFO - [DEFAULT_APP] という名前のアペンダを Logger[ROOT] に接続しています
17:58:08,078 |-ch.qos.logback.classic.joran.action.ConfigurationAction の INFO - 構成の終了。
17:58:08,082 |-INFO in ch.qos.logback.classic.joran.JoranConfigurator@1c24521 - 現在の構成を安全なフォールバック ポイントとして登録しています

番号: 02A pdfDocToWrite.numberOfPages : 2 03A com.itextpdf.kernel.pdf.PdfPage@11aa95a 番号: 03A pdfDocToWrite.numberOfPages : 4 03B com.itextpdf.kernel.pdf.PdfPage@bc05a6 番号:03B pdfDocToWrite.numberOfPages : 6 03C com.itextpdf.kernel.pdf.PdfPage@ef309d 番号: 03C pdfDocToWrite.numberOfPages : 8 04A com.itextpdf.kernel.pdf.PdfPage@1fc609f 番号: 04A pdfDocToWrite.numberOfPages : 10 08A com.itextpdf.kernel.pdf.PdfPage@173813a 番号: 08A pdfDocToWrite.numberOfPages : 12

数追加!

プロセスは終了コード 0 で終了しました

編集: シミュレートされたドキュメントと編集されたドキュメントをドロップボックスにアップロードしました。ここにあります: シミュレートされたドキュメント

シミュレートされたドキュメントを編集

4

1 に答える 1

0

原因

この問題は、iText が結果の PDF を小さくしようとしているために発生します。

pdfDocToReadに複数回のページをコピーするpdfDocToWriteと、実際のページ コンテンツ ストリーム、ページ リソースなどは 1 回だけコピーされ、これらのデータを参照する小さなオブジェクトがコピーとページごとに 1 回だけ生成されます。

この最適化はまだ問題ではありませんが、さらなるマイクロ最適化は、

PdfCanvas canvas = new PdfCanvas(pdfPage);

このPdfCanvasヘルパー メソッドは、コンテンツが追加されるコンテンツ ストリームを取得するために使用されます。

private static PdfStream getPageStream(PdfPage page) {
    PdfStream stream = page.getContentStream(page.getContentStreamCount() - 1);
    return stream == null || stream.getOutputStream() == null || stream.containsKey(PdfName.Filter) ? page.newContentStreamAfter() : stream;
}

ご覧のとおり、通常、新しいコンテンツ ストリームがページに追加されます ( page.newContentStreamAfter())。コンテンツ ストリームが既に存在し、このストリームにフィルター (圧縮など) がない場合にのみ、この既存のコンテンツ ストリームを使用してデータを追加します。

ドキュメントの場合、ソース ページごとにコピーされた単一のコンテンツ ストリームは圧縮されません。したがって、これら 2 つの最適化により、すべてのPdfCanvas canvasインスタンスが同じ単一のコンテンツ ストリームに追加されます。

回避策

明らかな回避策は、後者の最適化を回避することです。次の行を置き換えます。

PdfCanvas canvas = new PdfCanvas(pdfPage);

PdfCanvas canvas = new PdfCanvas(pdfPage.newContentStreamAfter(), pdfPage.getResources(), pdfPage.getDocument());

( StampPageNumbers.javaメソッド内numberingPage)

これは基本的に、元のコンテンツ ストリームが圧縮されていた場合にも発生することです。

(一般に、save-graphics-state 命令を使用して現在の前に新しいコンテンツ ストリームを実際に追加し、最初に現在の後の新しいコンテンツ ストリームに restore-graphics-state 命令を追加する必要がある場合があります。サンプル ドキュメントの場合、ただし、現在のコンテンツによってグラフィックス状態が悪影響を受けることはないため、これは必要ありません。)

于 2016-10-18T07:21:41.087 に答える