JavaScript将图像数据放在画布上

时间:2018-02-19 00:43:38

标签: javascript html css html5-canvas

我有以下代码创建一个矩形,如下图所示:

<!DOCTYPE html>
<html>
<body>
  <canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;">
    Your browser does not support the HTML5 canvas tag.
  </canvas>
  <p id='one'></p>

  <script>

    var c = document.getElementById("myCanvas");
    var ctx = c.getContext("2d");
    ctx.fillStyle = 'black';
    ctx.fillRect(20, 20, 40, 40)
    var imgData = ctx.createImageData(100, 100);
    var i;
    for (i = 0; i < imgData.data.length; i += 16) {
      imgData.data[i + 0] = 255;
      imgData.data[i + 1] = 0;
      imgData.data[i + 2] = 0;
      imgData.data[i + 3] = 255;
    }
    // ctx.putImageData(imgData, 10, 10);

  </script>
</body>
</html>

enter image description here


<小时/>

当我确保通过不评论ctx.putImageData添加图像数据时,我只获得如下图所示的图像数据:

enter image description here


<小时/>

如何在红线之间的白色空间中确保图像是在黑色矩形的顶部创建的?
我希望能够看到黑色矩形。我尝试更改alpha通道,但没有做任何事情。

提前致谢:)。

2 个答案:

答案 0 :(得分:2)

putImageData会将目标像素替换为ImageData中包含的像素,无论它们是什么 这意味着如果您的ImageData包含透明像素,一旦您将ImageData放在画布上,这些透明像素就会存在。

有几种方法可以达到你想要的效果。

需要更少代码更改的是从上下文的当前状态进行像素操作。通过调用getImageData代替createImageData,您将拥有一个ImageData,其中包含您所选区域中当前绘制的像素。

&#13;
&#13;
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.fillStyle = 'black';
ctx.fillRect(20, 20, 40, 40);
// get the current pixels at (x, y, width, height)
var imgData = ctx.getImageData(10, 10, 100, 100);
var i;
// and do the pixel manip over these pixels
for (i = 0; i < imgData.data.length; i += 16) {
  imgData.data[i + 0] = 255;
  imgData.data[i + 1] = 0;
  imgData.data[i + 2] = 0;
  imgData.data[i + 3] = 255;
}
ctx.putImageData(imgData, 10, 10);
&#13;
<canvas id="myCanvas"></canvas>
&#13;
&#13;
&#13;

主要警告是getImageData速度较慢,需要的内存比createImageData更多,所以如果要在动画中的每一帧都这样做,那么它可能不合适。

在这种情况下(动画)的另一个解决方案是使用第二个离屏画布,您将在其上绘制一次ImageData,然后使用drawImage在主要画布上绘制此离屏画布

&#13;
&#13;
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
ctx.fillStyle = 'black';
var gridImage = generateGrid(100, 100);

var x = 0;
anim();

/* 
  Makes your pixel manip on an off-screen canvas
  Returns the off-screen canvas
*/
function generateGrid(width, height){
  var canvas = document.createElement('canvas');
  canvas.width = width;
  canvas.height = height;
  var off_ctx = canvas.getContext('2d');
  var imgData = off_ctx.createImageData(width, height);
  for (i = 0; i < imgData.data.length; i += 16) {
    imgData.data[i + 0] = 255;
    imgData.data[i + 1] = 0;
    imgData.data[i + 2] = 0;
    imgData.data[i + 3] = 255;
  }
  off_ctx.putImageData(imgData, 0,0);
  return canvas;
}
function anim(){
  ctx.clearRect(0,0,c.width, c.height);
  x = (x + 1) % (c.width + 100);
  ctx.fillRect(x, 20, 40, 40);
  // and here you draw your generated canvas
  ctx.drawImage(gridImage, x - 10, 0);
  requestAnimationFrame(anim);
}
&#13;
<canvas id="myCanvas"></canvas>
&#13;
&#13;
&#13;

您还可以重构代码,以便在之后绘制ImageData时使普通绘图(此处为fillRect,但背后当前图纸,这要归功于您的上下文的globalCompositeOperation属性:

&#13;
&#13;
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
// do first your pixel manip
var imgData = ctx.createImageData(100, 100);
var i;
for (i = 0; i < imgData.data.length; i += 16) {
  imgData.data[i + 0] = 255;
  imgData.data[i + 1] = 0;
  imgData.data[i + 2] = 0;
  imgData.data[i + 3] = 255;
}
ctx.putImageData(imgData, 10, 10);

// change the gCO to draw behind current non-transparent pixels
ctx.globalCompositeOperation = 'destination-over';
// now make your normal drawings
ctx.fillStyle = 'black';
ctx.fillRect(20, 20, 40, 40);
// reset the gCO
ctx.globalCompositeOperation = 'source-over';
&#13;
<canvas id="myCanvas"></canvas>
&#13;
&#13;
&#13;

最后,如果你只定位next-gen browsers,那么你可以使用ImageBitmap object,这将产生与屏幕外画布相同的结果,代码更少:

&#13;
&#13;
(async () => {
  var c = document.getElementById("myCanvas");
  var ctx = c.getContext("2d");
  ctx.fillStyle = 'black';
  var gridImage = await generateGrid(100, 100);
  var x = 0;
  anim();

  /* 
    Makes your pixel manip on an empty ImageData
    Returns an Promise resolving to an ImageBitmap
  */
  function generateGrid(width, height) {
    var imgData = ctx.createImageData(width, height);
    for (i = 0; i < imgData.data.length; i += 16) {
      imgData.data[i + 0] = 255;
      imgData.data[i + 1] = 0;
      imgData.data[i + 2] = 0;
      imgData.data[i + 3] = 255;
    }
    return createImageBitmap(imgData);
  }

  function anim() {
    ctx.clearRect(0, 0, c.width, c.height);
    x = (x + 1) % (c.width + 100);
    ctx.fillRect(x, 20, 40, 40);
    // and here you draw your generated canvas
    ctx.drawImage(gridImage, x - 10, 0);
    requestAnimationFrame(anim);
  }
})();
&#13;
<canvas id="myCanvas"></canvas>
&#13;
&#13;
&#13;

答案 1 :(得分:1)

我无法使用精确的代码,但是当我尝试重叠2张图片时,我设法让它们重叠。

<canvas id="myCanvas" width="300" height="150" style="border:1px solid #d3d3d3;">
</canvas>
<p id = 'one'></p>

<script>

var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var img = ctx.createImageData(100, 100);
 var i;
for (i = 0; i < img.data.length; i += 6) {
  img.data[i+0] = 255;
  img.data[i+1] = 0;
  img.data[i+2] = 0;
  img.data[i+3] = 255;
}
var img2 = ctx.createImageData(100, 100);
var i;
for (i = 0; i < img2.data.length; i += 20) {
  img2.data[i+0] = 0;
  img2.data[i+1] = 255;
  img2.data[i+2] = 0;
  img2.data[i+3] = 255;
}
  var pixels = 4*100*100;
  var imgData1 = img.data;
  var imgData2 = img2.data;
  while (pixels--){
    imgData1[pixels] = imgData1[pixels] * 0.5 + imgData2[pixels] *0.5;
  }
  img.data = imgData1;
ctx.putImageData(img, 10, 0);

</script>