Read region from very large image file in Java - java

Is there a Java library that can read regions of very large image (e.g. JPEG) files (> 10,000 x 10,000 pixels) without keeping the whole image in memory.
Or alternatively, which Java library is capable of handling very large image files with a minimum of overhead.

Standard ImageIO allows you to read regions of (large) images without reading the entire image into memory first.
Rectangle sourceRegion = new Rectangle(x, y, w, h); // The region you want to extract
ImageInputStream stream = ImageIO.createImageInputStream(input); // File or input stream
Iterator<ImageReader> readers = ImageIO.getImageReaders(stream);
if (readers.hasNext()) {
ImageReader reader = readers.next();
reader.setInput(stream);
ImageReadParam param = reader.getDefaultReadParam();
param.setSourceRegion(sourceRegion); // Set region
BufferedImage image = reader.read(0, param); // Will read only the region specified
}

You can use, for example, RandomAccessFile to read from the middle of the file:
but the issue is that whole jpeg image is compressed after DCT quantization (http://www.fileformat.info/mirror/egff/ch09_06.htm), so I don't think that it is possible to read a fragment without reading whole file to memory.

You can use a BufferedImage to do what you need.
// Set these variables according to your requirements
int regionX, regionY, regionWidth, regionHeight;
BufferedImage image = ImageIO.read(new File("/path/to/image.jpg"));
BufferedImage region = image.getSubimage(regionX, regionY, regionWidth, regionHeight);
And then you can process the region subimage however you want.

Related

Write animated-gif stored in BufferedImage to java.io.File Object

I am reading a gif image from internet url.
// URL of a sample animated gif, needs to be wrapped in try-catch block
URL imageUrl = new Url("http://4.bp.blogspot.com/-CTUfMbxRZWg/URi_3Sp-vKI/AAAAAAAAAa4/a2n_9dUd2Hg/s1600/Kei_Run.gif");
// reads the image from url and stores in BufferedImage object.
BufferedImage bImage = ImageIO.read(imageUrl);
// creates a new `java.io.File` object with image name
File imageFile = new File("download.gif");
// ImageIO writes BufferedImage into File Object
ImageIO.write(bImage, "gif", imageFile);
The code executes successfully. But, the saved image is not animated as the source image is.
I have looked at many of the stack-overflow questions/answers, but i am not able to get through this. Most of them do it by BufferedImage frame by frame which alters frame-rate. I don't want changes to the source image. I want to download it as it is with same size, same resolution and same frame-rate.
Please keep in mind that i want to avoid using streams and unofficial-libraries as much as i can(if it can't be done without them, i will use them).
If there is an alternative to ImageIO or the way i read image from url and it gets the thing done, please point me in that direction.
There is no need to decode the image and then re-encode it.
Just read the bytes of the image, and write the bytes, as is, to the file:
try (InputStream in = imageUrl.openStream()) {
Files.copy(in, new File("download.gif").toPath());
}

Encoding image file

I have an int array of color r,g and b values. And I would like to encode them in a image file. Is there an easy method in android to write this data to an image? Also which image format should I use for this, png?
Create a bitmap using your int array like this using Bitmap.createBitmap:
int[] array; // array of int RGB values e.g. 0x00ff0000 = red
Bitmap bitmap = Bitmap.createBitmap(array, width, height, Bitmap.Config.ARGB_8888);
Then write it out using Bitmap.compress:
outStream = new FileOutputStream(filepath);
bitmap.compress(Bitmap.CompressFormat.PNG, 100, outStream);
You can call Environment.getExternalStorageDirectory() to get a folder on external storage where you can save the file, if that's where you want to save it. You can get the path with get File.getAbsolutePath(), e.g:
String filepath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/image.png";
You need the WRITE_EXTERNAL_STORAGE permission defined in your AndroidManifest.xml to be able to write to files on external storage.
There are pure java implementations for reading and writting images:
Image processing library for Android and Java
Probably some will work in android out of the box
I believe ImageIO is available in Android. The ImageIO API provides methods to read the source image and to write the image in the new file format.
To read the image, simply provide the ImageIO.read() method a File object for the source image. This will return a BufferedImage.
//Create file for the source
File input = new File("c:/temp/image.bmp");
//Read the file to a BufferedImage
BufferedImage image = ImageIO.read(input);
Once you have the BufferedImage, you can write the image as a PNG. You will need to create a File object for the destination image. When calling the write() method, specify the type string as "png".
//Create a file for the output
File output = new File("c:/temp/image.png");
//Write the image to the destination as a PNG
ImageIO.write(image, "png", output);

Is there an efficient way to crop out PDF and save as image (.JPG) via java program?

I am Currently using ICEPDF to render PDF files and display it in my java Swing application (in Internal Frame). Now I want to add crop features to my Java application. Like, if I click a button, I can drag required portion of PDF and save it as Image in my local storage.
Is there an efficient way to crop out PDF and save as image (.JPG) via java program?
Ghost4J library (http://ghost4j.sourceforge.net), is your best option:
3 simple step:
Load PDF files:
PDFDocument document = new PDFDocument();
document.load(new File("test.pdf"));
Create the renderer:
SimpleRenderer renderer = new SimpleRenderer();
// set resolution (in DPI)
renderer.setResolution(600);
Render:
List<Image> images = renderer.render(document);
Then you can do what you want with your image objects, for example, you can write them as JPG like this:
for (int i = 0; i < images.size(); i++) {
ImageIO.write((RenderedImage) images.get(i), "jpg", new File((i + 1) + ".jpg"));
}
Ghost4J uses the native Ghostscript API so you need to have a Ghostscript installed.
EDIT: investigating a bit, if you convert the PDF to Image you won't have much problem to crop them:
BufferedImage is a(n) Image, so the implicit cast that you're doing in the second line is able to be compiled directly. If you knew an Image was really a BufferedImage, you would have to cast it explicitly like so:
Image image = ImageIO.read(new File(file));
BufferedImage buffered = (BufferedImage) image;
Then you can crop it with BufferedImage::getSubimage method:
private BufferedImage cropImage(BufferedImage src, Rectangle rect) {
BufferedImage dest = src.getSubimage(rect.x, rect.y, rect.width, rect.height);
return dest;
}

Stream the content of a scanned image to a file in Java

I'm trying to scan an image and save it to a file given a specific format (Tiff or Jpeg) with a Swing application, using Morena and Sane.
I load the whole image in memory with this process:
SaneSource source = /* source implemented here */;
MorenaImage morenaImage = new MorenaImage(source);
Image image=Toolkit.getDefaultToolkit().createImage(morenaImage);
BufferedImage bimg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D g = bimg.createGraphics();
g.drawImage(image, 0, 0, null);
ImageIO.write(bimg, "jpg", new File(filename));
I'm pretty sure there is a better way to do this without eating all my memory, like streaming the content of my scanned image in cache to the file with a Consumer / Observer, but I couldn't wrap my mind good enough around these notions to create my own solution.
Could you please help me down the path to better image processing?
Thanks in advance, david
You should attach an ImageConsumer (that will write image to OutputStream using your favorite image format) directly to an ImageProducer (SaneSource or MorenaImage if you wish). You can find ImageConsumer example that encodes image as PPM and transfers it to OutputStream here. You'll need to write something like this to use this example:
ImageProducer prod = ... your producer here ....;
PpmEncoder ppm = new PpmEncoder(prod, myOutputStream);
ppm.encode();

Java: Reading images and displaying as an ImageIcon

I'm writing an application which reads and displays images as ImageIcons (within a JLabel), the application needs to be able to support jpegs and bitmaps.
For jpegs I find that passing the filename directly to the ImageIcon constructor works fine (even for displaying two large jpegs), however if I use ImageIO.read to get the image and then pass the image to the ImageIcon constructor, I get an OutOfMemoryError( Java Heap Space ) when the second image is read (using the same images as before).
For bitmaps, if I try to read by passing the filename to ImageIcon, nothing is displayed, however by reading the image with ImageIO.read and then using this image in the ImageIcon constructor works fine.
I understand from reading other forum posts that the reason that the two methods don't work the same for the different formats is down to java's compatability issues with bitmaps, however is there a way around my problem so that I can use the same method for both bitmaps and jpegs without an OutOfMemoryError?
(I would like to avoid having to increase the heap size if possible!)
The OutOfMemoryError is triggered by this line:
img = getFileContentsAsImage(file);
and the method definition is:
public static BufferedImage getFileContentsAsImage(File file) throws FileNotFoundException {
BufferedImage img = null;
try {
ImageIO.setUseCache(false);
img = ImageIO.read(file);
img.flush();
} catch (IOException ex) {
//log error
}
return img;
}
The stack trace is:
Exception in thread "AWT-EventQueue-0" java.lang.OutOfMemoryError: Java heap space
at java.awt.image.DataBufferByte.<init>(DataBufferByte.java:58)
at java.awt.image.ComponentSampleModel.createDataBuffer(ComponentSampleModel.java:397)
at java.awt.image.Raster.createWritableRaster(Raster.java:938)
at javax.imageio.ImageTypeSpecifier.createBufferedImage(ImageTypeSpecifier.java:1056)
at javax.imageio.ImageReader.getDestination(ImageReader.java:2879)
at com.sun.imageio.plugins.jpeg.JPEGImageReader.readInternal(JPEGImageReader.java:925)
at com.sun.imageio.plugins.jpeg.JPEGImageReader.read(JPEGImageReader.java:897)
at javax.imageio.ImageIO.read(ImageIO.java:1422)
at javax.imageio.ImageIO.read(ImageIO.java:1282)
at framework.FileUtils.getFileContentsAsImage(FileUtils.java:33)
You are running out of memory because ImageIO.read() returns an uncompressed BufferedImage which is very large and is retained in the heap because it is referenced by the ImageIcon. However, the images returned by Toolkit.createImage remain in their compressed format (using the private ByteArrayImageSource class.)
You cannot read a BMP using Toolkit.createImage (and even if you could it would still remain uncompressed in memory and you would probably run out of heap space again) but what you can do is read the uncompressed image and save it in a byte array in compressed form, e.g.
public static ImageIcon getPNGIconFromFile(File file) throws IOException {
BufferedImage bitmap = ImageIO.read(file);
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
ImageIO.write(bitmap, "PNG", bytes);
return new ImageIcon(bytes.toByteArray());
}
That way the only time the uncompressed bitmap must be held in memory is when it is being loaded or rendered.
Have you tried this?
ImageIcon im = new ImageIcon(Toolkit.getDefaultToolkit().createImage("filename"));
It couldn't be that you indeed just run out of memory? I mean, does the error still occur if you run java with, say, -Xmx1g ?

Categories

Resources