I've been reading the OS X Java Developer Tools, in order to help make my application more "native" with the operating system. I found something interesting in this particular section. (emphasis mine)
To load a resolution-independent tiff, icns, or pdf file from the Resources folder of your application bundle into your Java application, use the
getImage()
method ofjava.awt.Toolkit
. The string you pass intogetImage()
is of the form"NSImage://MyImage"
. Do not include the file extension of the image. Also be aware that the Sun 2D renderer is disabled when the user interface scale factor does not have a value of 1.0. Use the Quartz renderer so that your images scale smoothly.
Being familiar with javax.imageio
, this comes as a complete surprise, as I hadn't known any other way to load other filetypes into images. Especially with an outdated platform and absolutely no support for files such as .tiff
. For example, a quick test on my computer gives me this:
Supported read formats: [jpg, bmp, gif, png, wbmp, jpeg]
Supported write formats: [jpg, bmp, gif, png, wbmp, jpeg]
'JPEG' reader: com.sun.imageio.plugins.jpeg.JPEGImageReader@5e9f23b4
'JPEG' reader: com.sun.imageio.plugins.jpeg.JPEGImageWriter@378fd1ac
I tried loading a simple .tiff
image and tested this out:
static Image n; public static void main(String[] args) { JFrame f = new JFrame(); JPanel p = new JPanel() { @Override public void paintComponent(Graphics graphics) { graphics.drawImage(n, 0, 0, null); } } f.add(p); n = Toolkit.getDefaultToolkit().getImage(("/Users/zinedine/Desktop/test_image.tiff"); f.setVisible(true) }
It yields nothing:
I tried again: This time, adding the image into the base folder of my java project, and typed this in as a string: "NSImage://test_image.tiff"
. Like everything I do, it doesn't work.
However, If I change my fancy path string to an NSImage one, such as "NSImage://NSApplicationIcon"
...
It works. I did a quick spotlight search for NSImage, and found one. It looks like the file type for these images are .png
. This is kind of disturbing, since I expected a proper image to come out of it. Mind you, I also kind of expected it: If it expects arguments of the form "NSImage://something"
, then it might just ignore anything else.
Obviously, I've got a couple questions:
How does the Toolkit load the image? If I try to load a .tiff
image from my desktop, this is what I get if I call .toString()
:
sun.awt.image.ToolkitImage@25f38edc // Also can't be cast to java.awt.BufferedImage
Are the readers (and writers if any) part of a public API? In other words, can I call something to load my .tiff
file into an Image
(which I can then cast into a `BufferedImage?
And then again, if the readers/writers are part of the API, why doesn't the javax.imageio
package locate them?
This may look like a handful, (yes I'm sorry for ruining your day on this question), but to me, this looks like expected, but at the same time erroneous behaviour. Bonus marks: Is there any friendly (i.e. Open Source) imaging api (Not the JAI) that can process .tiff
files (and others)?
You are asking multiple questions here, but I'll do my best at interpreting it all. :-)
Using the Toolkit
to load images (java.awt.Image
and friends) is part of the "old" asynchronous producer/consumer imaging API, and might feel a bit awkward to work with. It's completely okay for loading packaged icons and similar, but less suitable for loading large, user-supplied images, as you have no progress tracking, little error feedback if anything goes wrong, etc.
These images are also a lot less useful than BufferedImage
s, if you want to perform image manipulations of any kind. You cannot cast them to a BufferedImage
but you can "convert" them, by painting them onto a BufferedImage
.
The Toolkit
class is abstract, and you obtain a concrete instance using Toolkit.getToolkit()
. This concrete instance is platform specific, and ends up using systems specific native calls for most methods, like loading images.
The Apple Java implementation does have some extra features, like allowing you to load Apple system images using a special URI scheme. It seems it can also load bundled images this way, using the @2x
naming convention, and even multi-scale TIFFs or scalable PDFs in OS X for resolution independent graphics for your application.
Note that for this to work, you need to package your application as an application bundle, and place your images in the Resources folder (ie. Contents/Resources
) of the bundle. And you must refer to images using its base name, without extension. You can not use this functionality to read random TIFF files not packaged with your application (ie. user supplied content), as far as I know.
Furthermore, this functionality is specific to the Apple JRE, and will only work on Apple's own JRE, and on OS X. It is not part of the public Java API, and it will not work cross platform. I recommend using the functionality sparingly, and only to have better system integration (ie. make your application look more native) on OS X.
To read (and write) any TIFF (or any other format for that sake), you should instead use ImageIO
and some proper plugins. The JRE does not come with plugins for the TIFF format for some reason, but several third party plugins exists.
If you don't want to use JAI (through jai_imageio.jar
), I can recommend my own TwelveMonkeys library which supports TIFF along with quite a few other formats. It uses the business-friendly open source BSD license.
There are also Apache Commons Imaging, iCafe and probably others that can read/write TIFF, but these have their own custom APIs, which make them less flexible and more proprietary IMO.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With