Can I reduce pdfbox memory use in my code or should I expand Java heap space

Viewed 1252
  • My pdf is 20 MB and four pages.
  • When my program crashes, I have 1 GB of free RAM
  • I have tried adding setupTempFileOnly to the load method without any change.
  • Used Memory first loop 217 MB, Used Memory second loop 220 MB
  • I get two jpg files but my program crash third loop, on page 3.
  • I want to export all pages as jpg with the highest jpg quality (low jpg compression)
  • I use the latest Java version and pdfbox 2.0.20

My pdf is not very large and has only four pages. Can I optimize my code to use less memory? Can I do someone clean after each loop?

My code

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.plugins.jpeg.JPEGImageWriteParam;
import javax.imageio.stream.FileImageOutputStream;

import org.apache.pdfbox.io.MemoryUsageSetting;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.rendering.ImageType;
import org.apache.pdfbox.rendering.PDFRenderer;

import net.coobird.thumbnailator.Thumbnails;

public class PdfToImage {
       public static void main (String args[]) throws IOException {
           File file = new File("C:/myPath/printfile.pdf");
            PDDocument document = PDDocument.load(file, MemoryUsageSetting.setupTempFileOnly());
            PDFRenderer renderer = new PDFRenderer(document);
           
           try {
               int pageNumber = 0;
               for( PDPage page : document.getPages() )
                {
        
        float trimboxWidth = page.getTrimBox().getWidth();
        float trimboxHeight = page.getTrimBox().getHeight();
        
        float mediaboxWidth = page.getMediaBox().getWidth();
        float mediaboxHeight = page.getMediaBox().getHeight();
        
        float getY = (mediaboxHeight - trimboxHeight) / 2;
        float getX = (mediaboxWidth - trimboxWidth) / 2;
        
        PDRectangle rectangle = new PDRectangle(getX, getY, trimboxWidth, trimboxHeight);
        
        //Crop the page
        page.setCropBox(rectangle);
        
        //Rendering an image from the PDF document
        BufferedImage image = renderer.renderImageWithDPI(pageNumber, 96, ImageType.RGB);
                
        //Resize the image
        BufferedImage thumbnail = 
                Thumbnails.of(image)
                    .height(700)
                    .asBufferedImage();

        //Writing the image to a file
        JPEGImageWriteParam jpegParams = new JPEGImageWriteParam(null);
        jpegParams.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
            jpegParams.setCompressionQuality(1f);
        
        final ImageWriter writer = ImageIO.getImageWritersByFormatName("jpg").next();
        // specifies where the jpg image has to be written
        writer.setOutput(new FileImageOutputStream(
          new File("C:/myPath/myimage" + pageNumber + ".jpg")));
        
        writer.write(null, new IIOImage(thumbnail, null, null), jpegParams);

            System.out.println("Used Memory: " +  (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()));
       pageNumber++; 
            
                }
           }
           finally
            {
                if( document != null )
                {
                    document.close();
                }

            } 
       }
}

Error message third loop

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at java.util.HashMap.replacementTreeNode(Unknown Source) at java.util.HashMap.treeifyBin(Unknown Source) at java.util.HashMap.putVal(Unknown Source) at java.util.HashMap.put(Unknown Source) at org.apache.pdfbox.pdmodel.graphics.shading.TriangleBasedShadingContext.calcPixelTable(TriangleBasedShadingContext.java:121) at org.apache.pdfbox.pdmodel.graphics.shading.PatchMeshesShadingContext.calcPixelTable(PatchMeshesShadingContext.java:280) at org.apache.pdfbox.pdmodel.graphics.shading.TriangleBasedShadingContext.createPixelTable(TriangleBasedShadingContext.java:80) at org.apache.pdfbox.pdmodel.graphics.shading.PatchMeshesShadingContext.(PatchMeshesShadingContext.java:71) at org.apache.pdfbox.pdmodel.graphics.shading.Type7ShadingContext.(Type7ShadingContext.java:46) at org.apache.pdfbox.pdmodel.graphics.shading.Type7ShadingPaint.createContext(Type7ShadingPaint.java:63) at sun.java2d.pipe.AlphaPaintPipe.startSequence(Unknown Source) at sun.java2d.pipe.AAShapePipe.renderTiles(Unknown Source) at sun.java2d.pipe.AAShapePipe.renderPath(Unknown Source) at sun.java2d.pipe.AAShapePipe.fill(Unknown Source) at sun.java2d.pipe.PixelToParallelogramConverter.fill(Unknown Source) at sun.java2d.pipe.ValidatePipe.fill(Unknown Source) at sun.java2d.SunGraphics2D.fill(Unknown Source) at org.apache.pdfbox.rendering.PageDrawer.shadingFill(PageDrawer.java:1388) at org.apache.pdfbox.contentstream.operator.graphics.ShadingFill.process(ShadingFill.java:42) at org.apache.pdfbox.contentstream.PDFStreamEngine.processOperator(PDFStreamEngine.java:932) at org.apache.pdfbox.contentstream.PDFStreamEngine.processStreamOperators(PDFStreamEngine.java:510) at org.apache.pdfbox.contentstream.PDFStreamEngine.processStream(PDFStreamEngine.java:484) at org.apache.pdfbox.contentstream.PDFStreamEngine.processPage(PDFStreamEngine.java:156) at org.apache.pdfbox.rendering.PageDrawer.drawPage(PageDrawer.java:271) at org.apache.pdfbox.rendering.PDFRenderer.renderImage(PDFRenderer.java:321) at org.apache.pdfbox.rendering.PDFRenderer.renderImage(PDFRenderer.java:243) at org.apache.pdfbox.rendering.PDFRenderer.renderImageWithDPI(PDFRenderer.java:229) at PdfToImage.main(PdfToImage.java:47)

Edit I found i I change

//Rendering an image from the PDF document
BufferedImage image = renderer.renderImageWithDPI(pageNumber, 96, ImageType.RGB);

to

//Rendering an image from the PDF document
BufferedImage image = renderer.renderImageWithDPI(pageNumber, 50, ImageType.RGB);

It works fine, no crash. But its not a solution, or a bad solution to lower resolution that much.

0 Answers
Related