0

一連の PDF を画像にレンダリングしているときに、icepdf がランダムに OutOfMemoryError を出すように見えます。これを追跡しようとすると、次の 2 つのことがわかります。

  1. A0ページまたは同様に大きなドキュメントページをレンダリングしたOOMに近い
  2. Eclipse メモリ アナライザーを使用すると、メモリ内に 1/2GB の画像が見つかります。

これは、出力画像のサイズを扱いやすいサイズに制限することを示唆しています。これを行う最も簡単な方法は何ですか?

私はicepdfのPageオブジェクトを見ましたが、常に使用することを強くお勧めします.JavadocにはPage.BOUNDARY_CROPBOX他の用途が記載されていないようです.

出力画像サイズを制限するにはどうすればよいですか、Document.getPageImageまたは OOM を防ぐために使用できる他の手段は何ですか (Xmx を増やすだけではありませんが、それはできません)。画質の低下はオプションです。ただし、すべてではなく、「大きすぎる」画像にのみ適用する必要があります。

Document.paintPage() を使用して定義済みの画像を使用しようとしましたが、これでは十分ではありませんでした。

デバッグにより、問題のあるドキュメントを拡大できるようになりました。次のようなログが表示されます。

2016-12-09T14:23:35Z    DEBUG   class org.icepdf.core.pobjects.Document 1       MEMFREE: 712484296 of 838860800
2016-12-09T14:23:35Z    DEBUG   class org.icepdf.core.pobjects.Document 1       LOADING: ..../F1-2.pdf
2016-12-09T14:23:37Z    WARN    class org.icepdf.core.pobjects.graphics.ScaledImageReference    1       Error loading image: 9 0 R Image stream= {Type=XObject, Length=8 0 R, Filter=FlateDecode, ColorSpace=DeviceGray, Decode=[1, 0], Height=18676, Width=13248, Subtype=Image, BitsPerComponent=1, Name=Im1}  9 0 R

これは Height=18676, Width=13248 となり、これは非常に大きいです。

画像の読み込み中に OOM が既に発生していると思われるため、後でスケーリングしても役に立ちません。また、プロパティorg.icepdf.core.imageReference=scaledが十分に早くヒットしないようです。

私にとっては、このような特大の画像を無視しても問題ありません。チャンスはありますか?

4

1 に答える 1

1

画像の読み込みは、PDF コンテンツをデコードする際に最もメモリを消費するメモリ タスクです。現時点では、非常に大きな画像の読み込みをオフにする簡単な方法はありませんが、これを自分で実装したい場合は、いくつかのコードのヒントを提供します。

ImageReferenceFactory.java クラスは、システム プロパティの背後にあるファクトリorg.icepdf.core.imageReferenceです。getImageReferenced() のデフォルトが ImageStreamReference であることがわかります。次のように、新しい ImageReference タイプを作成できます。

public static org.icepdf.core.pobjects.graphics.ImageReference
getImageReference(ImageStream imageStream, Resources resources, GraphicsState graphicsState,
                  Integer imageIndex, Page page) {
    switch (scaleType) {
        case SCALED:
            return new ScaledImageReference(imageStream, graphicsState, resources, imageIndex, page);
        case SMOOTH_SCALED:
            return new SmoothScaledImageReference(imageStream, graphicsState, resources, imageIndex, page);
        case MIP_MAP:
            return new MipMappedImageReference(imageStream, graphicsState, resources, imageIndex, page);
        case SKIP_LARGE:
            return new SkipLargeImageReference(imageStream, graphicsState, resources, imageIndex, page);
        default:
            return new ImageStreamReference(imageStream, graphicsState, resources, imageIndex, page);
    }
}

ImageStreamReference次に、新しいクラスでクラスを拡張できますSkipLargeImageReference。次に call() メソッドを次のようにオーバーライドすると、定義された MAX_SIZE を超える画像の読み込みがスキップされます。

public BufferedImage call() {
    BufferedImage image = null;
    if (imageStream.getWidth() < MAX_SIZE && imageStream.getHeight() < MAX_SIZE){
        long start = System.nanoTime();
        try {
            image = imageStream.getImage(graphicsState, resources);
        } catch (Throwable e) {
            logger.log(Level.WARNING, "Error loading image: " + imageStream.getPObjectReference() +
                    " " + imageStream.toString(), e);
        }
        long end = System.nanoTime();
        notifyImagePageEvents((end - start));
        return image;
    }
    return null;
}

補足: 画像のデコードに必要なメモリ量を最小限に抑えるには、org.icepdf.core.imageReference=default画像を 1 回だけデコードするため、使用していることを確認してください。 org.icepdf.core.imageReference=scaled実際に画像をフルサイズでデコードしてから、非常に大きなメモリスパイクを作成する可能性のあるスケーリングを行います。私たちは NIO のダイレクト ByteBuffers を試しています。これは、デコード メモリの使用量をヒープから移動するのに有望であると思われるため、将来的にはこれが改善されることを願っています。

于 2016-12-15T16:59:05.023 に答える