首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在icepdf中显示的图像大小限制

在icepdf中显示的图像大小限制
EN

Stack Overflow用户
提问于 2016-12-09 12:10:14
回答 1查看 421关注 0票数 0

当将一堆PDF呈现到图像中时,icepdf似乎随机地使用了一个OutOfMemoryError。为了追踪这件事,我发现了两件事:

  1. 它在OOM附近呈现了一个A0页面或类似的大型文档页。
  2. 使用eclipse内存分析器,我可以在内存中找到1/2GB的图像。

这建议将输出图像大小限制在可管理的范围内。我想知道做这个最简单的方法是什么?

我查看了icepdf的Page对象,但强烈建议始终使用Page.BOUNDARY_CROPBOX,而且Javadoc中似乎没有记录其他用途。

如何限制Document.getPageImage的输出映像大小,或者可以使用什么其他措施来防止OOM (除了增加Xmx之外,我不能这样做)。降低图像质量是一种选择。但它应该只适用于“超大”图像,而不是适用于所有的图像。

我已经尝试使用Document.paintPage()来使用预定义的映像,但这还不够。

调试最终允许我放大一个有问题的文档。我得到了一个日志,就像:

代码语言:javascript
复制
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的命中时间不够早。

对我来说,忽略这样的超大图片是很好的。有机会吗?

EN

回答 1

Stack Overflow用户

发布于 2016-12-15 16:59:05

在解码PDF内容时,图像加载是内存开销最大的任务。此时,没有一种轻松的方法来关闭真正大的映像的图像加载,但是,如果您想实现这个自我,我将给您一些代码提示。

ImageReferenceFactory.java类是系统属性org.icepdf.core.imageReference后面的工厂,您将看到getImageReferenced()的缺省值是ImageStreamReference。您可以创建如下新的ImageReference类型:

代码语言:javascript
复制
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上加载任何图像。

代码语言:javascript
复制
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,因为这只会对图像进行一次解码。org.icepdf.core.imageReference=scaled实际上将解码图像的全尺寸,然后进行缩放,这可以创建一个非常大的内存尖峰。我们正在试验NIO的直接ByteBuffers,它看起来很有希望将解码内存的使用从堆中移出,因此希望这将在将来变得更好。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/41060193

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档