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:))
Related
I'm making a texture streaming system for my game. I've successfully built it - but it has one problem. For the first frame after it's made, the width/height is 1 because it has begun being read yet by the streamer. I'm trying to think of a way I can possibly "peek" into the image's file and get the dimensions without actually loading the whole thing at once.
I have a few limitations here: we don't use AWT and can't access it. Due to how our threads are set up (due to making it compatible with MacOS), if we try and access AWT, it'll crash the program on Mac Systems. So I can't use any of those tools (BufferedImage, etc). I've never accessed ImageIO before either, but I'm quite sure if it'd cause a crash just because it has a function that returns BufferedImages.
What I have access to is the file location itself. The first thing that comes to mind is checking the image metadata, and at the very least using that as a placeholder. When I've checked online, it appears that the only native to Java method is using ImageIO, but as I said above, I think that could cause crashes due to it referencing AWT classes for stuff like ImageIO read.
So, to summarize: I'm streaming a texture, but I need a way to check the image for its dimensions (without actually loading the entire image) so that I know the dimensions immediately/as soon as the streaming is set up.
Thank you!
Edit*
I also forgot to mention, we use Java-bindings for STB-Image for our texture loading/saving/etc needs. If it has a way to access metadata, please let me know!
I figured it out. Keep in mind that I'm using STBImage on the LWJGL bindings, but:
try (MemoryStack stack = MemoryStack.stackPush()) {
IntBuffer w = stack.mallocInt(1);
IntBuffer h = stack.mallocInt(1);
IntBuffer c = stack.mallocInt(1);
STBImage.stbi_info(imageFile.getAbsolutePath(), w, h, c);
return new Vector2i(w.get(), h.get());
}
This will check the given file's image dimensions without actually fully loading it. It outputs a Vector2i containing the dimensions.
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.
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
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.
Has anybody managed to convince ImageIO to write an animated GIF, and in particular setting the correct metadata? My first attempt is roughly as follows (where b1 and b2 are BufferedImages):
ImageTypeSpecifier spec = new ImageTypeSpecifier(b1);
ImageWriter wr = ImageIO.getImageWriters(spec, "GIF").next();
wr.setOutput(ImageIO.createImageOutputStream(new File("C:\\Flashing.gif")));
ImageWriteParam param = wr.getDefaultWriteParam();
IIOMetadata meta = wr.getDefaultImageMetadata(spec, param);
wr.prepareWriteSequence(meta);
wr.writeToSequence(new IIOImage(b1, null, null), param);
wr.writeToSequence(new IIOImage(b2, null, null), param);
This appears to almost work, but:
I clearly need to somehow set "proper" metadata to set the time between the images and ideally make them loop (I was naively hoping the default would do something sensible, but hey...)
whatever metadata it is writing by default is obviously not quite right: the GIMP gives a couple of error messages when loading the file, although embedding the image in a test web page in Firefox does display the two images in very quick succession, which is tantilisingly close to what I want...
If anyone has got writing animated GIFs from ImageIO to work and can share a snippet of working code or how to fix the above problems, it would be greatly appreciated!
I ran across this question, and decided to try it out; It took a small but non-trivial amount create a usable class (thanks ax) -- so I thought I might share the code around: here is a small class for creating an animated gif image from a number of other images. Archived version