drawImage裁剪用户选择的区域位置和比例不正确

问题描述 投票:0回答:1

我有一个 Chrome 扩展程序,允许用户从屏幕的选定区域截取屏幕截图。

流程是这样的:

  1. 用户单击 Chrome 扩展程序弹出菜单中的屏幕截图按钮。弹出窗口向后台脚本发送消息以捕获选项卡。
  2. 后台脚本截图整个选项卡并将URL发送到内容脚本。
  3. 内容脚本允许用户在屏幕上绘制一个矩形,然后从屏幕截图中裁剪出该区域并将其发送到服务器。

问题: 当用户选择要裁剪的区域时,最终结果会按比例放大并向左和向上移动一点。对于我的生活,我无法弄清楚为什么。此外,如果我尝试在垂直/水平滚动页面时进行裁剪,则会在顶部创建画布。我不确定这是否是相关问题。

示例截图 原图 裁剪结果(裁剪时我选择了整个图像)

下面的代码只是内容脚本的修改版本,没有服务器调用。

let selectableCanvasArea: HTMLCanvasElement;
let screenshotUrl: string;
let startX: number, startY: number, endX: number, endY: number;

export const startScreenshotProcess = (screenshotUrlParam: string): void => {
    screenshotUrl = screenshotUrlParam; // This comes from the background script
    createCanvas();
    // Change the cursor
    document.body.style.cursor = "crosshair";
    // Darken the entire screen so we can see the cursor
    document.body.style.filter = "brightness(50%)";
    window.addEventListener("mousedown", mouseDownListener);
    window.addEventListener("mouseup", mouseUpListener);
}

const createCanvas = () => {
    // Create the canvas and prepend it to the HTML
    selectableCanvasArea = document.createElement("canvas");
    selectableCanvasArea.style.position = "absolute";
    selectableCanvasArea.style.top = "0px";
    selectableCanvasArea.style.left = "0px";
    selectableCanvasArea.width = 0;
    selectableCanvasArea.height = 0;
    selectableCanvasArea.style.zIndex = "9999";
    selectableCanvasArea.style.border = "3px dashed lightblue";
    document.body.insertAdjacentElement('beforebegin', selectableCanvasArea);
}

const mouseDownListener = (e: MouseEvent): void => {
    startX = e.clientX;
    startY = e.clientY;
    selectableCanvasArea.style.top = startY + "px";
    selectableCanvasArea.style.left = startX + "px";
    window.addEventListener("mousemove", mouseMoveListener);
}

const mouseMoveListener = (e: MouseEvent): void => {
    e.preventDefault();
    selectableCanvasArea.width = Math.abs(e.clientX - startX);
    selectableCanvasArea.height = Math.abs(e.clientY - startY);
}

const mouseUpListener = (e: MouseEvent): void => {
    endX = e.clientX;
    endY = e.clientY;
    processScreenshot();
}

export const processScreenshot = async () => {
    const image = new Image();
    image.src = screenshotUrl;
    image.onload = () => {
        let pos = selectableCanvasArea.getBoundingClientRect();
        
        let originalX = (pos.left + window.scrollX);
        let originalY = (pos.top + window.scrollY);

        let croppedWidth = pos.width;
        let croppedHeight = pos.height;
        
        let croppedCanvas = document.createElement("canvas");
        croppedCanvas.width = croppedWidth;
        croppedCanvas.height = croppedHeight;

        let ratioX = image.naturalWidth / croppedWidth;
        let ratioY = image.naturalHeight / croppedHeight;
        
        let context = croppedCanvas.getContext("2d");
        
        context?.drawImage(image,
            originalX, originalY, // sx, sy
            croppedWidth, croppedHeight, // sWidth, sHeight
            0, 0, // dx, dy
            croppedWidth, croppedHeight // dWidth, dHeight
        );
        document.body.insertAdjacentHTML('beforebegin', `<img src="${croppedCanvas.toDataURL()}" alt="Cropped Image"/>`);
    }
}
javascript canvas html5-canvas
1个回答
0
投票

我的问题是 Chrome 截取的屏幕截图 与您的屏幕/标签的分辨率不同。

Ex:如果屏幕是 2000px 宽,图像可能是 1000px 宽。所以我们需要我们的起点和宽度为 1000/2000 (0.5)。

我用这段代码更新了上面的代码:

/* We need a ratio because the screenshot image is NOT the same resolution
        as the screen that we see. Ex: If the screen is 2000px wide, the image might be 1000px wide. So we need our start points and width to be 1000/2000 (0.5) */
        let ratio = image.width / window.innerWidth;
context?.drawImage(image,
            (startX) * ratio, 
            (startY) * ratio,
            (endX - startX) * ratio, (endY - startY) * ratio,
            0, 0,
            endX - startX, endY - startY);
© www.soinside.com 2019 - 2024. All rights reserved.