2016-12-09 3 views
0

При рендеринге кучи PDF-файлов изображениям icepdf, казалось бы, случайно удаляется OutOfMemoryError. Попытка отследить это вниз, я найти две вещей:Ограничить размер изображения в icepdf

  1. Близко к ООМУ вынесенной странице A0 или аналогичным образом больших страниц документа
  2. С затмением анализатором памяти я нахожу 1/2 Гб изображения в памяти.

Это позволяет ограничить размер выходного изображения чем-то управляемым. Интересно, что самый простой способ сделать это?

Я смотрел объект страницы icepdf, но там настоятельно рекомендуется всегда использовать Page.BOUNDARY_CROPBOX, и другие виды использования, похоже, не документируются в Javadoc.

Как ограничить размер выходного изображения 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, ширина = 13248, который действительно огромен.

Я полагаю, что OOM происходит уже во время загрузки изображения, поэтому дальнейшее масштабирование не помогает. Также кажется, что свойство org.icepdf.core.imageReference=scaled не ударило достаточно рано.

Для меня было бы замечательно просто игнорировать негабаритные изображения, подобные этому. Любой шанс?

ответ

1

Загрузка изображения на сегодняшний день является наиболее важной задачей памяти при декодировании содержимого PDF. В настоящее время нет способа esasy по отключению загрузки изображения для действительно большого изображения, однако я дам вам несколько подсказок кода, если вы хотите реализовать это самостоятельно.

Класс 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 как это будет декодировать изображение только один раз. org.icepdf.core.imageReference=scaled фактически декодирует изображение в полном размере, а затем сделает масштаб, который может создать очень большой всплеск памяти. Мы экспериментируем с прямыми ByteBuffers от NIO, которые выглядят многообещающими для переноса использования памяти декодирования из кучи, поэтому, надеюсь, в будущем это улучшится.

+0

Это то, что я грустно догадался: изображения могут стать чрезвычайно большими при загрузке. Я попробовал ваше предложение о внедрении SkipImageStreamReference.С Xmx = 900m (преднамеренно немного маленьким) он все еще бомбит OOM на изображениях размером менее 1500x1500. У нас есть много схем построения с размерами от 10000^2 до 20000^2, поэтому нам потребуется, если линейно масштабировать, более 90 ГБ оперативной памяти. – Harald

+0

Байт-буферы с отображением памяти будут препятствовать OOM, но они по-прежнему требуют либо большого количества ОЗУ, либо огромного пространства подкачки или файла подкачки, что приведет к урон производительности. Я понятия не имею, как рендеринг PDF действительно работает, но я подозреваю, что должен быть способ иметь даже первоначальный рендеринг, уменьшающий разрешение до требуемого размера. – Harald

Смежные вопросы