Java 是否从不可见的AWT组件创建图像?
我正在尝试创建一个不可见AWT组件的图像(屏幕截图)。我无法使用Java 是否从不可见的AWT组件创建图像?,java,graphics,awt,bufferedimage,Java,Graphics,Awt,Bufferedimage,我正在尝试创建一个不可见AWT组件的图像(屏幕截图)。我无法使用Robotclasses的屏幕捕获功能,因为该组件在屏幕上不可见。正在尝试使用以下代码: BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); Graphics2D g = image.createGraphics(); component.paintAll(g); 有时可以工作,但如果组件包含文本框、按钮或某种Ope
Robot
classes的屏幕捕获功能,因为该组件在屏幕上不可见。正在尝试使用以下代码:
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D g = image.createGraphics();
component.paintAll(g);
有时可以工作,但如果组件包含文本框、按钮或某种OpenGL/3D组件(这些内容不在图像中!),则无法工作。如何拍摄整个过程的正确屏幕截图?本课程展示了如何对Swing组件进行截图。我从未尝试过AWT组件,但我可以猜到它的概念是一样的。
组件
有一个方法paintAll(Graphics)
(正如您已经发现的那样)。该方法将在传递的图形上绘制自身。但是在调用绘制方法之前,我们必须预先配置图形。这就是我在以下位置发现的有关AWT组件渲染的内容:
当AWT调用此方法时
图形对象参数为
使用适当的
说明如何利用这一特殊情况
组成部分:
- 图形对象的颜色设置为组件的前景属性
- 图形对象的字体设置为组件的字体属性
- 图形对象的平移设置为坐标(0,0)表示组件的左上角
- 图形对象的剪辑矩形设置为需要重新绘制的组件区域
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);
}
对于可见组件,这也是一种更好的方法,而不是使用Robot
编辑: 很久以前,我使用了我在上面发布的代码,它工作了,但现在不行了。所以我进一步搜索。我有一种经过测试的工作方式。它很脏,但能用。它的想法是制作一个JDialog,将它放在屏幕边界之外的某个地方,将它设置为可见,然后在图形上绘制它 代码如下:
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);
}
因此,这也适用于Windows和Mac。另一个答案是在虚拟屏幕上绘制。但是这不需要它。像这样的东西怎么样。容纳所有组件的JFrame不可见
导入java.awt.Color;
导入java.awt.Component;
导入java.awt.Container;
导入java.awt.Dimension;
导入java.awt.Graphics2D;
导入java.awt.Rectangle;
导入java.awt.image.buffereImage;
导入java.io.File;
导入java.io.IOException;
导入java.util.array;
导入java.util.List;
导入java.util.logging.Level;
导入java.util.logging.Logger;
导入javax.imageio.imageio;
导入javax.swing.JButton;
导入javax.swing.JComponent;
导入javax.swing.JFrame;
导入javax.swing.JPanel;
导入javax.swing.JTextArea
/**
*捕获不可见的awt组件
*@author-dvargo
*/
公共类截图
{
private static List types=Arrays.asList(ImageIO.getWriterFileSuffix());
/**
*构建GUI
*@param args
*/
公共静态void main(字符串[]args)
{
JFrame InvisibleName=新JFrame();
InvisibleName.setSize(300300);
JPanel colorPanel=新的JPanel();
彩色面板。背景(颜色。红色);
colorPanel.setSize(InvisibleName.getSize());
JTextArea textBox=新的JTextArea(“这里有一些文本”);
colorPanel.add(文本框);
添加(彩色面板);
JButton theButton=新JButton(“单击我”);
颜色面板。添加(按钮);
按钮。设置可见(真);
textBox.setVisible(true);
colorPanel.setVisible(真);
//截屏
尝试
{
BuffereImage屏幕截图=createImage((JComponent)colorPanel,新矩形(InvisibleName.getBounds());
writeImage(屏幕截图,“文件路径”);
}
捕获(IOEX异常)
{
Logger.getLogger(screenscapture.class.getName()).log(Level.SEVERE,null,ex);
}
}
/**
*为Swing组件创建缓冲区映像。
*可以将组件的全部或部分捕获到图像中。
*
*@param component用于创建图像的组件
*@param region要捕捉到图像的组件区域
*@returnimage指定区域的图像
*/
公共静态缓冲区图像createImage(组件,矩形区域){
//确保组件有一个尺寸,并且已经布置好。
//(对未添加到已实现框架的组件进行必要检查)
如果(!component.isDisplayable()){
维度d=组件.getSize();
如果(d.width==0 | | d.height==0){
d=组件。getPreferredSize();
组件。设置大小(d);
}
布局组件(组件);
}
BuffereImage=新的BuffereImage(region.width、region.height、BuffereImage.TYPE_INT_RGB);
Graphics2D g2d=image.createGraphics();
//为非不透明组件绘制背景,
//否则背景将为黑色
如果(!component.isOpaque()){
g2d.setColor(component.getBackground());
g2d.fillRect(region.x,region.y,region.width,region.height);
}
平移(-region.x,-region.y);
成分油漆(g2d);
g2d.dispose();
返回图像;
}
公共静态无效布局组件(组件组件){
已同步(component.getTreeLock()){
component.doLayout();
if(容器的组件实例){
对于(组件子组件:((容器)组件).getComponents()){
布局组件(子组件);
}
}
}
}
/**
*将BuffereImage写入文件。
*
*@param image要写入的图像
*@param fileName要创建的文件的名称
*@exception IOException如果在写入过程中发生错误
*/
公共静态void writeImage(BuffereImage图像,字符串文件名)
抛出IOException
{
如果(fileName==null)返回;
int offset=fileName.lastIndexOf(“.”);
如果(偏移量==-1)
{
字符串消息
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
/**
* Captures an invisible awt component
* @author dvargo
*/
public class ScreenCapture
{
private static List<String> types = Arrays.asList( ImageIO.getWriterFileSuffixes() );
/**
* Build GUI
* @param args
*/
public static void main(String [] args)
{
JFrame invisibleFrame = new JFrame();
invisibleFrame.setSize(300, 300);
JPanel colorPanel = new JPanel();
colorPanel.setBackground(Color.red);
colorPanel.setSize(invisibleFrame.getSize());
JTextArea textBox = new JTextArea("Here is some text");
colorPanel.add(textBox);
invisibleFrame.add(colorPanel);
JButton theButton = new JButton("Click Me");
colorPanel.add(theButton);
theButton.setVisible(true);
textBox.setVisible(true);
colorPanel.setVisible(true);
//take screen shot
try
{
BufferedImage screenShot = createImage((JComponent) colorPanel, new Rectangle(invisibleFrame.getBounds()));
writeImage(screenShot, "filePath");
}
catch (IOException ex)
{
Logger.getLogger(ScreenCapture.class.getName()).log(Level.SEVERE, null, ex);
}
}
/**
* Create a BufferedImage for Swing components.
* All or part of the component can be captured to an image.
*
* @param component component to create image from
* @param region The region of the component to be captured to an image
* @return image the image for the given region
*/
public static BufferedImage createImage(Component component, Rectangle region) {
// Make sure the component has a size and has been layed out.
// (necessary check for components not added to a realized frame)
if (!component.isDisplayable()) {
Dimension d = component.getSize();
if (d.width == 0 || d.height == 0) {
d = component.getPreferredSize();
component.setSize(d);
}
layoutComponent(component);
}
BufferedImage image = new BufferedImage(region.width, region.height, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = image.createGraphics();
// Paint a background for non-opaque components,
// otherwise the background will be black
if (!component.isOpaque()) {
g2d.setColor(component.getBackground());
g2d.fillRect(region.x, region.y, region.width, region.height);
}
g2d.translate(-region.x, -region.y);
component.paint(g2d);
g2d.dispose();
return image;
}
public static void layoutComponent(Component component) {
synchronized (component.getTreeLock()) {
component.doLayout();
if (component instanceof Container) {
for (Component child : ((Container) component).getComponents()) {
layoutComponent(child);
}
}
}
}
/**
* Write a BufferedImage to a File.
*
* @param image image to be written
* @param fileName name of file to be created
* @exception IOException if an error occurs during writing
*/
public static void writeImage(BufferedImage image, String fileName)
throws IOException
{
if (fileName == null) return;
int offset = fileName.lastIndexOf( "." );
if (offset == -1)
{
String message = "file suffix was not specified";
throw new IOException( message );
}
String type = fileName.substring(offset + 1);
if (types.contains(type))
{
ImageIO.write(image, type, new File( fileName ));
}
else
{
String message = "unknown writer file suffix (" + type + ")";
throw new IOException( message );
}
}
import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class ComponentPainter {
public static BufferedImage paintComponent(Component c) {
// Set it to it's preferred size. (optional)
c.setSize(c.getPreferredSize());
layoutComponent(c);
BufferedImage img = new BufferedImage(c.getWidth(), c.getHeight(),
BufferedImage.TYPE_INT_RGB);
CellRendererPane crp = new CellRendererPane();
crp.add(c);
crp.paintComponent(img.createGraphics(), c, crp, c.getBounds());
return img;
}
// from the example of user489041
public static void layoutComponent(Component c) {
synchronized (c.getTreeLock()) {
c.doLayout();
if (c instanceof Container)
for (Component child : ((Container) c).getComponents())
layoutComponent(child);
}
}
}
JPanel p = new JPanel();
p.add(new JButton("Button 1"));
p.add(new JButton("Button 2"));
p.add(new JCheckBox("A checkbox"));
JPanel inner = new JPanel();
inner.setBorder(BorderFactory.createTitledBorder("A border"));
inner.add(new JLabel("Some label"));
p.add(inner);
BufferedImage img = ComponentPainter.paintComponent(p);
ImageIO.write(img, "png", new File("test.png"));
Xvfb :1 &
DISPLAY=:1 java YourMainClass
xwd -display :1 -root -out image.xwd