Wednesday Aug 26, 2009

Get a swing component rendered to an image

Today my friend contacted me with an issue he faced with his program in swing. He wanted to get a swing component painted on to an image, except that he didn't want to show the component on screen. This was the code snippet he sent me:


    JPanel panel = new JPanel();
    panel.setSize(200, 200);
    panel.setBackground(Color.BLUE);
    panel.setLayout(new BorderLayout());
    panel.add(new JLabel("Hello"));

    //Get the panel rendered to an image
    BufferedImage image = new BufferedImage(200, 200, BufferedImage.TYPE_INT_RGB);
    Graphics g = image.createGraphics();
    panel.paintAll(g);
    g.dispose();
    ImageIO.write(image, "jpeg", <file>);
    image.flush();
  

Now, if the JPanel was added to a JFrame and shown, all worked well - the JPanel along with the JLabel in it was being correctly captured as image. But, when the JPanel wasn't added anywhere, only the blue background of JPanel was being captured as image. 

This seems to be a painting optimization being done in java. As per the documentation of Component.paint method


    For performance reasons, Components with zero width or height aren't 
    considered to need painting when they are first shown, and also aren't 
    considered to need repair.
  

My colleague Praveen came up with a workaround for this. The code was changed as follows and that solved the issue. Now, the JPanel along with its content is being captured correctly.


    Graphics g = image.createGraphics();
    panel.addNotify();
    panel.validate();
    panel.paintAll(g);
    g.dispose();
  

This seems to work in headless mode too.

Comments:

Post a Comment:
  • HTML Syntax: NOT allowed