javascript 将画布内容序列化为 ArrayBuffer 并再次反序列化

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/22228552/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 22:43:49  来源:igfitidea点击:

Serialize canvas content to ArrayBuffer and deserialize again

javascripthtmlserializationhtml5-canvasarraybuffer

提问by vtortola

I have two canvas, and I want to pass the content of canvas1, serialize it to an ArrayBuffer, and then load it in canvas2. In the future I will send the canvas1 content to the server, process it, and return it to canvas2, but right now I just want to serialize and deserialize it.

我有两个画布,我想传递canvas1的内容,将其序列化为一个ArrayBuffer,然后将其加载到canvas2中。将来我会将 canvas1 的内容发送到服务器,进行处理,然后将其返回给 canvas2,但现在我只想对其进行序列化和反序列化。

I found this way of getting the canvas info in bytes:

我找到了这种以字节为单位获取画布信息的方法:

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];
}

And also found this way of set the information to a Imageobject:

并且还发现了这种将信息设置为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;

But unfortunately it doesn't seem to work.

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

Which would be the right way of doing this?

这样做的正确方法是什么?

Thanks.

谢谢。

回答by

The ImageData you get from getImageData()is already using an ArrayBuffer (used by the Uint8ClampedArrayview). Just grab it and send it:

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

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

To set it again:

再次设置:

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

You probably want to consider some form of byte encoding though (such as f.ex base-64) as any byte value above 127 (ASCII) is subject to character encoding used on a system. Or make sure all steps on the trip uses the same (f.ex. UTF8).

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

回答by markE

Create an ArrayBuffer and send it into to the Uint8Array constructor, then send the buffer using websockets:

创建一个 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);

[ Previous answer using canvas.toDataURL removed ]

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

回答by Don McCurdy

Consider using canvas.toBlob()instead of context.getImageData()if you want compact data rather than a raw ImageDataobject.

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

Example:

例子:

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/

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

Also note that images must be hosted on a service that provides CORS headers, or you'll see errors like "The canvas has been tainted by cross-origin data."

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