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.
Related
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.
I have an application that need to show a very large image (from a png on disk) with only a small part of the image is visible on screen at any time. However the visible section can move quickly around the large image.
Loading the whole image into a BufferedImage at once is not a good idea as it can be 10 000 - 100 000 pixels wide, but the size on disk is not very large (a few MB perhaps) so it is a question of loading only the relevant sections to be displayed.
I've tried creating an ImageReader like this:
FileImageInputStream is = new FileImageInputStream(imageFile);
ImageReader imageReader = ImageIO.getImageReaders(is).next();
ImageReader.setInput(is, false, true);
ImageReadParam readParameters = imageReader.getDefaultReadParam();
And then a method for getting a subimage something like this:
private BufferedImage loadFrame(int x, int y, int w, int h) {
readParameters.setSourceRegion(new Rectangle(x,y,w,h));
try {
return imageReader.read(0, readParameters);
} catch (IOException ex) {
return null;
}
}
This works in principle, but it is far too slow. So when moving fast around the image it lags way too much.
I also tried splitting up the source image beforehand so I had a bunch of smaller images on disk that I then loaded as needed using ImageIO.read(getImageFile(x,y)) where getImageFile(x,y) would return the appropriate File for that location. This method was actually much faster and fully usable.
So I guess I have a way to make this work, but it just seems a bit awkward to do it this way. Besides needing some preparation of the source image, it also requires a lot of disk access (although I guess this is probably buffered somewhere).
So my question is: What would be the best way to do this? (And why is it faster to load an image from disk than to load a part of an image from an ImageReader?)
PNG is a compressed format, you can't just open the file and seek to a specific location to start reading the region (like you can with a bitmap ~after reading the file header of course). The whole PNG needs to be loaded (parsed/decompressed) before you can start extracting regions of it. (http://en.wikipedia.org/wiki/Portable_Network_Graphics#File_header)
If you want to sacrifice disk space to improved memory (RAM) usage and performance...
You can divide the image up and load only those grid chunks that you need to build the view for the user.
1x1.png, 1x2.png, 2x1.png, 2x2.png - if the user is looking at the top left corner you only need to load 1x1.png etc etc.
You can convert the image to a bitmap BMP the image will be much larger on the disk, but you'll be able to extract specific regions of it without having to process the whole file.
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
This is a bit of a followup to my last question: Canvas is drawing too slowly
Now that I can draw images more quickly, the problem I am faced with is that the actual loading of the images takes far too long.
In the app I am working on, the user is able to play back video frames (jpegs) in succession, as though he is viewing the video in realtime. I have been using BitmapFactory.decodeFile() to load each jpeg in a Bitmap. I'm unable to load all images at once since there are about 240 of them, and that would use up all of my heap space. What I have been doing is preloading up to 6 at a time into an array by way of a separate thread in order to cut down on the time it takes for each image to display.
Unfortunately, it takes somewhere between 50 and 90ms to load an image, and I need to show an image every 42ms. Is there a faster way to load images possibly?
For clarification, these images are in a folder on the SD card, and they are all 720x480 jpegs. I am sampling them at half that size to cut down on memory usage.
I ended up doing this quite a bit differently than I had originally envisioned. There was quite a bit to it, but here's the gist of how I achieved my goal:
All images are stored on SD card and written to one file (each image takes up X bytes in the file)
Use native code to read from and write to the image file
When requesting an image, I pass the index of the image in the list and a bitmap object (RGB_565) to the native code using a JNI wrapper
The native code locks the bitmap surface, writes pixel data (as a uint8_t**) directly to the bitmap, then unlocks it
The image is rendered to the screen
By doing it this way, I only needed to store one image in memory at a time, and I was able to bypass garbage collection (since the bitmap was only created once and then repopulated natively). I hope someone else might find this strategy useful.
Guess you already tried all methods in this tutorial http://www.higherpass.com/Android/Tutorials/Working-With-Images-In-Android/2/ and chosen the fastest. Maybe tweaking resizing can decrease loading time.
Best of all would of course be if you didn't have to resize the images at all. If you have full control of the images maybe you could try to pack them as sprites, see article http://www.droidnova.com/2d-sprite-animation-in-android,471.html