将画布的部分移动到其他画布

时间:2018-01-23 21:32:35

标签: javascript html5 canvas html5-canvas

我有两幅画布,让我们说Canvas A和Canvas B.用户上传一个文件然后放到Canvas A上,我已经做过了。一旦发生这种情况,我想开始将Canvas A的部分复制到Canvas B。

我试过这样做

source = a.getContext('2d');
b.drawImage(source, 0, 0, source.width, source.height);

但是复制整件事。所以我的问题是,如何将Canvas A的一部分复制到Canvas B。

编辑:

我也试过......

var imgData=atx.getImageData(10,10,20,20);
btx.putImageData(imgData, 0, 0);

但只是将imgData复制回Canvas A at(0,0)。

1 个答案:

答案 0 :(得分:1)

首先,b.drawImageCanvasImageSource作为其第一个参数,而不是上下文。将整个HTMLCanvasElement传递到那里。

drawImage需要九个参数,而你需要全部这些参数。如果您只使用五个,则假定您正在拍摄整个源图像并将其绘制到目的地。完整的签名是

drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh);

sxsyswsh定义您要从源中复制的矩形。 dxdydwdh定义了您在目的地吸引的矩形。请注意,swsh不得与dwdh匹配。如果源矩形和目标矩形不具有相同的大小,则复制的图像将被压扁或拉伸以适合目标矩形。

我制作了一个片段,让您可以与drawImage一起玩,看看它在做什么。当您将其视为整页时效果最佳:



const srcCanvas = document.querySelector('#source');
const srcContext = srcCanvas.getContext('2d');
const destContext = document.querySelector('#destination')
  .getContext('2d');

// The overlay canvas is where we draw the red rectangle. It's
// positioned directly on top of the source canvas.
const overlay = document.querySelector('#overlay')
  .getContext('2d');
overlay.fillStyle = 'rgba(255, 0, 0, 0.3)';
overlay.strokeStyle = 'red';

const inputs = Array.from(
  document.querySelectorAll('input[type="number"]')
);
const lockScale = document.querySelector('#lockScale');
lockScale.addEventListener('change', () => {
  inputs[6].disabled = lockScale.checked;
  inputs[7].disabled = lockScale.checked;
  if (lockScale.checked) update();
});

// Grab an image and draw it on the source canvas...
fetch('https://picsum.photos/320/240/?image=451')
  .then(res => res.blob())
  .then(createImageBitmap)
  .then(bitmap => {
    srcContext.drawImage(bitmap, 0, 0);
    
// ...and only then start watching for changes in the input boxes.
// There's no point in spending cycles copying an empty canvas.
    inputs.forEach(i => {
      i.addEventListener('input', update);
    });
    update();
  });

function update() {
  if (lockScale.checked) {
    inputs[6].value = inputs[2].value;
    inputs[7].value = inputs[3].value;
  }
  const values = inputs.map(i => Number(i.value));
  
  destContext.clearRect(0, 0, 320, 240);
  overlay.clearRect(0, 0, 320, 240);
  overlay.beginPath();
  overlay.rect(
    // These adjustments move the overlay path off the boundary
    // between pixels so the rectangle border is a crisp 1px line.
    values[0] + 0.5,
    values[1] + 0.5,
    // JavaScript uses half-open intervals, which makes sense for
    // code. But for a visualization of graphics work, fully-
    // closed intervals are preferable. These adjustments make the
    // overlay rectangle exactly cover the pixels that will be
    // copied.
    values[2] - 1,
    values[3] - 1
  );
  overlay.fill();
  overlay.stroke();
  
  // The real drawing code of this snippet doesn't look like the
  // code you would actually use. We call apply() on drawImage()
  // so we can pass in the entire values array without listing out
  // every element.
  destContext.drawImage.apply(
    destContext, // We don't want to change what 'this' points to
    [srcCanvas].concat(values));
    
  // The spread operator provides a more elegant way of doing this:
  // destContext.drawImage(srcCanvas, ...values);
  // But it doesn't work with IE.
}

canvas {
  height: 240px;
  width: 320px;
  position: absolute;
  top: 0;
  left: 0;
}

.canvasbox {
  display: inline-block;
  position: relative;
  width: 320px;
  height: 240px;
  border: 1px solid black;
}

input[type="number"] {
  font-family: monospace;
  border: none;
  background: silver;
  color: black;
  width: 3em;
}

input[disabled] {
  color: silver;
  background: grey;
}

code {
  color: navy;
}

<div class="canvasbox">
  <canvas id="source" width="320" height="240"></canvas>
  <canvas id="overlay" width="320" height="240"></canvas>
</div>
<div class="canvasbox">
  <canvas id="destination" width="320" height="240"></canvas>
</div>
<div>
  <code>
    destContext.drawImage(srcCanvas,
    <input id="sx" type="number" value="180">,
    <input id="sy" type="number" value="100">,
    <input id="sw" type="number" value="40">,
    <input id="sh" type="number" value="50">,
    <input id="dx" type="number" value="10">,
    <input id="dy" type="number" value="10">,
    <input id="dw" type="number" value="40">,
    <input id="dh" type="number" value="50">);
  </code>
</div>
<div>
  <label>
    <input id="lockScale" type="checkbox">Lock scale
  </label>
</div>
&#13;
&#13;
&#13;