I'm developping a simple image organizer in java to sort quickly hundred of photos taken with my camera. The program has a list of photos(file paths) and displays a given photo
When I want to display one of them, it takes more than a second to load the file (~ 10Mb).
In this case, the sorting isn't efficient.
FXML private ImageView preview;
....
private void showMedia(Media m) {
if(m != null) {
Image i = new Image(new File(m.getPath()).toURI().toString());
m.loadMediaProperties();
this.preview.setImage(i);
}
else
this.preview.setImage(null);
}
The constructor of Image class consumes time to loading the given file. I tried to keep the instance of Image for each Media but it I get "java.lang.OutOfMemoryError: Java heap space"
I'm looking for a way to load and display a photo almost instantaneous (like adobe lightroom if you know).
Your goal cannot be achieved by such a simple, brute force approach as you are trying and Adobe Lightroom also does not work that way. Lightroom maintains a database of thumbnails and preview images and uses a lot of caching in order to give you a good performance and you would have to do the same in your application if you want to achieve a similar result. Utitizing background loading and processing is also key to a good performance here.
Related
Is there a way to load the images that will come on the screen soon as opposed to loading the images that are currently in view?
If you're asking how to pre-load images so they are freshly cached, so that when the corresponding ImageView comes on screen the loading is nice and fast, you could use (somewhat untested):
String uri = getUriOfImageAboutToComeOnScreen(...);
ImageLoader.getInstance().loadImage(uri, null /* or use a listener */);
Of course, the magic contained in getUriOfImageAboutToComeOnScreen() is up to you :)
My application is basically a photo browser. My approach (don't judge me, I am new to java) was to have an ArrayList filled with BufferedImages and then add the images to the JList(to the left).
This is how I get an image :
private void getFullImage() {
BufferedImage im = null;
ImageReader imageReader = null;
try {
System.out.println("Loading "+original+"...");
String suffix = Utils.getFileExt(original.getName(), "jpg");
#SuppressWarnings("rawtypes")
Iterator readers = ImageIO.getImageReadersBySuffix(suffix);
imageReader = (ImageReader)readers.next();
imageReader.setInput(new FileImageInputStream(original));
im = imageReader.read(0);
imageReader.dispose();
} catch (Exception e)
{
e.printStackTrace();
}
this.img = im;
}
and then, after I fetched all the data, I would add the images to my JList :
Vector vector = new Vector();
JPanel container = null;
PhotoPanel pp = null;
Photo p = null;
for(int i=0;i<files.length;i++)
{
p = new Photo(files[i]);
pp = new PhotoPanel(p);
container = new JPanel(new BorderLayout());
container.add(pp,BorderLayout.CENTER);
container.setBorder(BorderFactory.createTitledBorder(p.getTitle()));
vector.addElement(container);
}
plist.setListData(vector);
If I have for example 10 files, the app works pretty well. The problem is when I have a lot more images to show. Then I would get an exception : Exception in thread "AWT-EventQueue-0" java.lang.OutOfMemoryError: Java heap space. So, I know my approach is a very poor one, and I am wondering how should I take and store all the images and have them to be displayed in the JList. Maybe using the cache memory? I read something about SoftReference but I don't really know how to use it. Thanks.
There are two main possible causes for the problem:
The first, and which I'm posting more as a warning than as an actual cause in your case, is that an excessive amount of data is being printed on the console with the System.out.println().
I am unsure if it only occurs with NetBeans or all Development tools. But either way, it requires a truly absurd amount of printing for it to be triggered, and i doubt you have that many files loading.
Anyways, if your intent with the System.out.println("Loading "+original+"..."); line is for a permanent/production logging, rather than something you've put on code just temporarily for development/debug purposes, then you are better off with a proper Logger. You can read a TL;DR version of instructions in this SO answer, and you can read further, including the official documentation, through the links provided there.
The other cause, which is quite certainly your's, is that you are having too much data loaded at the same time. The solutions are to either:
Scale down the images (make thumbnails), and only show the full-size version for the selected image. Please note tough, that this is a fast solution method, and is not recommended! As it might still be too much for the system to withstand.
Only have the images present at visible portion of the interface loaded (or the thumbnails of said images, for a combined, best solution), and load new images (and unload the others), as the interface is navigated.
I was struggling a lot with large images (in SWT though) and those OutOfMemory and NoMoreHandles (which might happen even, if there is not enough memory) were a nightmare. I think there is no way, to keep large images or have a lot of images in memory. I agree with Andrew's comment, but just wanted to add, that depending on your requirements you could try to extend a canvas (or whatever there is in Swing) and DRAW your images directly on it, without holding those in memory (similar for PaperClips#PrintPreview). Sure, you will need to have some calculations to layout images correctly, but I think, that in this case you might overcome your problems with memory (but get some other problems:))
In my eclipse-rcp application I need to create an image with dimensions 30000x10000 px or more. This image is NatTable representation. Using standard image creation approach, it fails with different problems: OutOfMemory, SWTError - IllegalArgument or my PC stops responding (btw, its windows 7, 64bit, 4 RAM - client have much slower laptops, but the picture is still needs to be created). Here is a code snippet:
private Image getNattableImageRepresentation(final Display display) {
final Rectangle totalGridArea = getTotalGridArea(); //this returns Rectangle(0,0,30000,10000)
setGridLayerSize(totalGridArea);
final Image nattableImage = new Image(display, totalGridArea);
final GC nattableGC = new GC(nattableImage);
gridLayer.getLayerPainter().paintLayer(gridLayer, nattableGC, 0, 0, totalGridArea, configRegistry);//nattable API, which draws an image into a specified gc
restoreGridLayerState();
return nattableImage;
}
return null;
}
Are there any tricks to create such huge images or may be API? Is Java Advanced Imaging Api suitable for this purpose?
Any suggestions are appreciated.
ImageMagick is neat tool for image processing like this.. new CG is not the way, definitely.. If you'll join all spare images to the big one, there should be no problem at all..
There is a simple solution for storing larger images in Java. BigBufferedImage stores the image on the hard drive in a very fast way:
https://stackoverflow.com/a/53205617/2631710
I develop an application in which I want to display a grid with a list of images. For each image I create an instance of a class myImage. MyImage class, extends JCompoment and create an thumbnail and after draw it with overide thepaintCompoment(Graphics g).
All is ok, but in big size images I have a lot of delay to create the thumbnail.
Now I think to when I scan the folders for image(to create the list I said above to create an thumbanail of each image and save it to disc. For each image I will have a database record to save the image path and thumbnail path.So is this a good solution of the problem?
Is there a way to get the thumbnails of the system creates for each image, in file manager. Or a more effective solution than I try.
Thank you!!
Your best bet is to use something like imagemagick to convert the image and create the thumbnail. There's a project called JMagick which provides JNI hooks into Imagemagick, but running a process work too.
Imagemagick is heavily optimized C code for manipulating images. It will also be able to handle images that Java won't and with much less memory usage.
I work for a website where we let users upload art and create thumbnails on the fly, and it absolutely needs to be fast, so that's what we use.
The following is Groovy code, but it can modified to Java code pretty easily:
public boolean createThumbnail(InputStream input, OutputStream output){
def cmd = "convert -colorspace RGB -auto-orient -thumbnail 125x125 -[0] jpg:-"
Process p = cmd.execute()
p.consumeProcessErrorStream(System.out)
p.consumeProcessOutputStream(output)
p.out << input
p.out.close()
p.waitForOrKill(8000)
return p.exitValue()==0
}
This creates a thumbnail using pipes without actually writing any data to disk. The outputStream can be to a file if you wanted to immediately write it as well.
One way to avoid OS dependance is to use getScaledInstance(), as shown in this example. See the cited articles for certain limitations. If it's taking too long, use a SwingWorker to do the load and scale in the background.
I haven't used it for the creation of thumbnails, but you may also want to take a look at the ImageIO API.
ImageIO
Hi I have an application that loads all the images of a folder in a canvas, vertically. Like thumbnails. These folders have usually more than 20 images, around 1mb sometimes even 2.
I created a class called Index, that extend canvas.
I managed to load all the images and resize them to the proper size (the original size is around 1280x1985, yeah they are quit big. But it takes too long, and I think I know why but I dont know how fix it or do it better.
public void loadImages(){
System.out.println("Loading Images");
List<String> imageList = new ArrayList<String>();
imageList = listDirImages(this.strDir);
int listSize=imageList.size();
for(int i=0;i<listSize;i++){
System.out.println(imageList.get(i));
Image sourceImage;
System.out.println(strDir.concat("/".concat(imageList.get(i))));
try {
sourceImage = new Image(getDisplay(),strDir.concat("/".concat(imageList.get(i))));
//sourceImage[i] = new Image(getDisplay(),strDir.concat("/".concat(lsImagenes.get(i))));
}catch(Exception e){
System.out.println(e);
//band=1;
}
}
}
This function uses the directory, then it calls to a function to list all the images. It lists all the images.
The original code was different but i tried to eliminate the code to see where it is taking so long. Original sourceImage was an array of images (I dont know if that is better), and I resized the images creating new ones, but it took longer to create them.
with 25 images it takes almost 45 seconds to load this part, I know the problem is that i am loading the full image, and they are quite heavy. Is there a way to load them directly to a thumbnail?
Some folders have around 80 pages, that is like 2 minutes. (For one part I think i have to this as thread, so the whole program could run other things while it is loading the index.
You need thumbnails to be pre-build on the server and just load them with the javascript. Even if there is a way to load images directly in thumbnails the client will still download the full size image to create the thumbnail and this is not good for the network bandwidth.