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})
}

标签: chrome extension, 截图, screenshot

已有 5 条评论

  1. 这篇文章提供了宝贵的经验和见解,对读者有很大的启发和帮助。

  2. 操作步骤清晰,指导性强,易于实践。

  3. 建议补充发展中国家案例,避免视角局限。

  4. 建议后续持续追踪此话题,形成系列研究。

  5. 这篇文章提供了宝贵的经验和见解,对读者有很大的启发和帮助。

添加新评论