I have 13255 images, each 240 x 240 pixels wide, the biggest 15,412 bytes in size and the smallest 839 bytes.
I am trying to loop through the folder adding each of them to a File[]. Once I have an array of each image I am then placing them inside a BufferedImage[] ready to be looped through and drawn onto a larger single image made up of each individual one.
Each image is named in the form of
Image x-y.png
However, I keep ending up with a java.lang.OutOfMemoryError: Java heap space error. I have no idea why. I have tried altering the size of the memory available to the JVM by adding parameters to the end of the target for Eclipse. Below is what I have used:
IDE's\eclipse-jee-juno-SR2-win32-x86_64\eclipse\eclipse.exe -vmargs -Xms64m -Xmx1024m
and
IDE's\eclipse-jee-juno-SR2-win32-x86_64\eclipse\eclipse.exe -vmargs -Xms64m -Xmx4096m
Both have no effect. I have also gone into Control Panel -> Programs -> Java and changed the amount of memory available there.
Here is the method that I have written :
public static void merge_images() throws IOException {
int rows = 115;
int cols = 115;
int chunks = rows * cols;
System.out.println(chunks);
int chunkWidth, chunkHeight;
int type;
// fetching image files
File[] imgFiles = new File[chunks];
int count = 0;
for (int j = 1; j <= 115; j++) {
for (int k = 1; k <= 115; k++) {
imgFiles[count] = new File("G:\\Images\\Image " + j
+ "-" + k + ".png");
count++;
}
}
System.out.println(imgFiles.length);
// creating a buffered image array from image files
BufferedImage[] buffImages = new BufferedImage[chunks];
for (int i = 0; i < chunks; i++) {
buffImages[i] = ImageIO.read(imgFiles[i]);
System.out.println(i);
}
type = buffImages[0].getType();
chunkWidth = buffImages[0].getWidth();
chunkHeight = buffImages[0].getHeight();
// Initializing the final image
BufferedImage finalImg = new BufferedImage(chunkWidth * cols,
chunkHeight * rows, type);
int num = 0;
for (int i = 0; i < rows; i++) {
for (int k = 0; k < cols; k++) {
finalImg.createGraphics().drawImage(buffImages[num], null,
chunkWidth * k, chunkHeight * i);
num++;
}
}
System.out.println("Image concatenated.....");
ImageIO.write(finalImg, "png", new File("fusions.png"));
System.out.println("Image Saved, Exiting");
}
At the print line here
for (int i = 0; i < chunks; i++) {
buffImages[i] = ImageIO.read(imgFiles[i]);
System.out.println(i);
}
it always stops at around the 7320 point.
Here is the exact console print out
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.awt.image.DataBufferByte.<init>(Unknown Source)
at java.awt.image.ComponentSampleModel.createDataBuffer(Unknown Source)
at java.awt.image.Raster.createWritableRaster(Unknown Source)
at javax.imageio.ImageTypeSpecifier.createBufferedImage(Unknown Source)
at javax.imageio.ImageReader.getDestination(Unknown Source)
at com.sun.imageio.plugins.png.PNGImageReader.readImage(Unknown Source)
at com.sun.imageio.plugins.png.PNGImageReader.read(Unknown Source)
at javax.imageio.ImageIO.read(Unknown Source)
at javax.imageio.ImageIO.read(Unknown Source)
at main.merge_images(main.java:48)
at main.main(main.java:19)
Any ideas where I am going wrong would be greatly appreciated.
Regards,
Jamie
Look like everyone is offering a simpler and less resource consuming solution. Let me try mine:
Try to run JVM with -Xmx1024m or the same with greater values. This value is the Heap size.
Also, you can increase this value in your IDE.
You need to increase the maximum memory for your program, not the maximum of eclipse which doesn't need more memory I assume.
There is an option in eclipse for changing the VM arguments (I don't know that it is as I haven't used it for many years)
All the same you need to be able to load all the images uncompressed. This means you need at least 13225 * 240 * 240 * 4 bytes. This is just over 3 GB. If you load all the images first, you need at least double this. I suggest you make the heap at least 4 - 8 GB.
As was pointed out by hoaz (Many thanks) I was taking too many steps than were necessary. My solution is as follows:
Essentially what I have done is remove the BufferedImage[] and instead created a new BufferedImage during the nested for loop when I am building up the final image. Rather than using variables I have hard coded the bounds of the images and type of each image.
Thanks for pointing me in the right direction hoaz.
Regards
Jamie
You don't need to keep all your chunk images in memory. You can read them one by one and draw to your final image in final loop like this:
This will save at least half of the memory.