首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 屏幕截圖實戰:三種核心方案完整代碼詳解

     編輯:Java 相關知識

前言

Java 實現屏幕截圖主要依賴 java.awt.Robot 類的 createScreenCapture() 方法。本文提供三種遞進方案:基礎全屏截圖、Swing 交互式區域截圖、完整桌面級截圖工具,涵蓋從單行代碼到生產級應用的完整演進。

核心 API 基礎


// 核心三行代碼
Robot robot = new Robot();
Rectangle screenRect = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
BufferedImage image = robot.createScreenCapture(screenRect);

方案一:基礎全屏截圖保存(適合自動化測試、定時任務)

import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;

public class SimpleScreenCapture {
    public static void captureFullScreen(String savePath) throws Exception {
        // 1. 獲取屏幕尺寸
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        Rectangle screenRect = new Rectangle(screenSize);
        
        // 2. 截圖
        Robot robot = new Robot();
        BufferedImage image = robot.createScreenCapture(screenRect);
        
        // 3. 保存為 PNG
        File outputFile = new File(savePath);
        ImageIO.write(image, "png", outputFile);
        System.out.println("截圖已保存至:" + outputFile.getAbsolutePath());
    }
    
    public static void main(String[] args) {
        try {
            captureFullScreen("screenshot_" + System.currentTimeMillis() + ".png");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

方案二:Swing 交互式矩形區域截圖(適合桌面應用集成)

核心思路:全屏截圖 → 顯示於無邊框 JDialog → 滑鼠拖拽選區 → 截取子圖 → 返回。

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import java.io.File;

public class RegionCaptureTool {
    private final Robot robot;
    private final JDialog dialog;
    private final JLabel imageLabel;
    private BufferedImage fullScreenImage;
    private BufferedImage pickedImage;
    
    // 選區座標
    private int x1, y1, x2, y2;
    private boolean isFirstPoint = true;

    public RegionCaptureTool() throws AWTException {
        robot = new Robot();
        
        // 無邊框、全屏、置頂對話框
        dialog = new JDialog();
        dialog.setUndecorated(true);
        dialog.setAlwaysOnTop(true);
        dialog.setModal(true);
        dialog.setSize(Toolkit.getDefaultToolkit().getScreenSize());
        dialog.setLocation(0, 0);
        dialog.setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
        
        imageLabel = new JLabel() {
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                if (fullScreenImage != null) {
                    g.drawImage(fullScreenImage, 0, 0, null);
                }
                // 繪製選區矩形
                if (x2 > x1 && y2 > y1) {
                    g.setColor(Color.RED);
                    g.drawRect(x1, y1, x2 - x1, y2 - y1);
                }
                // 繪製十字光標
                g.setColor(Color.CYAN);
                g.drawLine(x1, 0, x1, getHeight());
                g.drawLine(0, y1, getWidth(), y1);
            }
        };
        
        imageLabel.addMouseListener(new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent e) {
                x1 = x2 = e.getX();
                y1 = y2 = e.getY();
                isFirstPoint = false;
            }
            @Override
            public void mouseReleased(MouseEvent e) {
                // 確認選區,截取子圖
                int minX = Math.min(x1, x2), minY = Math.min(y1, y2);
                int w = Math.abs(x2 - x1), h = Math.abs(y2 - y1);
                if (w > 5 && h > 5) { // 忽略點擊
                    pickedImage = fullScreenImage.getSubimage(minX, minY, w, h);
                }
                dialog.setVisible(false);
                dialog.dispose();
            }
        });
        
        imageLabel.addMouseMotionListener(new MouseMotionAdapter() {
            @Override
            public void mouseDragged(MouseEvent e) {
                x2 = e.getX(); y2 = e.getY();
                imageLabel.repaint();
            }
            @Override
            public void mouseMoved(MouseEvent e) {
                x1 = x2 = e.getX(); y1 = y2 = e.getY();
                imageLabel.repaint();
            }
        });
        
        dialog.add(imageLabel);
    }
    
    public BufferedImage capture() {
        // 1. 截全屏
        fullScreenImage = robot.createScreenCapture(
            new Rectangle(Toolkit.getDefaultToolkit().getScreenSize())
        );
        imageLabel.setIcon(new ImageIcon(fullScreenImage));
        x1 = y1 = x2 = y2 = 0;
        isFirstPoint = true;
        
        // 2. 顯示對話框等待用戶選區
        dialog.setVisible(true);
        
        return pickedImage; // 可能為 null(用戶取消或點擊)
    }
    
    public void save(BufferedImage img, File file) throws Exception {
        if (img != null) ImageIO.write(img, "png", file);
    }
    
