Effective Image Resizing (Scaling)
Hi all!
I have been using the ImageIcon and Image classes to scale images by the help of the Image.getScaledInstance(...) method. This is all good for most cases but there is a bit of hitch.
When I use this technique for more than say 100 images, I begin to get slower performance and loss of memory. Sometimes I even get an OutOfMemoryException.
I believe I do my best to set the used classes to null after they have been used but that does not seem to ease the problem. I need to be able create a multiple image presentation (sort of like the thumbnail view in windows).
Could anyone point me to some example that does thiseffectively or some little work around for this problem. See example code (not guaranteed to compile. Code written on the fly)
final File[] images = imageDir.listFiles();
final JPanel imagePanel =new JPanel(new GridLayout(0,3,20,20) );
final Timer timer =new Timer(500,new ActionListener(){
int row = 0;
publicvoid actionPerformed(ActionEvent e){
ImageIcon icon =new ImageIcon( images[row++].getAbsolutePath() );
icon =new ImageIcon(icon.getImage().getScaledInstance(80,80, Image.SCALE_DEFAULT));
imagePanel.add(new JLabel(icon) );
if(row > images.length){
timer.stop();
}
}
});
timer.start();
Hope some sort of solution can be obtained.
ICE
The Java Advanced Imaging API may represent a better way of loading images than using java.awt.Toolkit (as used by ImageIcon) as Toolkit is expected to cache images and may therefore not give sufficient control over the loading process for this type of application. Toolkit.createImage may also be suitable...
My main concern with the code you've posted, however, is that imagePanel will build up hundreds of labels in it. This is exactly the sort of situation renderers were designed to deal with. A table, list or even a custom component using a CellRendererPane should provide a much better use of resources.
Do some profiling - does the problem remain if you simply add the image icons to a List rather than creating labels and adding these to a panel? What if you use Toolkit.getDefaultToolkit().createImage().getScaledInstance() to load the images?
Hope this helps.
Hi again, thanks 4 the reply.
Sorry if u were misled by the above code but I believe I actually tested the feature using a JList instead of a panel. However, it is very good to know that using a JPanel and JLabels could be a problem.
I'll get to work using a Toolkit createImage(..) method instead of the ImageIcon and see how best that solves the problem.
I was just wondering, are thumbnails stored in JPEGs? (I think I saw that somewhere) if not never mind. Also, could the fact that I'm scaling images of dimensions "800 x 600" and "1024 x 760" be a factor, in that the system might require more resources to scale such "large" images and hence I would not really matter whether JLabels or a CellRenderer system is used?
ICE
I don't know about JPEGs storing thumbnails... I don't think they do. Some paint applications and Windows explorer store thumbnail files in directories.
Loading large images will definitely require a lot of resources. However, these should be reclaimed automatically once the image has been finished with (ie, once you've only got a scaled version of it left in memory).
You can still use ImageIcon by passing it the Image directly:
Image image = Toolkit.getDefaultToolkit().createImage(url);
if(image == null) {
continue;
}
image = image.getScaledInstance(80, 80, Image.SCALE_SMOOTH);
Icon icon = new ImageIcon(image);
// add to list model
Hope this helps.
I doubt it'll be all that useful...
If you go to your folder options in Windows and ensure "Do not cache thumbnails" is not selected as well as unselect "Hide protected operating system files" you'll see a file called Thumbs.db which (presumably) contains the thumbnails. It's just a cache of the thumbnail previews for a folder that's been viewed using the "thumbnail" view.
I think you might be able to read it using Jakarta's POI but I don't have the faintest idea how!
Hope this helps.
Ah yes. I know about that darn file. Never really seen its use.
But the idea is what I like. Cos instead scaling all the images everytime they are accessed, I could store scaled versions in a temporary location and update these only when necessary. Hence, I can load the display faster by checking see if thumbnails exist in the temp folder and load those instead of the original images.
I love these forums. Hey tell me if this is a good enough strategy cos it means I might be taking up extra storage if this method is used. Some users might not like that. (Then I think a cache option should be made available right?)
ICE
If you've got a serious requirement for thumbnails then caching them would seem to be a sensible approach.
You've got to ensure that you come up with a suitable structure, however. Apart from the image data it will also need to store the file modification date so that it can detect changes to the file and refresh.
Your cache data format should probably also support incremental loading so that it can show thumbnails as it loads them.
Personally, I'd abstract the thumbnail functionality so that your application doesn't know whether they're loading directly from the image data or from a cache file. Then you can add the caching code later if you need to.
Hope this helps.