Serialize canvas contents into ArrayBuffer and deserialize again

I have two canvases and I want to transfer the contents of canvas1, serialize it to ArrayBuffer, and then load it into canvas2. In the future, I will send the contents of canvas1 to the server, process it and return it to canvas2, but right now I just want to serialize and deserialize it.

I found this way to get canvas information 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 setting information to an Image object:

 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, this does not work.

What would be the right way to do this?

Thanks.

+7
javascript html5 serialization html5-canvas arraybuffer
source share
3 answers

ImageData obtained from getImageData() already uses ArrayBuffer (used in Uint8ClampedArray ). Just take it and send:

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

To install it again:

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

You probably want to consider some form of byte encoding (e.g. f.ex base-64), since any byte value above 127 (ASCII) is subject to the character encoding used in the system. Or make sure that all steps on the trip are used the same way (f.ex. UTF8).

+12
source share

Create an ArrayBuffer and send it to the Uint8Array constructor, then send the buffer using 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 deleted]

+4
source share

Using canvas.toBlob() instead of context.getImageData() use context.getImageData() if you need compact data, not raw ImageData .

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/

Also note that images must be hosted on a service that provides CORS headers, or you will see errors such as β€œThe canvas was corrupted by cross-origin data”.

0
source share

All Articles