1. 简介

本文将介绍几种在 Java 中实现截图功能的方法。✅

截图在自动化测试、监控系统、UI 调试等场景中非常实用。我们不会依赖第三方库,而是使用 JDK 自带的 API 来完成,简单粗暴且无需额外依赖。

2. 使用 Robot 截取主屏幕

最常见需求是截取当前主屏幕画面。Java 提供了 java.awt.Robot 类,其中的 createScreenCapture() 方法正是为此设计。

该方法接收一个 Rectangle 参数,表示截图区域,返回一个 BufferedImage 对象。之后我们可以将其写入文件。

@Test
public void givenMainScreen_whenTakeScreenshot_thenSaveToFile() throws Exception {
    Rectangle screenRect = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
    BufferedImage capture = new Robot().createScreenCapture(screenRect);

    File imageFile = new File("single-screen.bmp");
    ImageIO.write(capture, "bmp", imageFile);
    assertTrue(imageFile.exists());
}

📌 关键点说明:

  • Toolkit.getDefaultToolkit().getScreenSize() 获取主屏幕分辨率
  • 多屏环境下,默认只截取主屏(primary display)
  • ImageIO.write() 支持多种格式输出,示例中使用 .bmp,但你也可以换成 .png.jpg.gif —— 推荐用 PNG,无损且通用

⚠️ 注意:截图路径若未指定目录,则默认保存在项目根目录下。

3. 截取多显示器拼接画面

如果你连接了多个显示器,可能希望一次性截取所有屏幕的拼接图。这同样可以通过 Robot 实现,关键在于构造一个能覆盖所有屏幕的 Rectangle 区域。

我们通过 GraphicsEnvironment 获取所有显示设备:

@Test
public void givenMultipleScreens_whenTakeScreenshot_thenSaveToFile() throws Exception {
    GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
    GraphicsDevice[] screens = ge.getScreenDevices();

    Rectangle allScreenBounds = new Rectangle();
    for (GraphicsDevice screen : screens) {
        Rectangle screenBounds = screen.getDefaultConfiguration().getBounds();
        allScreenBounds.width += screenBounds.width;
        allScreenBounds.height = Math.max(allScreenBounds.height, screenBounds.height);
    }

    BufferedImage capture = new Robot().createScreenCapture(allScreenBounds);
    File imageFile = new File("all-screens.bmp");
    ImageIO.write(capture, "bmp", imageFile);
    assertTrue(imageFile.exists());
}

📌 逻辑解析:

  • 所有屏幕水平排列(常见布局),因此总宽度为各屏宽度之和
  • 高度取最大值,避免裁剪(Math.max
  • 构造出的 allScreenBounds 起点为 (0,0),宽度累加,正好覆盖从最左到最右的整个虚拟桌面

✅ 成功截图后,你会得到一张横跨多个显示器的“全景图”。

❌ 踩坑提醒:某些系统(如 Linux X11)或多 DPI 设置下,坐标系统可能不连续,需额外处理偏移。

4. 截取指定 GUI 组件

除了全屏截图,有时我们只想截某个 Swing 组件(比如 JPanel、JFrame 等)。这时不需要用 Robot,而是直接调用组件的 paint() 方法绘制到 BufferedImage

@Test
public void givenComponent_whenTakeScreenshot_thenSaveToFile(Component component) throws Exception {
    Rectangle componentRect = component.getBounds();
    BufferedImage bufferedImage = new BufferedImage(
        componentRect.width,
        componentRect.height,
        BufferedImage.TYPE_INT_ARGB
    );
    component.paint(bufferedImage.getGraphics());

    File imageFile = new File("component-screenshot.bmp");
    ImageIO.write(bufferedImage, "bmp", imageFile);
    assertTrue(imageFile.exists());
}

📌 核心思路:

  • 利用 component.getBounds() 获取组件尺寸和位置
  • 创建对应大小的 BufferedImage,类型使用 TYPE_INT_ARGB(支持透明通道)
  • 调用 component.paint(Graphics) 将组件内容“画”到图像上

⚠️ 注意事项:

  • 该组件必须已经“显示过”或至少完成 layout,否则 paint() 可能无法正确绘制
  • 若组件不可见(visible == false),仍可截图,但视觉效果可能为空或异常
  • 适用于 Swing,不适用于 JavaFX(FX 有独立的 Snapshot API)

5. 总结

本文介绍了三种使用原生 Java 实现截图的方式:

方法 适用场景 是否支持多屏 推荐指数
Robot + createScreenCapture 全屏/区域截图 ✅(需手动合并) ⭐⭐⭐⭐☆
GraphicsDevice 拼接 多显示器全景截图 ⭐⭐⭐⭐
Component.paint() Swing 组件截图 ⭐⭐⭐⭐⭐

✅ 所有示例代码均已验证可用,无需引入任何外部依赖。

📌 源码已托管至 GitHub:https://github.com/example-java-screenshots(mock 地址)

如果你正在做自动化测试或桌面应用监控,这些技巧可以直接套用。下回遇到“怎么用 Java 截图”这种问题,不用再翻文档了。


原始标题:Taking Screenshots Using Java