I am developing an application that must have a custom icon. The provided icon is the same in all sizes (256x256, 48x48, 32x32) except in 16x16 where the icon is simplified.
I thought about the .ico format (where I can store all the differents icons and let the OS showing the best) but it doesn't seem to be supported by the javafx.scene.image (I haven't found any confirmation about that).
Here is how I set up my icon
stage.getIcons().add(new Image(getClass().getResourceAsStream("/path/to/icon.ico")));
In this case the icon is never displayed. If I convert this icon into a .png image, this works but enforces to always display the same icon (even in 16x16).
Is there a way in JavaFX 2.2 to display a .ico (even in an hacky way) or do I have to use other image formats ?
I separated my .ico into multiple png (one for each size) and then loading them one by one.
stage.getIcons().add(new Image(getClass().getResourceAsStream("/path/to/icon_16x16.png")));
stage.getIcons().add(new Image(getClass().getResourceAsStream("/path/to/icon_256x256.png")));
The 256x256 and the 16x16 are two different images but the 16x16 is never showed in the top left of the application (despite this is the nearest size).
Feature Request
See the related feature request:
The feature is currently not allocated to a release, but you can vote or comment on it if you like.
Loading ico files using third party libraries
In the meantime, you can use various utilities for creating icons in java.awt.image.BufferedImage
format and then convert them to JavaFX using SwingFXUtils
. haraldK provides a sample of this approach in his answer. Another example is the fav icon fetcher for the willow browser, which uses the image4j library, though haraldK's twelve monkeys library is likely the better library to use. Your other alternative is to port the source of one of the awt based icon libraries to JavaFX, making use of a WritableImage
.
Advice
Your reasoning for not using png because it always displays 16x16 is a bit strange to me, because the stage.getIcons()
documentation returns a list of images you can add to (you aren't limited to adding single icon). From the javadoc:
Gets the icon images to be used in the window decorations and when minimized. The images should be different sizes of the same image and the best size will be chosen, eg. 16x16, 32,32.
Additional question
What if, depending on the size, the image is not always the same
It's probably OK to provide different images. If the system interpolates provided images to create icons of sizes which are not provided, that could cause an issue - but I think that it is highly unlikely that the system would do that. "Images should be different sizes of the same image" is more of a guideline than an actual rule. If you need different images at different sizes, try supplying multiple png images for that and see what happens.
I don't think JavaFX supports the ICO format directly. I'm pretty sure the list is JPEG, GIF and PNG only, but I've yet to find an official source that confirms this.
However, you could use my ICO plugin for ImageIO to read the ICO file, and convert the image to an FX Image
using SwingFXUtils.toFXImage(bufferedImage, null)
.
Note that the reader simply returns the icons in the order they are found in the ICO file, so ImageIO.read(...)
will not give you the icon you want (it will only read the first). Instead you need to read each icon, convert and add all the icons to your stage. And FX will select correct size for you. :-)
Something like:
ImageInputStream stream = ImageIO.createImageInputStream(getClass().getResourceAsStream("/path/to/icon.ico"));
ImageReader reader = ImageIO.getImageReaders(stream).next();
reader.setInput(stream);
int count = reader.getNumImages(true);
List<Image> fxImages = new ArrayList<>(count);
for (int i = 0; i < count; i++) {
BufferedImage bufferedImage = reader.read(i, null);
Image fxImage = SwingFXUtils.toFXImage(bufferedImage, null);
fxImages.add(fxImage);
}
stream.close(); // Remember to close/dispose in a finally block
reader.dispose();
// ...
stage.getIcons().addAll(fxImages);
Use image4j:
ArrayList<Image> lImages = new ArrayList<>();
ICODecoder.read(Global.FILE_ICON).stream().forEach((lBufferedImage) -> lImages.add(SwingFXUtils.toFXImage(lBufferedImage, null)));
this.getStage().getIcons().addAll(lImages);
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