0

特定の PDF で、タグ構造のフラッシュ中に NPE が表示されます。この問題は iText 7.0.2-SNAPSHOT で発生します。iText 5.5.10 はこれらのファイルを問題なく処理します。PdfDictionary.get(PdfName key, boolean asDirect)マップがヌルであるため、NPE がスローされます。そのクラスのマップが null になるのは、releaseContent()が呼び出されたときだけです。

の唯一の目的は、releaseContent()私が知る限り、メモリを解放することであるため、空のメソッドに変更するとどうなるかをテストしました。その結果、ファイルは正常に処理されているように見えます。もう例外はありません。これがサンプルファイルです。

解放された後、少数のオブジェクトのみがアクセスされます。上記のサンプル ファイルの場合、これで問題も解決します。

protected void releaseContent() {
    List<Integer> objs = Arrays.asList(6888, 6856, 6824, 844, 836);
    if (objs.contains(indirectReference.objNr)) {
        return;
    }
    map = null;
}

なぜこれが起こるのかの分析は、私よりも知識のある人に任せます。これが破損した PDF の結果なのか、iText7 のバグなのかはわかりません。

入出力

私が iText 7.0.2-SNAPSHOT でやっていること:

PdfReader reader = new PdfReader(src);
PdfWriter writer = new PdfWriter(dest);
PdfDocument doc = new PdfDocument(reader, writer);
doc.close();`

出力は次のとおりです。

Exception in thread "main" com.itextpdf.kernel.PdfException: Tag structure flushing failed: it might be corrupted.
at       com.itextpdf.kernel.pdf.PdfDocument.tryFlushTagStructure(PdfDocument.java:1746)
at com.itextpdf.kernel.pdf.PdfDocument.close(PdfDocument.java:727)
at perinorm.cleanPdf.MainCleanPDF.run(MainCleanPDF.java:139)
at perinorm.cleanPdf.MainCleanPDF.lambda$2(MainCleanPDF.java:58)
at java.util.stream.ForEachOps$ForEachOp$OfRef.accept(Unknown Source)
at java.util.stream.ReferencePipeline$3$1.accept(Unknown Source)
at java.util.stream.ReferencePipeline$2$1.accept(Unknown Source)
at java.util.stream.ReferencePipeline$3$1.accept(Unknown Source)
at java.util.Iterator.forEachRemaining(Unknown Source)
at java.util.Spliterators$IteratorSpliterator.forEachRemaining(Unknown Source)
at java.util.stream.AbstractPipeline.copyInto(Unknown Source)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(Unknown Source)
at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(Unknown Source)
at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(Unknown Source)
at java.util.stream.AbstractPipeline.evaluate(Unknown Source)
at java.util.stream.ReferencePipeline.forEach(Unknown Source)
at perinorm.cleanPdf.Main.main(Main.java:56)

Caused by: java.lang.NullPointerException
at com.itextpdf.kernel.pdf.PdfDictionary.get(PdfDictionary.java:555)
at com.itextpdf.kernel.pdf.PdfDictionary.get(PdfDictionary.java:146)
at com.itextpdf.kernel.pdf.tagging.PdfStructElem.getK(PdfStructElem.java:338)
at com.itextpdf.kernel.pdf.tagging.PdfStructElem.getKids(PdfStructElem.java:322)
at com.itextpdf.kernel.pdf.tagging.PdfStructTreeRoot.flushAllKids(PdfStructTreeRoot.java:247)
at com.itextpdf.kernel.pdf.tagging.PdfStructTreeRoot.flushAllKids(PdfStructTreeRoot.java:249)
at com.itextpdf.kernel.pdf.tagging.PdfStructTreeRoot.flushAllKids(PdfStructTreeRoot.java:249)
at com.itextpdf.kernel.pdf.tagging.PdfStructTreeRoot.flushAllKids(PdfStructTreeRoot.java:249)
at com.itextpdf.kernel.pdf.tagging.PdfStructTreeRoot.flushAllKids(PdfStructTreeRoot.java:249)
at com.itextpdf.kernel.pdf.tagging.PdfStructTreeRoot.flushAllKids(PdfStructTreeRoot.java:249)
at com.itextpdf.kernel.pdf.tagging.PdfStructTreeRoot.flush(PdfStructTreeRoot.java:184)
at com.itextpdf.kernel.pdf.PdfDocument.tryFlushTagStructure(PdfDocument.java:1744)
... 16 more
4

1 に答える 1

0

この問題の直接の原因は、サンプル ドキュメントの構造ツリーで、いくつかのノードが複数回使用されていることです。

6770 0 obj
<<
  /K [ 6873 0 R 6874 0 R 6875 0 R 6876 0 R 6877 0 R 6878 0 R 6879 0 R
       6880 0 R 6881 0 R 6882 0 R 6883 0 R 6884 0 R 6885 0 R 6886 0 R
       6887 0 R 6888 0 R 6888 0 R ]
  /P 5874 0 R
  /S /TR    
>>

ご覧のとおり6888 0 R、この構造ツリー ノードの子の配列で が 2 回発生します。

iText 7 が を閉じるとPdfDocument、構造ツリーをたどり、見つかった各要素をターゲット ドキュメントにフラッシュします。

private void flushAllKids(IPdfStructElem elem) {
    for (IPdfStructElem kid : elem.getKids()) {
        if (kid instanceof PdfStructElem) {
            flushAllKids(kid);
            ((PdfStructElem) kid).flush();
        }
    }
}

(からPdfStructTreeRoot)

したがって、手元のドキュメントでは、最初の参照が見つかったときに子辞書オブジェクト 6888 0 をフラッシュし6888 0 R、2 番目の参照が見つかったときに失敗します。

私は構造ツリーにあまり興味がないので、構造ツリーにエントリを繰り返してよいかどうかわかりません (結局のところ、特定のノードが次のように参照されることを示すことができるツリーと呼ばれます)。子供は一度だけ)。ただし、上記の方法を次のように変更することで、そのような繰り返し使用されるノードに対して iText を強化できます

private void flushAllKids(IPdfStructElem elem) {
    for (IPdfStructElem kid : elem.getKids()) {
        if (kid instanceof PdfStructElem) {
            if (!((PdfStructElem) kid).isFlushed())
            {
                flushAllKids(kid);
                ((PdfStructElem) kid).flush();
            }
        }
    }
}

この変更により、サンプル ドキュメントは例外なくスタンプされます。

于 2016-10-10T09:55:43.130 に答える