    // 測試主程式
    public static void main(String[] args) {
        try {
            RegionCaptureTool tool = new RegionCaptureTool();
            BufferedImage img = tool.capture();
            if (img != null) {
                tool.save(img, new File("region_capture.png"));
                System.out.println("區域截圖完成");
            } else {
                System.out.println("用戶取消截圖");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

方案三:生產級桌面截圖工具(含工具欄、多圖管理、系統托盤、剪貼板)

完整代碼較長(約 400 行),此處給出核心架構與關鍵模組,完整可運行版本請參考附件或 GitHub 同款開源項目 java-screen-captor。

核心功能模組

模組關鍵技術點
系統托盤SystemTray + TrayIcon + PopupMenu,支援最小化到托盤、右鍵菜單操作
多圖管理JTabbedPane + 自定義 PicPanel,每張圖獨立標籤頁,含保存/複製/關閉按鈕
區域選取無邊框 JFrame 全屏覆蓋 + MouseListener/MotionListener 繪製選區、八向縮放手柄
圖片持久化ImageIO.write 支援 PNG/JPG/BMP/GIF,JFileChooser + FileFilter 選擇格式
剪貼板Toolkit.getSystemClipboard().setContents(Transferable),實現 DataFlavor.imageFlavor
批量保存SwingWorker 後台線程 + JProgressBar 顯示進度,避免阻塞 EDT
外觀切換UIManager.setLookAndFeel 切換 System/CrossPlatform L&F

關鍵代碼片段:剪貼板圖片寫入


public void copyToClipboard(BufferedImage image) {
    Transferable trans = new Transferable() {
        @Override public DataFlavor[] getTransferDataFlavors() {
            return new DataFlavor[] { DataFlavor.imageFlavor };
        }
        @Override public boolean isDataFlavorSupported(DataFlavor flavor) {
            return DataFlavor.imageFlavor.equals(flavor);
        }
        @Override public Object getTransferData(DataFlavor flavor) 
                throws UnsupportedFlavorException, IOException {
            if (isDataFlavorSupported(flavor)) return image;
            throw new UnsupportedFlavorException(flavor);
        }
    };
    Toolkit.getDefaultToolkit().getSystemClipboard().setContents(trans, null);
}

關鍵代碼片段:八向縮放手柄邏輯


enum ResizeDir {
    NW(Cursor.NW_RESIZE_CURSOR), N(Cursor.N_RESIZE_CURSOR), NE(Cursor.NE_RESIZE_CURSOR),
    E(Cursor.E_RESIZE_CURSOR), SE(Cursor.SE_RESIZE_CURSOR), S(Cursor.S_RESIZE_CURSOR),
    SW(Cursor.SW_RESIZE_CURSOR), W(Cursor.W_RESIZE_CURSOR),
    MOVE(Cursor.MOVE_CURSOR), DEFAULT(Cursor.DEFAULT_CURSOR);
    final Cursor cursor;
    ResizeDir(int cursorType) { this.cursor = Cursor.getPredefinedCursor(cursorType); }
}

// 在 mouseMoved 中判斷滑鼠落在哪個手柄矩形,設置對應游標與 resize 方向
// mouseDragged 中根據方向修改 x1/y1/x2/y2,repaint()

常見坑與避坑指南

  1. 多屏幕環境: Toolkit.getScreenSize() 僅返回主屏尺寸。多屏需用 GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices() 遍歷合併邊界。
  2. 高 DPI 縮放: Windows 縮放 150% 時,Robot 截圖可能模糊。需 JVM 參數 -Dsun.java2d.uiScale.enabled=true 或配置 dpiAware 清單。
  3. Headless 環境: 服務器無顯示器會拋 HeadlessException。需安裝 Xvfb 或使用 X11 虛擬顯示器。
  4. 權限問題: macOS 需在「系統偏好設定 → 安全性與隱私 → 輔助功能」授權 Java/IDE;Linux Wayland 下 Robot 可能失效,需 X11 會話。
  5. 記憶體洩漏: 大量截圖未及時 flush() 或 dispose() 會導致 Heap OOM。用完即釋放:image.flush()。

總結與選型建議

場景推薦方案關鍵類
自動化測試、定時截圖、無 UI方案一Robot + ImageIO
桌面應用集成「選區截圖」方案二Robot + JDialog + MouseListener
獨立截圖工具、需托盤、多圖、剪貼板方案三完整 Swing 應用架構

掌握 Robot.createScreenCapture() 核心 API,配合 Swing 事件模型與圖片 I/O,即可構建從簡單到專業的 Java 截圖解決方案。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved