我想在无头模式(屏幕上根本没有图形用户界面)下将JPanel绘制到BufferedImage中。
final JPanel panel = createPanel();
panel.setSize(panel.getPreferredSize());
panel.validate();
// JFrame frame = new JFrame();
// frame.getContentPane().add(panel);
// frame.pack();
// frame.setVisible(true);
final BufferedImage image = new BufferedImage(
panel.getBounds().width,
panel.getBounds().height,
BufferedImage.TYPE_INT_ARGB
);
final Graphics2D gc = image.createGraphics();
gc.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
gc.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
try {
panel.paint(gc);
...save the image somewhere...
} finally {
gc.dispose();
}但我总是得到空图像,直到我将面板放入一个重量级组件并将其显示在屏幕上(请参阅注释代码)。我不想展示它,这个应用程序在服务器上运行。
以下是SSCCE:
public class Example {
private static JPanel createPanel() {
final JPanel panel = new JPanel(new GridBagLayout());
final JLabel label = new JLabel("Yeah, it's working!", SwingConstants.CENTER);
label.setFont(new Font("Arial", Font.PLAIN, 12));
final GridBagConstraints constraints = new GridBagConstraints();
constraints.fill = GridBagConstraints.BOTH;
constraints.weightx = 1;
constraints.weightx = 1;
panel.add(label, constraints);
return panel;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
final JPanel panel = createPanel();
panel.setSize(panel.getPreferredSize());
panel.validate();
// JFrame frame = new JFrame();
// frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// frame.getContentPane().add(panel);
// frame.pack();
// frame.setVisible(true);
final BufferedImage image = new BufferedImage(
panel.getBounds().width,
panel.getBounds().height,
BufferedImage.TYPE_INT_ARGB
);
final Graphics2D gc = image.createGraphics();
gc.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
gc.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
try {
panel.paint(gc);
ImageIO.write(image, "png", new File("image.png"));
} catch (IOException e) {
e.printStackTrace();
} finally {
gc.dispose();
}
}
});
}
}发布于 2013-06-10 23:13:09
在实现组件之前,组件的大小为零,因此绘制方法不起作用。
查看Screen Image。它将通过调用面板上的doLayout()来为您处理此问题,以确保所有组件都具有有效的大小。
发布于 2013-06-10 23:29:23
下面是一个代码片段,它将一个简单的标签绘制到一个图像文件中,然后打开该图像文件(如果是在台式计算机上)。
import java.awt.Desktop;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JLabel;
public class Test {
public static void main(String[] args) throws IOException {
JLabel label = new JLabel("Hello world");
label.setSize(label.getPreferredSize());
BufferedImage image = new BufferedImage(label.getWidth(), label.getHeight(), BufferedImage.TYPE_INT_ARGB);
label.paint(image.getGraphics());
File output = new File("C:\\test\\hello world.png");
if (!output.getParentFile().exists()) {
output.getParentFile().mkdirs();
}
ImageIO.write(image, "png", output);
Desktop.getDesktop().open(output);
}
}编辑(使用您的SSCCE):
不要在你的面板上调用validate()而是doLayout() (如果你有嵌套的面板,确保递归地调用它):
import java.awt.Desktop;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
public class Example {
private static JLabel label;
private static JPanel createPanel() {
final JPanel panel = new JPanel(new GridBagLayout());
label = new JLabel("Yeah, it's working!", SwingConstants.CENTER);
label.setFont(new Font("Arial", Font.PLAIN, 12));
final GridBagConstraints constraints = new GridBagConstraints();
constraints.fill = GridBagConstraints.BOTH;
constraints.weightx = 1;
constraints.weightx = 1;
panel.add(label, constraints);
return panel;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
final JPanel panel = createPanel();
panel.setSize(panel.getPreferredSize());
panel.doLayout();
System.err.println(label.getSize() + "");
// JFrame frame = new JFrame();
// frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// frame.getContentPane().add(panel);
// frame.pack();
// frame.setVisible(true);
final BufferedImage image = new BufferedImage(panel.getBounds().width, panel.getBounds().height,
BufferedImage.TYPE_INT_ARGB);
final Graphics2D gc = image.createGraphics();
gc.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
gc.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
try {
panel.paint(gc);
File output = new File("image.png");
ImageIO.write(image, "png", output);
Desktop.getDesktop().open(output);
} catch (IOException e) {
e.printStackTrace();
} finally {
gc.dispose();
}
}
});
}
}发布于 2017-08-30 22:42:07
在您试图打印/绘制的根组件上调用addNotify也可以解决这个问题。问题的症结似乎在于,除非容器有一个“同级”,否则验证调用短路。调用addNotify会初始化对等体,从而允许后续对Component.validate的调用像在非headless场景中那样正常工作。
将此作为替代解决方案提交,因为在组件嵌套更深的情况下,调用doLayout将不起作用,这是因为doLayout没有布局子组件。(尽管camickr的答案中提到的ScreenImage类通过递归调用doLayout来解决这个问题。)
https://stackoverflow.com/questions/17026803
复制相似问题