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.
Related
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()
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.
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).
There is a built-in method in the Java JDK that detects file types:
Files.probeContentType(Paths.get("/temp/word.doc"));
The javadoc says that a FileTypeDetector may examine the filename, or it may examine a few bytes in the file, which means that it would have to actually try to pull the file from a URL.
This is unacceptable in our app; the content of the file is available only through an InputStream.
I tried to step through the code to see what the JDK is actually doing, but it seems that it goes to FileTypeDetectors.defaultFileTypeDetector.probeContentType(path) which goes to sun.nio.fs.AbstractFileTypeDetector, and I couldn't step into that code because there's no source attachment.
How do I use JDK file type detection and force it to use file content that I supply, rather than having it go out and perform I/O on its own?
The docs for Files.probeContentType() explain how to plug in your own FileTypeDetector implementation, but if you follow the docs you'll find that there is no reliable way to ensure that your implementation is the one that is selected (the idea is that different implementations serve as fallbacks for each other, not alternatives). There is certainly no documented way to prevent the built-in implementation from ever reading the target file.
You can surely find a map of common filename extensions to content types in various places around the web and probably on your own system; mime.types is a common name for such files. If you want to rely only on such a mapping file then you probably need to use your own custom facility, not the Java standard library's.
The JDK's Files.probeContentType() simply loads a FileTypeDetector available in your JDK installation and asks it to detect the MIME type. If none exists then it does nothing.
Apache has a library called Tika which does exactly what you want. It determines the MIME type of the given content. It can also be plugged into your JDK to make your Files.probeContentType() function using Tika. Check this tutorial for quick code - http://wilddiary.com/detect-file-type-from-content/
If you are worried about reading the contents of an InputStream you can wrap it in a PushBackInputStream to "unread" those bytes so the next detector implementation can read it.
Usually binary file's magic numbers are 4 bytes so having a new PushBackInputStream(in, 4) should be sufficient.
PushBackInputStream pushbackStream = new PushBackInputStream(in, 4);
byte[] magicNumber = new byte[4];
//for this example we will assume it reads whole array
//for production you will need to check all 4 bytes read etc
pushbackStream.read(magicNumber);
//now figure out content type basic on magic number
ContentType type = ...
//now pushback those 4 bytes so you can read the whole stream
pushbackStream.unread(magicNumber);
//now your downstream process can read the pushbackStream as a
//normal InputStream and gets those magic number bytes back
...
Following on from my previous question, my program doesn't detect the 300 images that have just been created in a particular directory; instead, it only detects desktop.ini, which is not the case as I can physically see that the files have been created within said directory and do exist.
Can somebody please explain why this happens as when I run the program the next time, it seems to work just fine?
The only way that something is detected within the directory on the first run is when there is at least one file which exists in the directory before the program is compiled and executed.
Many thanks.
UPDATE: Files are detected as follows:
//Default greyscale image directory (to convert from greyscale to binary).
static File dirGrey = new File("test_images\\Greyscale");
//Array of greyscale image filenames.
static File imgListGrey[] = dirGrey.listFiles();
without knowing how you create the images, this question is akin to 'How many kittens are under my desk right now?'
Are you creating the files yourself? If so, are you closing any file handles referring to those files once they are created?
You're creating the file list in a static array, and it's created when the class containing the array is loaded by the Java class loader, which is probably before you create the image files. That's why the array contains an outdated list.
static is rarely needed, mostly useful for constants (things that never change, such as 42), for pure functions (Math.sqrt()) and a few other special cases. When you use it, you have to learn all the tricky initialization order stuff. Otherwise, just stick with non-static variables.