浏览器扩展截图
content js
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
console.log('got message: ', message)
if (message.type === 'get_slider_position') {
// 获取滑块元素(需替换为实际选择器)
const slider = document.querySelector('.tc-slider-normal');
let rect = slider.getBoundingClientRect();
sendResponse({rect})
} else if (message.type === 'get_captcha_position') {
console.log('got message: ', 'get_captcha_position')
// 获取滑块元素(需替换为实际选择器)
const slider = document.querySelector('#slideBg');
let rect = slider.getBoundingClientRect();
sendResponse({rect})
} else if (message.type === 'devicePixelRatio') {
console.log('devicePixelRatio', window.devicePixelRatio)
sendResponse({devicePixelRatio: window.devicePixelRatio});
}
});
background js
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
console.log('got message: ', message)
if (message.type === 'TAKE_ELEMENT_SCREENSHOT') {
get_captcha_screen(message, sender, sendResponse)
return true
} else if (message.type === 'download_image') {
chrome.downloads.download(message.data);
}
});
const get_captcha_screen = (message, sender, sendResponse) => {
// 获取当前标签页的 windowId
const windowId = sender.tab.windowId;
chrome.tabs.captureVisibleTab(windowId, {format: 'png'}, async (dataUrl) => {
if (chrome.runtime.lastError) {
console.error(chrome.runtime.lastError.message);
return;
}
// chrome.downloads.download({
// url: dataUrl,
// filename: 'page.png'
// });
try {
// 将 dataUrl 转为 Blob 并创建 ImageBitmap 便于裁剪
const blob = await fetch(dataUrl).then(r => r.blob());
const imageBitmap = await createImageBitmap(blob);
const rect = message.rect
console.log('rect', rect)
let iframe = await get_element_position(sender.tab.id, 'iframe').then(result => result.rect)
console.log('iframe', iframe)
// 创建 OffscreenCanvas,其尺寸与目标元素一致
// const canvas = new OffscreenCanvas(iframe.width, iframe.height);
const radio = await chrome.tabs.sendMessage(sender.tab.id, {type: "devicePixelRatio"}).then(r => r.devicePixelRatio)
const canvas = new OffscreenCanvas(rect.width, rect.height);
const ctx = canvas.getContext('2d');
ctx.drawImage(
imageBitmap,
(iframe.left + rect.left) * radio, //源图像的裁剪起点 X 坐标。
(iframe.top + rect.top) * radio,//iframe.top, //源图像的裁剪起点 Y 坐标。
rect.width * radio,//iframe.width, //源图像的裁剪宽度。
rect.height * radio,//iframe.height, //源图像的裁剪高度。
0, //目标 Canvas 上的 X 坐标。
0, //目标 Canvas 上的 Y 坐标。
rect.width, //绘制到 Canvas 上的宽度(可以缩放图像)。
rect.height,//绘制到 Canvas 上的高度(可以缩放图像)
);
// 将裁剪结果转换为 Blob 或 dataURL
const croppedBlob = await canvas.convertToBlob();
const reader = new FileReader();
reader.onload = () => {
const croppedDataUrl = reader.result;
console.log('元素截图完成,dataURL:', croppedDataUrl);
chrome.downloads.download({
url: croppedDataUrl,
filename: 'screenshot.png'
});
sendResponse({url: croppedDataUrl})
// 此处可以将截图 dataURL 发送到 popup 显示,或者打开新窗口展示
};
reader.readAsDataURL(croppedBlob);
} catch (error) {
console.error('截图过程中出错:', error);
}
});
}
async function get_element_position(tabId, element_type) {
const type = `get_${element_type}_position`
return await chrome.tabs.sendMessage(tabId, {type})
}
这篇文章提供了宝贵的经验和见解,对读者有很大的启发和帮助。
操作步骤清晰,指导性强,易于实践。
建议补充发展中国家案例,避免视角局限。
建议后续持续追踪此话题,形成系列研究。
这篇文章提供了宝贵的经验和见解,对读者有很大的启发和帮助。