Search code examples
javaswingjavafx-8fxml

How do I paint a javax.swing.ImageIcon into a JavaFX .fxml rendered User Interface?


I am developing a JavaFX rich client that uses legacy resource providers. One such provided resource is a javax.swing.ImageIcon. I have to paint that icon inside a details dialog that is rendered from a JavaFX .fxml file.

The way I found to work was to paint the ImageIcon into a java.awt.image.BufferedImage using the ImageIcon.paintIcon() method with a java.awt.Graphics from BufferedImage.createGraphics(). From that BufferedImage, javafx.embed.swing.SwingFXUtils.toFXImage() gives a javafx.scene.image.WritableImage that can be placed in the ImageView of the .fxml.

Here is the code of the transforming method, based on some other solutions viewed here in StackOverflow:

private javafx.scene.image.Image atonIcon2ImageConverter(ImageIcon icon) {
    BufferedImage bi = new BufferedImage(
            icon.getIconWidth(),
            icon.getIconHeight(),
            BufferedImage.TYPE_INT_RGB);

    Graphics g = bi.createGraphics();
    // paint the Icon to the BufferedImage.
    icon.paintIcon(null, g, 0, 0);
    g.dispose();
    return SwingFXUtils.toFXImage(bi.getSubimage(0, 1, bi.getWidth(), bi.getHeight()-1), null);
}

Although this solution works, it appears to me quite convoluted and I would like some expert opinion on how it could be made more straightforward. With JavaFX being the successor of Swing, I see quite possible that there is a simpler way to place a Swing ImageIcon inside a JavaFX .fxml file (the ImageIconis given, but the ImageView can be challenged).

Edit: my solution.

After playing around and mixing different comments and solutions, here is what I came out with for my real system implementation. It definitely is a very particular environment (the ImageIcon has a Swing ToolkitImage inside), so it might not be applicable to many:

private javafx.scene.image.Image atonIcon2ImageConverter(ImageIcon icon) {
    BufferedImage bi = ((sun.awt.image.ToolkitImage)imageIcon.getImage()).getBufferedImage();
    return SwingFXUtils.toFXImage(bi, null);
}

Solution

  • Have you tried:

    ImageIcon imageIcon;
    Image image = imageIcon.getImage();
    BufferedImage bufferedImage = (BufferedImage) image;
    

    or combinded

    BufferedImage bufferedImage = (BufferedImage) imageIcon.getImage();
    

    Whether this works or not depends on how the ImageIcons are constructed in your legacy code. Here is a working example. It also contains the commented out variant which does not work.

    import java.awt.image.BufferedImage;
    import java.io.IOException;
    
    import javax.imageio.ImageIO;
    import javax.swing.ImageIcon;
    
    public class ImageIconTest {
    
        public static void main(String[] args) throws IOException {
            ImageIcon imageIcon = createImageIcon("/DukeCheers.png", "DukeCheers");
    
            BufferedImage bufferedImage = (BufferedImage)imageIcon.getImage();
    
            System.out.println("done");
        }
    
        private static ImageIcon createImageIcon(String path, String description) throws IOException {
            java.net.URL imgURL = ImageIconTest.class.getResource(path);
            if (imgURL != null) {
    
                // This does not work.
                // return new ImageIcon(imgURL, description);
    
                // This works.
                return new ImageIcon(ImageIO.read(imgURL), description);
    
            } else {
                System.err.println("Couldn't find file: " + path);
                return null;
            }
        }
    
    }