Search code examples
javaimagememory-managementbufferedimagegraphics2d

javafx memory consuption hints for resizing images


I have a simple javafx application which batch manipulating with images (just resizing yet :)) It's a simple javafx form with source directory textField, destination directory textField and desired dimensions. After start of this application, simple form without any action consump aroud 65MB of memory... After start batch processing memory consuption jump to 250 MB and then raising and raising. After 700 images my application consump around 1,35GB of memory (pictures have around 3500x2600px and it's resized to 1920x1080). If I call gc() after each image, memory is around 300 - 350 MB. But do you have some hints to smaller memory requirements of javafx app or 350 MB is OK because Java is virtual machine. Thanks for hints. I programmed simillar application in C# around few years ago and it's consump around 60 MB of memory :) It's so big different :( But I like Java and multi-platform Appliation. And of course, I opening image in second Thread via ImageIO.read(), then converting to BufferedImage() and then I create new BufferedImage() with smaller dimesnions and draw original BufferedImage() to new - smaller image via Graphics2D()

BufferedImage resizedImage = new BufferedImage(IMG_WIDTH, IMG_HEIGHT, type);
Graphics2D g = resizedImage.createGraphics();
g.drawImage(originalImage, 0, 0, IMG_WIDTH, IMG_HEIGHT, null);
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,RenderingHints.VALUE_INTERPOLATION_BICUBIC);
g.setRenderingHint(RenderingHints.KEY_RENDERING,RenderingHints.VALUE_RENDER_QUALITY);
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
g.dispose();

And finally

ImageIO.write(backgroundThread.resize(1920, 1080), "jpg", new File(destinationPath +      f.getFileName()));

Thanks for help


Solution

  • Use the JavaFX Image constructor to create and resize your images, rather than using BufferedImage and ImageIO.

    Memory consumption should improve as:

    1. There are less format conversions happening, so intermediate formats don't need to be stored.
    2. When the JavaFX Image constructor is utilized, the JavaFX javadoc specifies:

      Images can be resized as they are loaded (for example to reduce the amount of memory consumed by the image)


    Answers to additional questions

    how I can save it on disk?

    Saving images to disk using JavaFX is currently (as of the initial Java 8 release), an open, unresolved feature request: RT-18886 Implement Image writers for JavaFX.

    Until RT-18886 is implemented, you will need to convert the image to a BufferedImage before you save it, in order to use ImageIO for saving images to formats like jpg. You can use SwingFXUtils to do this. It is still efficient to resize the image up front when you first load it into memory, which is how the JavaFX Image constructor works.

    I must also create a new Buffered Image and then draw it inside with Graphics2D.

    You can load your image as a JavaFX image then paint it on a JavaFX Canvas, using JavaFX GraphicsContext, then snapshot the canvas to get a new Image that you can convert to an BufferedImage and save using ImageIO. OK, so perhaps not the most efficient process, but it does allow you to stick with (mainly) a single framework and API and avoid some potential threading issues.

    I using SwingFXUtils.fromFXImage(im, null) but I have a strange filter on the pictures then

    I don't know exactly what "strange filter" means, but perhaps you are seeing RT-14647 Incorrect display of JPEG images, which was fixed in a past JavaFX update. Try running against the latest Java 8 development release and see if you still get the same issue. If not, you can create a new question with an mcve.


    Alternatives

    There is almost certainly an equivalent way of saving resized images efficiently using only BufferedImage, ImageIO and the awt/swing framework, but I am not familiar enough with that API to comment on how that might be done and I am not a fan of mixing Swing, AWT and JavaFX unless you really need to.