6

I know how to get a BufferedImage from JComponent, but how to get a BufferedImage from a Component in java ? The emphasis here is an object of the "Component" type rather than JComponent.

I tried the following method, but it return an all black image, what's wrong with it ?

  public static BufferedImage Get_Component_Image(Component myComponent,Rectangle region) throws IOException
  {
    BufferedImage img = new BufferedImage(myComponent.getWidth(), myComponent.getHeight(), BufferedImage.TYPE_INT_RGB);
    Graphics g = img.getGraphics();
    myComponent.paint(g);
    g.dispose();
    return img;
  }
Frank
  • 30,590
  • 58
  • 161
  • 244

2 Answers2

8

Component has a method paint(Graphics). That method will paint itself on the passed graphics. This is what we are going to use to create the BufferedImage, because BufferedImage has the handy method getGraphics(). That returns a Graphics-object which you can use to draw on the BufferedImage.

UPDATE: But we have to pre-configure the graphics for the paint method. That's what I found about the AWT Component rendering at java.sun.com:

When AWT invokes this method, the Graphics object parameter is pre-configured with the appropriate state for drawing on this particular component:

  • The Graphics object's color is set to the component's foreground property.
  • The Graphics object's font is set to the component's font property.
  • The Graphics object's translation is set such that the coordinate (0,0) represents the upper left corner of the component.
  • The Graphics object's clip rectangle is set to the area of the component that is in need of repainting.

So, this is our resulting method:

public static BufferedImage componentToImage(Component component, Rectangle region) throws IOException
{
    BufferedImage img = new BufferedImage(component.getWidth(), component.getHeight(), BufferedImage.TYPE_INT_ARGB_PRE);
    Graphics g = img.getGraphics();
    g.setColor(component.getForeground());
    g.setFont(component.getFont());
    component.paintAll(g);
    if (region == null)
    {
        region = new Rectangle(0, 0, img.getWidth(), img.getHeight());
    }
    return img.getSubimage(region.x, region.y, region.width, region.height);
}
Martijn Courteaux
  • 67,591
  • 47
  • 198
  • 287
  • 1
    How is this different from how you would do it for a `Component`? I think the question needs some clarification. – aioobe Oct 04 '10 at 18:25
  • I tries it, still didn't work, maybe because the Component I passed to it is a WebBrowser object from JDIC, it's a non light weight Component, as I mentioned in my other question, do you know how to make it work ? Someone suggested I use CellRenderPane, but I don't know how to use it in my case, any sample code ? – Frank Oct 08 '10 at 00:03
  • @DavidKroukamp I don't think this is an excellent answer. Creating a `BufferedImage` with fixed attributes may mean that its processing is much slower than necessary. Also, while the Q asks for a `BufferedImage`, changes are that an `Image` is enough. Why not simply use `Component.createImage()`? – class stacker May 11 '15 at 09:02
  • This worked for me, although I may have been a bit smarter in obtaining a subregion. img = new BufferedImage(region.width,region.height,...); Graphics2D g = img.createGraphics(); g.translate(-region.x,-region.y); component.paintAll(g); I do believe Java optimises rendering based on clipping bounds, which should be the size of the image; it at least skips the getSubimage step if not. – Perry Monschau Mar 04 '17 at 14:34
1

You could try to use Component.paintAll.

You could also pass a reference to a Graphics object (coming from your buffered image) to SwingUtilities.paintComponent.

aioobe
  • 413,195
  • 112
  • 811
  • 826
  • I'm with you that the intention of the Q has not been clarified. It would have been nice if you had mentioned the particular use case for which your answer is suitable. – class stacker May 11 '15 at 08:45