What is difference between these two kinds of image loading code? - java

These two kinds of code below are used for loading an Image file:
A)
File sourceimage = new File("filename");
Image image = ImageIO.read(sourceimage);
B)
Toolkit tk = Toolkit.getDeafaultToolkit();
img=tk.getImage("filename");
What's the real difference between these two codes ?

ImageIO.read(File) takes a File and is newer than Toolkit.getImage(String) which takes a filename (and has been part of the language longer). Also, the first one provides additional functionality (that is, the ImageIO.read(File) javadoc says in part)
The current cache settings from getUseCache and getCacheDirectory will be used to control caching in the ImageInputStream that is created.
Note that there is no read method that takes a filename as a String; use this method instead after creating a File from the filename.

Perhaps the primary difference between the two is that Toolkit.getImage returns a java.awt.Image, while ImageIO.read return a java.awt.image.BufferedImage (which is a subclass of java.awt.Image).
An Image object is a fairly abstract image representation that you can't do very much with apart from pass to the various Graphics.drawImage methods, while a BufferedImage contains the full image data, so that you can inspect individual pixels, modify them and also, for instance, save the image (to a new file and/or a new file format).

Related

Determine in Java, whether a file is a picture, having only binary data

The situation is this: in my code I download a picture from the Internet as an array of bytes: byte[] imageBytes. And then I make the object of my MyImage class:
public class MyImage {
private String imageName;
private byte[] data;
// Constructor, getters, setters
}
Create object:
MyImage myimg = new MyImage("some_name", imageBytes);
Then I use my resulting object.
I have a question: can I somehow make sure, that I downloaded the picture file?
It seems that each file type has its own signature (that is, the first bytes of the file). But there are a lot of different types of files. And if I compare the signature of my file with all existing types of signatures, then these will be very large checks.
Is it possible to make the check simpler: do I currently have an image (no matter what type) or not image?
Why do I want to do this: what if the user mistakenly passes a link not to an image, but to a file of a different type (for example, an archive). And in this case, I would like to determine in the code that the wrong file was downloaded and give the user an appropriate error message.
One way could be to check the Content-Type header that is sent from the server you download from. Another one could be the same algorithm that is used by the Linux file command. It would be tedious to reimplement that in Java.
So I suggest to either
check the Content-Type header
assuming you are on a *nix system: store the data in a file, then exec file and get the result
just try to parse the image and let the graphics library decide. If successful, check the image you obtained
some libraries are listed in How to reliably detect file types?
The most promising way would be to ask the JDK via probeContentType()

When calling javax.imageio.ImageIO.read, can I specify the format?

In Java, I want to use the class javax.imageio.ImageIO to read a image from an InputStream. This class has a static method, read(InputStream input), which can do this.
However, this method does not allow me to specify the format (such as png, jpeg, bmp ...). According to the documentation of this class, it seems that this method will detect the format automatically from the InputStream. But to me, this seems unsafe. What if a byte sequence can be interpreted as two different image formats? After all, a byte sequence is meaningless unless a format is specified. Besides, it seems that custom image formats and their readers can be registered to the ImageIO class, which makes this problem more severe.
So, is there a way to read an image from an InputStream with a format specified?
No, none of the static ImageIO.read(...) methods allows specifying the format to be read.
For these methods, the registered reader plugins briefly inspects the stream/file contents and decides whether or not it is able to decode it. The first reader plugin that can decode is chosen, and an actual reader instance is created to perform the decoding.
For most file formats, this method is a common and completely safe way to determine the file format, and is based on the "magic identifier" or file signature. There are file formats that does not have such signatures that are hard to detect, like WBMP, PICT or old TGA files. But the formats you mention, like BMP, JPEG and PNG are all easily and correctly detected using this mechanism.
If however, you know that your inputs are always the same format or explicitly only want to support a single format, that is possible with a little extra code. This is probably also a tiny bit faster than detecting the file format by inspection, although I doubt it matters much.
If the only format you want is JPEG, use ImageIO.getImageReadersByFormatName("JPEG") (getImageReadersBySuffix("jpg") or getImageReadersByMIMEType("image/jpeg") will also do) to get a reader and then pass the input directly to this reader. The code would look something like this:
Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName("JPEG");
ImageReader reader = readers.next(); // There should always be a JPEG reader installed, for other formats you might want to check
try (ImageInputStream stream = ImageIO.createImageInputStream(input)) {
reader.setInput(stream);
BufferedImage image = reader.read(0);
}
finally {
reader.dispose();
}
Yes you can speficy the format. You do that with the file name.
BufferedImage img = ImageIO.read(new File("abc.jpg"));
For more information, like accepted file formats, take a look here.
https://docs.oracle.com/javase/tutorial/2d/images/loadimage.html
This topic didn't let me sleep last night. Take a look at this solution:
The computer must know, how to handle a file and for that, it takes a look into the file. Just open an image with the normal editor and you see what I mean.
You can write a method for specification by yourself. This method needs to read a file (or a part of it), and then check for the format.

Java : read an image inside a binary file (or maybe more generally, from a stream)

