2025-01-23 18:43:44 +08:00

85 lines
2.2 KiB
JavaScript

const { initCDP, cleanupCDP } = require("./cdp");
const { searchTarget } = require("./tabs");
const fs = require("fs");
// 捕获标签页截图
const captureScreenshot = async (tab, options = {}) => {
const target = await searchTarget(tab);
const { format = "png", quality = 100, savePath, selector = null } = options;
try {
const { Page, DOM } = await initCDP(target.id);
await DOM.enable();
let clip = null;
if (selector) {
// 获取DOM节点
const { root } = await DOM.getDocument();
const { nodeId } = await DOM.querySelector({
nodeId: root.nodeId,
selector: selector,
});
if (!nodeId) {
throw new Error(`未找到元素: ${selector}`);
}
// 获取元素的精确四边形坐标
const { quads } = await DOM.getContentQuads({ nodeId });
if (!quads || quads.length === 0) {
throw new Error("无法获取元素位置信息");
}
// 获取布局指标
const { visualViewport } = await Page.getLayoutMetrics();
const { pageX, pageY } = visualViewport;
// 计算边界框
const quad = quads[0];
const x = Math.min(quad[0], quad[2], quad[4], quad[6]);
const y = Math.min(quad[1], quad[3], quad[5], quad[7]);
const width = Math.max(quad[0], quad[2], quad[4], quad[6]) - x;
const height = Math.max(quad[1], quad[3], quad[5], quad[7]) - y;
clip = {
x: Math.round(x - pageX),
y: Math.round(y - pageY),
width: Math.round(width),
height: Math.round(height),
scale: 1,
};
// 确保尺寸不为0
if (clip.width === 0) clip.width = 1;
if (clip.height === 0) clip.height = 1;
}
const screenshotParams = {
format,
quality: format === "jpeg" ? quality : undefined,
fromSurface: true,
captureBeyondViewport: !!selector,
};
if (clip) {
screenshotParams.clip = clip;
}
const { data } = await Page.captureScreenshot(screenshotParams);
await DOM.disable();
if (savePath) {
fs.writeFileSync(savePath, data, "base64");
}
return data;
} finally {
await cleanupCDP(target.id);
}
};
module.exports = {
captureScreenshot,
};