14

我有两个画布,我想把canvas1的内容传过来,序列化成一个ArrayBuffer,然后加载到canvas2中。以后我会把canvas1的内容发送到服务器,处理,然后返回canvas2,但是现在我只想序列化和反序列化。

我发现这种以字节为单位获取画布信息的方法:

var img1 = context.getImageData(0, 0, 400, 320);
var binary = new Uint8Array(img1.data.length);
for (var i = 0; i < img1.data.length; i++) {
    binary[i] = img1.data[i];
}

并且还发现了将信息设置为Image对象的这种方式:

var blob = new Blob( [binary], { type: "image/png" } );
var urlCreator = window.URL || window.webkitURL;
var imageUrl = urlCreator.createObjectURL( blob );
var img = new Image();
img.src = imageUrl;

但不幸的是,它似乎不起作用。

哪种方法是正确的?

4

3 回答 3

22

您从中获得的 ImageDatagetImageData()已经在使用 ArrayBuffer (由Uint8ClampedArray视图使用)。只需抓住它并发送它:

var imageData = context.getImageData(x, y, w, h);
var buffer = imageData.data.buffer;  // ArrayBuffer

再次设置它:

var imageData = context.createImageData(w, h);
imageData.data.set(incomingBuffer);

您可能想要考虑某种形式的字节编码(例如 f.ex base-64),因为任何高于 127 (ASCII) 的字节值都受系统上使用的字符编码的影响。或者确保旅途中的所有步骤都使用相同的(例如 UTF8)。

于 2014-03-06T19:18:28.033 回答
4

创建一个 ArrayBuffer 并将其发送到 Uint8Array 构造函数,然后使用 websockets 发送缓冲区:

var img1 = context.getImageData(0, 0, 400, 320);
var data=img1.data;
var buffer = new ArrayBuffer(data.length);
var binary = new Uint8Array(buffer);
for (var i=0; i<binary.length; i++) {
    binary[i] = data[i];
}
websocket.send(buffer);

[先前使用 canvas.toDataURL 的答案已删除]

于 2014-03-06T17:56:29.280 回答
1

如果您想要紧凑数据而不是原始ImageData对象,请考虑使用canvas.toBlob()而不是。context.getImageData()

例子:

const imageIn = document.querySelector('#image-in');
const imageOut = document.querySelector('#image-out');
const canvas = document.querySelector('#canvas');
const imageDataByteLen = document.querySelector('#imagedata-byte-length');
const bufferByteLen = document.querySelector('#arraybuffer-byte-length');

const mimeType = 'image/png';

imageIn.addEventListener('load', () => {

  // Draw image to canvas.
  canvas.width = imageIn.width;
  canvas.height = imageIn.height;
  const ctx = canvas.getContext('2d');
  ctx.drawImage(imageIn, 0, 0);

  // Convert canvas to ImageData.
  const imageData = ctx.getImageData(0, 0, imageIn.width, imageIn.height);
  imageDataByteLen.textContent = imageData.data.byteLength + ' bytes.';

  // Convert canvas to Blob, then Blob to ArrayBuffer.
  canvas.toBlob((blob) => {
    const reader = new FileReader();
    reader.addEventListener('loadend', () => {
      const arrayBuffer = reader.result;
      bufferByteLen.textContent = arrayBuffer.byteLength + ' bytes.';

      // Dispay Blob content in an Image.
      const blob = new Blob([arrayBuffer], {type: mimeType});
      imageOut.src = URL.createObjectURL(blob);
    });
    reader.readAsArrayBuffer(blob);
  }, mimeType);

});
<h1>Canvas ↔ ArrayBuffer</h1>

<h2>1. Source <code>&lt;img&gt;</code></h2>
<img id="image-in" src="https://ucarecdn.com/a0338bfa-9f88-4ce7-b53f-e6b61000df89/" crossorigin="">

<h2>2. Canvas</h2>
<canvas id="canvas"></canvas>

<h2>3. ImageData</h2>
<p id="imagedata-byte-length"></p>

<h2>4. ArrayBuffer</h2>
<p id="arraybuffer-byte-length"></p>

<h2>5. Final <code>&lt;img&gt;</code></h2>
<img id="image-out">

JSFiddle:https ://jsfiddle.net/donmccurdy/jugzk15b/

另请注意,图像必须托管在提供 CORS 标头的服务上,否则您会看到诸如“画布已被跨域数据污染”之类的错误。

于 2017-12-13T21:20:59.347 回答