Create an image from a non-visible AWT Component?

后端 未结 5 598
迷失自我
迷失自我 2020-12-16 11:15

I\'m trying to create an image (screen-shot) of a non-visible AWT component. I can\'t use the Robot classes\' screen capture functionality because the component

5条回答
  •  情歌与酒
    2020-12-16 11:55

    Component has a method paintAll(Graphics) (as you already have found). That method will paint itself on the passed graphics. But we have to pre-configure the graphics before we call 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)
    {
        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);
        g.dispose();
        if (region == null)
        {
            return img;
        }
        return img.getSubimage(region.x, region.y, region.width, region.height);
    }
    

    This is also the better way instead of using Robot for the visible components.


    EDIT:

    A long time ago I used the code I posted here above, and it worked, but now not. So I searched further. I have a tested, working way. It is dirty, but works. The Idea of it is making a JDialog, put it somewhere out of the Screen bounds, set it visible, and then draw it on the graphics.

    Here is the code:

    public static BufferedImage componentToImageWithSwing(Component component, Rectangle region) {
        BufferedImage img = new BufferedImage(component.getWidth(), component.getHeight(), BufferedImage.TYPE_INT_RGB);
        Graphics g = img.createGraphics();
    
        // Real render
        if (component.getPreferredSize().height == 0 && component.getPreferredSize().width == 0)
        {
            component.setPreferredSize(component.getSize());
        }
    
        JDialog f = new JDialog();
        JPanel p = new JPanel();
        p.add(component);
        f.add(p);
        f.pack();
        f.setLocation(-f.getWidth() - 10, -f.getHeight() -10);
        f.setVisible(true);
        p.paintAll(g);
        f.dispose();
        // ---
    
        g.dispose();
        if (region == null) {
            return img;
        }
        return img.getSubimage(region.x, region.y, region.width, region.height);
    }
    

    So, this will work also on Windows and Mac. The other answer was to draw it on a virtual screen. But this doesn't need it.

提交回复
热议问题