How do I load an enormous image to Java via BufferedImage? - java

I want to load large images (18000 x 18000) to my application. If i use BufferedImage with type int_rgb, I need around 1235mb of heap memory to load. This is a very high amount of memory, and end users will likely have less ram (1GB or less).
On my development PC, when I load the image from MyEclipse IDE, it throws an out of memory Exception. When i pack my code to an executable jar and run it on my PC external of Eclipse, it still throws an exception.
How do I load such a large image into my application using buffered image without using 1235mb of memory? Is there a trick, like splitting the image into smaller portions like image segmentation?
I found this thread on SO, but it not useful for me; I want to load the image into BufferedImage and then draw it on a Panel using the Graphics class.

You can read and display fragments of the image using ImageReadParam from ImageIO package. Here is a basic example that illustrates how to read a single fragment using ImageReadParam without reading the whole image:
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import javax.swing.*;
public class TestImageChunks {
private static void createAndShowUI() {
try {
URL url = new URL(
"http://duke.kenai.com/wave/.Midsize/Wave.png.png");
Image chunk = readFragment(url.openStream(), new Rectangle(150,
150, 300, 250));
JOptionPane.showMessageDialog(null, new ImageIcon(chunk), "Duke",
JOptionPane.INFORMATION_MESSAGE);
} catch (IOException e) {
JOptionPane.showMessageDialog(null, e.getMessage(), "Failure",
JOptionPane.ERROR_MESSAGE);
e.printStackTrace();
}
}
public static BufferedImage readFragment(InputStream stream, Rectangle rect)
throws IOException {
ImageInputStream imageStream = ImageIO.createImageInputStream(stream);
ImageReader reader = ImageIO.getImageReaders(imageStream).next();
ImageReadParam param = reader.getDefaultReadParam();
param.setSourceRegion(rect);
reader.setInput(imageStream, true, true);
BufferedImage image = reader.read(0, param);
reader.dispose();
imageStream.close();
return image;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}
The result looks like this:

Generally, you'd need to do something like this:
Break the image into manageable size image files and store them on disk with your application.
When displaying a particular part of this image, only the load and display image fragments that overlap your viewport.
As you pan around the image, update the loaded and displayed image fragments appropriately.
Either let the unnecessary image fragments get collected by the GC or load new ones in such a way that they overwrite older ones. (This last argues for identically-sized image fragments that load into pooled memory buffers.)

Related

Java ImageIO, Can't read input file

Some years ago I took a couple of courses in programming. Now I'm in a situation where some very basic image processing might save me loads of time. Unfortunately I'm a bit stuck trying to read an image. I haven't done this before and basically just copied some code I found, but I get "javax.imageio.IIOException: Can't read input file!". I've tried moving the image "Test.jpg" and change the path. I don't understand what is causing the issue. I use macOS, not sure if this is relevant.
import java.io.File;
import java.io.IOException;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
public class MyImage{
public static void main(String args[])throws IOException{
BufferedImage image = null;
File f = null;
try {
f = new File("Users/simonprobert/eclipse-workspace/LineLengthCounter/src/Test.jpg");
image = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB);
image = ImageIO.read(f);
System.out.println("Reading complete.");
} catch(IOException e){
System.out.println("Error: "+e);
}
}
}
(Currently I'm just trying to read the image, the rest is not important at this point)

Java robot class doesn't work after being exported [Solved][Reason: Window scaling ]

So I have a class that utilizes java's robot class to take a screen picture and make 5 smaller pictures from it.
import java.awt.AWTException;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ArrayList;
public class screencap {
static Rectangle rectangle = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
public ArrayList<BufferedImage> get() throws AWTException, IOException {
ArrayList<BufferedImage> array = new ArrayList<BufferedImage>();
Robot robot = new Robot();
BufferedImage bufferedImage = robot.createScreenCapture(rectangle);
BufferedImage img1 = bufferedImage.getSubimage(481,1039,190,31);
BufferedImage img2 = bufferedImage.getSubimage(682,1039,190,31);
BufferedImage img3 = bufferedImage.getSubimage(883,1039,190,31);
BufferedImage img4 = bufferedImage.getSubimage(1085,1039,190,31);
BufferedImage img5 = bufferedImage.getSubimage(1286,1039,190,31);
array.add(img1);
array.add(img2);
array.add(img3);
array.add(img4);
array.add(img5);
return array;
}
}
So what I can do is use the class above to get an array of 5 buffered image like so
screencap nsc = new screencap();
try {
ArrayList<BufferedImage> bfl = nsc.get();
} catch (AWTException | IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
The problem that I encountered was that the code worked flawlessly when I ran it on eclipse but when I exported it as an executable jar file it didn't work and couldn't even throw an error. I'm pretty sure the code at fault here is screencap.get() but I don't know how to fix it. Can someone tell me what went wrong? Thanks in advance.
SOLVED: I turned off window scaling. Apparently it messes with my program somehow.
Also, when I execute the program from cmd it works even if window scaling is on
#ArnaudClaudel thank you for suggesting I use cmd
The reason my program didn't work is that I have window scaling turned on to 125%. It made my exported program look bigger than it supposed to be, making pictures look blurry and it messes with the function in the question. I fixed it by turning off window scaling. Another solution is to execute the jar file from the cmd.

Android's BitmapFactory returns corrupted image

I am participating in a project where we build an app which solves Rubiks' cubes. Initially we started with a desktop app using JavaFX but we decided to switch over to an Android app.
Since I already implemented a working model at least for color recognition, I wanted to reuse that and just build another UI around it. That is where I am stuck right now because I cannot even get Android's bitmap API to work. Unfortunately it looks like I need to stick with it since Swing/AWT/JavaFX image libraries are not available.
So I implemented a JUnit test which I cleaned up a bit:
package de.uniks.rubiksapp;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
#RunWith(RobolectricTestRunner.class)
public class TestBitmap {
#Test
public void testBitmap() {
Resources resources = RuntimeEnvironment.application.getResources();
InputStream testImageStream = resources.openRawResource(R.drawable.test_front);
Bitmap testImageBitmap = BitmapFactory.decodeStream(testImageStream);
//Bitmap testImageBitmap = BitmapFactory.decodeResource(resources, R.drawable.test_front);
// --- Pixel readout would be here --- //
System.out.println(testImageBitmap.getWidth() + "x" + testImageBitmap.getHeight() + "px");
FileOutputStream out = null;
try {
out = new FileOutputStream("test.png");
testImageBitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (out != null) {
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
My problem currently is that the bitmaps I get from BitmapFactory seem to be corrupted. When I am trying to read specific pixels using Bitmap.getPixel(), they are always black. So I tried saving the image back to disk which works but the resulting files are only around 40 bytes large and cannot be opened.
Initially, I tried using Bitmap.decodeResource() instead of Bitmap.decodeStream() but that always returns images with a size of 100x100px, although my source images are 1240x800px large. Even when I use Bitmap.Options and set inScaled = false. At least the size is correct when using Bitmap.decodeStream().
Thanks for any help!

How rotate image and save it from JSP/Servlet page

I was able to successfully use JQueryRotate to rotate my images in a JSP page.
However, the user now wants to have the ability to save the rotated image.
But from what I've gathered so far, it seems that it's not possible to do this client side. So I probably have to re-start from scratch.
Is it possible to do a rotate image with saving capability for images rendered in a JSP/Servlet? If yes, how?
EDIT: By the way, HTML5 is out of the questions because my requirement is to still support IE9.
Well, just to sumarize. Using non-HTML5 browsers - no way to save the modified on the client side picture. In a modern browser - you could try to save a canvas containing the image. Also you could keep track of the css trasformation and, on demand, render trasformed image but this is server side and just will show rotated image, not save it. Other thing you could do is send the transformed image to the server when the user ask for saving operation, rotate/transform the image using image manipulation software/library on the server side and send the new image back to the client. This could work, for example php has some image libraries. BTW, some social sites share images but, I think, all the transformation if any (crop, cut, resize, rotate...) is made on the server, when the user upload the image and it is saved on the server. BTW (2) a time ago in a J2EE application we had to do something like this because of user requirement - save an image rendered in a browser to the client machine. Will try to rescue the idea and if there is something interesting will post it.
EDITED
Here is some code we made a time ago for saving screen captures:
import java.awt.AWTException;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import javax.imageio.ImageIO;
public class Screenshot {
public Screenshot() {
}
public static void imageCapture(int left, int top, int width, int height, String outFileName, String imgFormat) {
if (!outFileName.toUpperCase().endsWith(imgFormat)) {
outFileName += "." + imgFormat;
}
try {
Robot robot = new Robot();
BufferedImage bi = robot.createScreenCapture(new Rectangle(left, top, width, height));
ImageIO.write(bi, imgFormat, new File(outFileName));
}
catch (AWTException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
}
public static void imageCapture(int left, int top, int width, int height, OutputStream outStream, String imgFormat) {
try {
Robot robot = new Robot();
BufferedImage bi = robot.createScreenCapture(new Rectangle(left, top, width, height));
ImageIO.write(bi, imgFormat, outStream);
}
catch (AWTException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
}
}
As you see we used java.awt. Set full file path or already prepared OutputStream to the file you want to write and then send back to the browser the image file. This approach has a disadvantage - if you have scroll, the parte out of the window (let say "scrolled out") will no be captured. Well in fact it has many disadvantages but that's all I have and you can make some research. Hope this helps.

I want to display a blurred image in imageJ. Why doesn't this work?

I'm very very new to imageJ but know a little Java.
Essentially I want to open a file from an OpenDialog display the image, then blur the image and display the resulting blurred image. My program compiles, however the two images look the same. Can anybody help? How do I make the program display a blurred and unblurred image?
import ij.*;
import ij.io.*;
import ij.process.*;
import ij.gui.*;
import java.awt.*;
import ij.plugin.*;
import java.util.*;
import java.io.*;
public class opens_ implements PlugIn {
ImagePlus imp;
public void run(String arg){
OpenDialog od = new OpenDialog("Open.....", arg);
Opener op = new Opener();
String directory = od.getDirectory();
String filename = od.getFileName();
if (filename==null) return ;
imp = op.openImage(directory, filename);
imp.show();
ImageProcessor improc = imp.getProcessor();
improc.smooth();
ImagePlus alter = new ImagePlus("alter", improc) ;
alter.show();
}
}
Thanks
Bateman
When you call .smooth() on improc, that call alters the image data contained by the ImageProcessor, which is being displayed by the original ImagePlus. Then you create a new ImagePlus based on the same ImageProcessor, so of course it's the blurred image rather than the original. If you don't want the original to be altered, then you can duplicate the ImageProcessor before smoothing, for example by changing the line:
ImageProcessor improc = imp.getProcessor();
... to:
ImageProcessor improc = imp.getProcessor().duplicate();
Update: when I tested your code, I saw both images as blurred. If you still see the original images, try adding the following to the end of your run method:
imp.updateAndDraw()
alter.updateAndDraw()

Categories

Resources