I am making a java program that reads a binary file, which contains multiple images (in PNG format), and some binary data.
How can i load the images (specifically, as java.awt.Image's) ? So far the only way i have found to load an image is via functions that just take a file. How can i do it from, say, an InputStream ?
The ImageIO#read(InputStream) method does return a java.awt.image.BufferedImage (which extends from java.awt.Image).
https://docs.oracle.com/javase/8/docs/api/javax/imageio/ImageIO.html#read-java.io.InputStream-

BufferedImage are Null in runtime

I'm having a problem with BufferedImage in runtime. I'm loading an .png, but the BufferedImage is null. I don't get an IOException, but an NullPointerException. And the biggest problem to me, is that when I run this same code in netbeans he works fine...
My code is
public Image loadImage() throws IOException {
BufferedImage bufferedImage = ImageIO.read(new File(ApplicationProperties.getPath() + "\\.wimdesktop\\image.png"));
return SwingFXUtils.toFXImage(bufferedImage, null);
}
The ApplicationProperties.getPath() are static and don't change in runtime.
And if I separate the declaration of the BufferedImage and try file.exists() I get a true result
Well, read the docs. This is bizarre behaviour, sure, but the docs spell it out for you:
Returns a BufferedImage as the result of decoding a supplied File with an ImageReader chosen automatically from among those currently registered. The File is wrapped in an ImageInputStream. If no registered ImageReader claims to be able to read the resulting stream, null is returned.
(I added the highlight). It's intentional behaviour, in other words.
This method is bad and you should never call it. Call one of the other ones, take some control back. Usually, such images are as static as your class files are: You determine what these images should be when you create this program, and your users are not meant to make them, edit them, or otherwise have any influence on it. Therefore, it makes sense to store these images in the same place you 'store' your class files: In a jar or jmod, together.
You can ask java to read stuff from the same place it reads class files. I think you should probably be using that mechanism instead. You need a method that takes an InputStream or URL. Fortunately, there are overloads of the read method for both. Thus:
If you e.g. have a java file MyApp.java, which starts with package com.foo;, then you end up having a jar file that contains the entry com/foo/MyApp.class; you can see this if you run jar tvf myapp.jar.
Now ensure that the image is in the same jar, either in a (subdir of) com/foo or in the root of the jar, your choice. Let's say that you have com/foo/img/image.png inside that jar.
Then, to make a BufferedImage out of that:
BufferedImage img = ImageIO.read(MyApp.class.getResource("img/image.png"));
return SwingFXUtils.toFXImage(img, null);
If you must go off of a file for some bizarre reason, take control of the process in order to get non-idiotic error handling (The read method that takes a File, unfortunately, qualifies as idiotic error handling, so you don't want that one):
try (FileInputStream in = new FileInputStream(new File(...))) {
BufferedImage img = ImageIO.read(in);
}
This way, if img is now null, you know that the file was most likely read just fine, but its either not a valid image at all, or its in a format that java cannot read (for example, I don't think java can guaranteed read anything, except png and jpg. So it might be in HEIF/HEVC, TIFF, BMP, etc - stuff java won't be able to read as far as I know).
Contrast to what you do, where it could also be that the file does not exist or your java process does not have read access to the file.

JAI: How do I extract a single page input stream from a multipaged TIFF image container?

I have a component that converts PDF documents to images, one image per page. Since the component uses converters producing in-memory images, it hits the JVM heap heavily and takes some time to finish conversions.
I'm trying to improve the overall performance of the conversion process, and found a native library with a JNI binding to convert PDFs to TIFFs. That library can convert PDFs to single TIFF files only (requires intermediate file system storage; does not even consume conversion streams), therefore result TIFF files have converted pages embedded, and not per-page images on the file system. Having a native library improves the overall conversion drastically and the performance gets really faster, but there is a real bottleneck: since I have to make a source-page to destination-page conversion, now I must extract every page from the result file and write all of them elsewhere. A simple and naive approach with RenderedImages:
final SeekableStream seekableStream = new FileSeekableStream(tempFile);
final ImageDecoder imageDecoder = createImageDecoder("tiff", seekableStream, null);
...
// V--- heap is wasted here
final RenderedImage renderedImage = imageDecoder.decodeAsRenderedImage(pageNumber);
// ... do the rest stuff ...
Actually speaking, I would really like just to extract a concrete page input stream from the TIFF container file (tempFile) and just redirect it to elsewhere without having it to be stored as an in-memory image. I would imagine an approach similar to containers processing where I need to seek for a specific entry to extract data from it (say, something like ZIP files processing, etc). But I couldn't find anything like that in ImageDecoder, or I'm probably wrong with my expectations and just missing something important here...
Is it possible to extract TIFF container page input streams using JAI API or probably third-party alternatives? Thanks in advance.
I could be wrong, but don't think JAI has support for splitting TIFFs without decoding the files to in-memory images. And, sorry for promoting my own library, but I think it does exactly what you need (the main part of the solution used to split TIFFs is contributed by a third party).
By using the TIFFUtilities class from com.twelvemonkeys.contrib.tiff, you should be able to split your multi-page TIFF to multiple single-page TIFFs like this:
TIFFUtilities.split(tempFile, new File("output"));
No decoding of the images are done, only splitting each IFD into a separate file, and writing the streams with corrected offsets and byte counts.
Files will be named output/0001.tif, output/0002.tif etc. If you need more control over the output name or have other requirements, you can easily modify the code. The code comes with a BSD-style license.

Categories

Resources