1

I need to read and write to images pixel by pixel (I was generating Fractals). As I experimented with Image sizes, I realized that writing to an Image using BufferedImage when the image size is huge (say 24000x18000), led to an OutOfMemoryError. To tackle that, I used -Xmx -Xms to increase the heap size.

Is there a way to write to an image pixel wise without having to load the entire image in the memory? Same goes for reading (and modifying) large images.

EDIT

I'm doing it pixel by pixel, left-to-right, top-to-bottom.

Community
  • 1
  • 1
Abdul Fatir
  • 6,159
  • 5
  • 31
  • 58
  • 2
    Are you _generating_ the image pixel by pixel, left-to-right, top-to-bottom? If so you might be able to arrange to write it serially. However, if you need to generate the image completely before writing it you will have to store it in memory first. Your question is not clear... – Jim Garrison May 30 '16 at 05:25
  • @JimGarrison Yes, I'm doing it pixel by pixel, left-to-right, top-to-bottom. Could you please answer how to do it serially? – Abdul Fatir May 30 '16 at 05:27
  • 1
    You will likely have to bypass the standard image code and write the image format directly. This will probably be quite a bit of work, and is outside my expertise. Maybe somebody else will answer. Rather than tacking on an an edit, I suggest you rewrite the question to more clearly explain exactly what you're doing. – Jim Garrison May 30 '16 at 05:29
  • Take a look at: http://stackoverflow.com/questions/18466513/read-region-from-very-large-image-file-in-java – Michael Markidis May 30 '16 at 05:33

2 Answers2

4

The easiest solution is usually just to add more memory. :-)

However, there are some options (I don't find enough information in your question to decide which one is the best, consider updating it):

  • Write a minimal format header (BMP is quite easy, TIFF is also doable) for your image, allocate the disk space needed for your image in that format, and memory map that region. This will be similar to working with virtual memory. The system will copy areas of the file into memory at a time, so you should work on limited regions at a time to avoid too much swapping.

  • I've written some classes to allow using such a file as a (quite slow) BufferedImage, MappedImageFactory and MappedFileBuffer. These can either be combined with the above, to have a "live" updating file, or use the more familiar ImageIO API to read/write huge files (special code needed to read into such image, see MappedImageFactory.createCompatibleMappedImage(w, h, type) and ImageReadParam.setDestination(image)).

  • Use the ImageIO API to read and write tiles (fixed sized regions). The only image format I know of that natively supports tiles, is TIFF. I think the TIFFImageReader and TIFFImageWriter from ja_imageio.jar will support tiling. There is also support in the RenderedImage API for tiling. Tiling could probably also be combined with the memory mapping technique, for better performance (i.e. copy tiles to normal BufferedImage for faster Java2D operations).

  • Use the ImageIO API to read and write arbitrary subregions. Reading a region is easy, using ImageReadParam.setSourceRegion(...). The ImageWriter.canReplacePixels() method will tell you if the writer supports writing regions. Unfortunately, I don't know of any ImageWriter implementation that currently supports this, but in theory it should be quite easy for any uncompressed format, if you want to implement it yourself.

This list is probably not exhaustive.

Harald K
  • 26,314
  • 7
  • 65
  • 111
  • Thank you for your answer. It's a pretty detailed one. I'll wait for some time and will mark this as the answer if I don't get a better one. – Abdul Fatir May 30 '16 at 10:03
1

I agree with the solutions proposed by haraldK. 18Kx24K can easily be load into the memory.

But as you go pixel by pixel, you can also use a BigBufferedImage that was presented into this post. The image is not loaded into the memory, but stored into a file.

Community
  • 1
  • 1
FiReTiTi
  • 5,597
  • 12
  • 30
  • 58