【问题标题】:CanvasRenderingContext2D putImageData oddityCanvasRenderingContext2D putImageData 异常
【发布时间】:2021-12-21 17:40:42
【问题描述】:

所以我正在向我们公司的一个项目中添加一些图像处理功能。该功能的一部分是图像裁剪器,希望在某种程度上“自动检测”裁剪后的图像。如果我们的猜测是错误的,他们可以拖放裁剪点,但大多数图像人们应该能够自动裁剪。

我的问题是当我将数据放回画布索引时,根据文档,这些索引对我来说似乎没有任何意义。我正在尝试获取我找到的矩形并将他的画布转换为单个图像大小,现在将包含我的整个矩形。

    let width = right - left + 1, height = bottom - top + 1;

    canvas.width = width;
    canvas.height = height;

    ctx.putImageData(imageBuffer, -left, -top, left, top, width,height);

这给了我正确的图像。我会根据文档预期以下代码是正确的。我在 mspaint 中验证了我的 rect 索引是正确的,所以我知道这不是我的算法得出的奇怪数字。

    let width = right - left + 1, height = bottom - top + 1;

    canvas.width = width;
    canvas.height = height;

    ctx.putImageData(imageBuffer, 0, 0, left, top, width,height);

为什么必须为第二个和第三个参数设置负索引?我已经验证它在 Chrome 和 Firefox 中的行为都是这样的。

【问题讨论】:

    标签: javascript canvas


    【解决方案1】:

    是的,这可能有点令人困惑,但是当您使用putImageData 时,destinationWidthdestinationHeight 在例如drawImage 中总是等于ImageData 的widthheight

    putImageData()dirtyXdirtyYdirtyWidthdirtyHeight 的最后 4 个参数是相对的到 ImageData 的边界。

    因此,使用前两个参数,您只需设置 ImageData 边界的位置,使用其他 4 个参数,您设置像素在此 ImageData 边界中的位置。

    var ctx = canvas.getContext('2d');
    
    var imgBound = {
      x: 10,
      y: 10,
      width: 100,
      height: 100
    },
    innerImg = {
      x: 20,
      y: 20,
      width: 200,
      height: 200
    };
    // a new ImageData, the size of our canvas
    var img = ctx.createImageData(imgBound.width, imgBound.height);
    // fill it with noise
    var d = new Uint32Array(img.data.buffer);
    for(var i=0;i<d.length; i++)
      d[i] = Math.random() * 0xFFFFFFFF;
    
    function draw() {
    
    ctx.putImageData(img,
      imgBound.x,
      imgBound.y,
      innerImg.x,
      innerImg.y,
      innerImg.width,
      innerImg.height
    );
    // the ImageData's boundaries
    ctx.strokeStyle = 'blue';
    ctx.strokeRect(imgBound.x, imgBound.y, imgBound.width, imgBound.height);
    
    // our pixels boundaries relative to the ImageData's bbox
    ctx.strokeStyle = 'green';
    ctx.strokeRect(
     // for stroke() we need to add the ImageData's translation
      innerImg.x + imgBound.x,
      innerImg.y + imgBound.y,
      innerImg.width,
      innerImg.height
      );
    }
    var inner_direction = -1,
      imgBound_direction = -1;
    function anim() {
      innerImg.width += inner_direction;
      innerImg.height += inner_direction;
      if(innerImg.width <= -50 || innerImg.width > 200) inner_direction *= -1;
      imgBound.x += imgBound_direction;
      if(imgBound.x <= 0 || imgBound.x > 200)
        imgBound_direction *= -1;
      
      ctx.clearRect(0,0,canvas.width,canvas.height);
      draw();
      requestAnimationFrame(anim);
    }
    anim();
    canvas{border: 1px solid;}
    &lt;canvas id="canvas" width="300" height="300"&gt;&lt;/canvas&gt;

    【讨论】:

    • 如果不扫描像素,我不知道矩形是什么,所以需要getImageData,从技术上讲,我可能会再次绘制图像而不是将图像放回去,因为它仍在画布上。啊,即使它绘制到画布上,它也相对于图像数据坐标?有点奇怪,但这是数字排列的唯一方式。您会认为前 2 个点位于画布坐标系中,因为它应该是目的地。
    • @user2927848 啊我错过了你问题中的 auto-detect 功能,那么 putImageData 就可以了,因为你已经得到它了。是的,前两点位于目标画布坐标中,但在您的代码中,您正在翻译其 ImageData 边界内的像素,因此您需要翻译整个 ImageData 以赶上这种翻译。
    猜你喜欢
    • 2010-11-02
    • 1970-01-01
    • 2019-04-10
    • 2018-11-29
    • 1970-01-01
    • 2013-12-24
    • 2014-07-09
    • 2015-11-17
    相关资源
    最近更新 更多