-
Trouble Displaying Image
This code was used to display images on a click of a button.... It works fine for small size images but when i import a image of about 2-3MB (JPEG pic taken from Nikon D40) it doesnt work..... It gives a heap space error...
Exception in thread "AWT-EventQueue-0" java.lang.OutOfMemoryError: Java heap space
Please help me to overcome this problem.....
Thank you in advance..........
Code:
try{
File tmpImage;
BufferedImage img1, img2, img3;
JFileChooser chooser = new JFileChooser();
ImagePreviewPanel preview = new ImagePreviewPanel();
chooser.setAccessory(preview);
chooser.addPropertyChangeListener(preview);
chooser.setMultiSelectionEnabled(false);
int option = chooser.showOpenDialog(this);
if (option == JFileChooser.APPROVE_OPTION) {
tmpImage = chooser.getSelectedFile();
}
BufferedImage img = ImageIO.read(tmpImage);
img1 = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_RGB);
img1.getGraphics().drawImage(img, 0, 0, null);
pic1.setIcon(new ImageIcon(zoomOut(img1,8)));
pic1.setText("");
}
catch(Exception e){
e.printStackTrace();
}
-
What is your heap size limit on your JVM ?
It should be 128m by default, but who knows what are your actual settings...
-
When I get the OutOfMemoryError the stack trace begins with:
Code:
Exception in thread "AWT-EventQueue-0" java.lang.OutOfMemoryError: Java heap space
at java.awt.image.DataBufferInt.<init>(Unknown Source)
at java.awt.image.Raster.createPackedRaster(Unknown Source)
at java.awt.image.DirectColorModel.createCompatibleWritableRaster(Unknown Source)
at java.awt.image.BufferedImage.<init>(Unknown Source)
at Test.copy(test.java:48)
at Test.openDialog(test.java:26)
The copy operation seems to be the problem area.
Copying the image seems to be a problem if the last loaded and next-to-load image file sizes total near 5 MB.
If I eliminate the copy operation and work with the loaded image it seems to work okay (see code below).
For more on diagnosing the OutOfMemoryError see B.1.2 in B.1 HotSpot VM Command-Line Options.
Code:
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.*;
import javax.swing.*;
import javax.imageio.ImageIO;
public class Test {
String folderPath = your_image_folder_path
JFileChooser fileChooser = new JFileChooser(folderPath);
JLabel label;
private void openDialog() {
if(fileChooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
File file = fileChooser.getSelectedFile();
System.out.printf("file name: %s size: %.2f MB%n",
file.getName(), getFileSize(file));
BufferedImage image = null;
try {
image = ImageIO.read(file);
} catch(IOException e) {
System.out.println("Read error: " + e.getMessage());
}
ImageIcon icon = //new ImageIcon(copy(image)); // trouble
new ImageIcon(scale(image, 8)); // okay
label.setIcon(icon);
}
}
private BufferedImage copy(BufferedImage src) {
int w = src.getWidth();
int h = src.getHeight();
int type = BufferedImage.TYPE_INT_RGB;
BufferedImage dst = new BufferedImage(w, h, type);
Graphics2D g2 = dst.createGraphics();
g2.drawImage(src, 0, 0, null);
g2.dispose();
return dst;
}
private BufferedImage scale(BufferedImage src, double scale) {
int w = (int)(src.getWidth()/scale);
int h = (int)(src.getHeight()/scale);
int type = BufferedImage.TYPE_INT_RGB;
BufferedImage dst = new BufferedImage(w, h, type);
Graphics2D g2 = dst.createGraphics();
g2.drawImage(src, 0, 0, w, h, null);
g2.dispose();
return dst;
}
private double getFileSize(File file) {
long size = file.length();
return (size/1024.0)/1024;
}
private JScrollPane getCenter() {
label = new JLabel((ImageIcon)null, JLabel.CENTER);
JScrollPane scrollPane = new JScrollPane(label);
scrollPane.setPreferredSize(new Dimension(500,500));
return scrollPane;
}
private JPanel getUIPanel() {
JButton button = new JButton("open");
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
openDialog();
}
});
JPanel panel = new JPanel();
panel.add(button);
return panel;
}
public static void main(String[] args) throws IOException {
Test test = new Test();
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(test.getCenter());
f.add(test.getUIPanel(), "Last");
f.pack();
f.setLocation(25,25);
f.setVisible(true);
}
}
-
Forget about the size on disk in MB. How big is the actual graphic, width and height, and what type is it?
That'll give you an idea of how large, in memory, it's going to be.
I notice that you're both using INT_RGB. What happens if, for example, you use 3BYTE_BGR?
The scale probably (in fact undoubtedly) works because the second image is far smaller on a scale() than on a copy().
My suggestion would be to figure out the "standard" size you want (width x height) for your icon. Scale anything larger than that. Otherwise copy.
Do the reading and scaling/copying in a separate method to the assigning to the icon, to give the garbage collector a chance to try and clear up the original image.
eg:
Code:
public void openDialog() {
BufferedImage image = getResizedImage(/*String or File for image we want*/);
ImageIcon icon = new ImageIcon(image);
}
private BufferedImage getResizedImage(/*String or File or whatever*/) {
// Read in the image off the disk.
// Is it too big?
// Then scale and return the scaled image.
// Else copy, and return the copy.
}
When the code exits getResizedImage() then the original, possibly big, image is eligible for garbage collection. However, because we've defined how big the icon image should be, I would hope that in itself would help against the OOM error.
Of course, you could always increase the JVM memory...