Java实现url页面截图功能(windows)

Java实现url页面截图功能~目前实现了windows、linux(centos7)版本,谷歌浏览器需要下载90.x版本,目前暂时没找到安装包

代码

package com.ruoyi.school.util;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.Base64;

public class ChromeScreenshotUtil {
    private static final String CHROME_PATH = "C:/Program Files/Google/Chrome/Application/chrome.exe";
    private static final String TEMP_SCREENSHOT_DIR = "D:/project/uploadFile";

    static {
        // 初始化检查
        File chromeFile = new File(CHROME_PATH);
        if (!chromeFile.exists()) {
            throw new RuntimeException("Chrome未找到:" + CHROME_PATH);
        }
        File dir = new File(TEMP_SCREENSHOT_DIR);
        if (!dir.exists() && !dir.mkdirs()) {
            throw new RuntimeException("无法创建临时目录:" + TEMP_SCREENSHOT_DIR);
        }
    }

    public String captureScreenshotAsBase64(String url) throws IOException, InterruptedException {
        return captureScreenshotAsBase64(url, 1200, 2000, 10000);
    }

    public String captureScreenshotAsBase64(String url, int width, int height, int delay) throws IOException, InterruptedException {
        String fileName = "temp_screenshot_" + System.currentTimeMillis() + ".png";
        File tempFile = new File(TEMP_SCREENSHOT_DIR, fileName);
        String outputPath = tempFile.getAbsolutePath();

        try {
            // 执行Chrome截图(省略,同之前)
            ProcessBuilder processBuilder = new ProcessBuilder(
                    CHROME_PATH,
                    "--headless",
                    "--disable-gpu",
                    "--no-sandbox",
                    "--window-size=" + width + "," + height,
                    "--virtual-time-budget=" + delay,
                    "--screenshot=" + outputPath,
                    url
            );
            processBuilder.directory(new File(CHROME_PATH).getParentFile());
            Process process = processBuilder.start();
            captureStream(process.getInputStream(), "输出");
            captureStream(process.getErrorStream(), "错误");
            int exitCode = process.waitFor(60, java.util.concurrent.TimeUnit.SECONDS) ? process.exitValue() : -1;
            if (exitCode != 0) {
                throw new RuntimeException("Chrome退出码:" + exitCode);
            }

            // 等待文件生成
            int retryCount = 0;
            while (retryCount < 5) {
                if (tempFile.exists() && tempFile.length() > 0) {
                    Thread.sleep(2000);
                    break;
                }
                Thread.sleep(1000);
                retryCount++;
            }
            if (retryCount >= 5 || !tempFile.exists() || tempFile.length() == 0) {
                throw new RuntimeException("图片未生成:" + outputPath);
            }

            // 关键:读取字节并验证
            byte[] imageBytes = readFileToBytes(tempFile);
            // 验证PNG头(前8字节必须为89 50 4E 47 0D 0A 1A 0A)
            if (imageBytes.length < 8) {
                throw new RuntimeException("字节数组过短,不是有效的PNG");
            }
            byte[] pngHeader = new byte[]{(byte)0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A};
            for (int i = 0; i < 8; i++) {
                if (imageBytes[i] != pngHeader[i]) {
                    throw new RuntimeException("PNG头验证失败,第" + i + "字节应为" + String.format("%02X", pngHeader[i]) + ",实际为" + String.format("%02X", imageBytes[i]));
                }
            }
            // 生成Base64
            String base64Str = Base64.getEncoder().encodeToString(imageBytes);
            String result = "data:image/png;base64," + base64Str;
            return result;
        } finally {
            // 保留文件用于手动验证
             tempFile.delete();
        }
    }

    // 循环读取字节,确保完整
    private byte[] readFileToBytes(File file) throws IOException {
        if (!file.exists()) {
            throw new FileNotFoundException("文件不存在:" + file.getAbsolutePath());
        }
        if (file.length() == 0) {
            throw new IOException("文件为空");
        }

        try (InputStream is = new FileInputStream(file);
             ByteArrayOutputStream bos = new ByteArrayOutputStream()) {

            byte[] buffer = new byte[4096];
            int bytesRead;
            while ((bytesRead = is.read(buffer)) != -1) {
                bos.write(buffer, 0, bytesRead);
            }
            bos.flush();

            byte[] result = bos.toByteArray();
            if (result.length != file.length()) {
                throw new IOException("读取不完整:文件大小=" + file.length() + ",读取大小=" + result.length);
            }
            return result;
        }
    }

    private void captureStream(InputStream is, String type) {
        new Thread(() -> {
            try (BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) {
                String line;
                while ((line = br.readLine()) != null) {
                    System.out.println("[Chrome" + type + "] " + line);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }).start();
    }

    public static void main(String[] args) {
        try {
            String url = "http://192.168.110.175:8083/#/";
            String base64 = new ChromeScreenshotUtil().captureScreenshotAsBase64(url);
            System.out.println(base64);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
posted @ 2025-08-21 17:46  青喺半掩眉砂  阅读(22)  评论(0)    收藏  举报