[英]How to copy canvas image data to some other variable?
我正在开发一个小型应用程序,该应用程序将用户图像加载到服务器上,让他选择其中一个过滤器并返回图像。
我需要以某种方式保存未应用过滤器的初始图像数据。
但是,正如我发现的那样,在JS中没有复制var的自然方法 。
我尝试使用LoDash _.clone()和jQuery函数之一来执行此操作,但是它们不起作用。
当我将克隆的数据应用于图像时,函数putImageData由于类型错误而无法获取克隆的数据。
克隆函数似乎以某种方式忽略了对象类型。
码:
var img = document.getElementById("image");
var canvas = document.getElementById("imageCanvas");
var downloadLink = document.getElementById("download");
canvas.width = img.width;
canvas.height = img.height;
var context = canvas.getContext('2d');
context.drawImage(img, 0, 0, img.width, img.height);
document.getElementById("image").remove();
initialImageData = context.getImageData(0, 0, canvas.width, canvas.height); //initialImageData stores a reference to data, but I need a copy
///////////////////////
normalBtn.onclick = function(){
if(!(currentState == converterStates.normal)){
currentState = converterStates.normal;
//here I need to apply cloned normal data
}
};
那么,我在这里可以做什么???
谢谢!!!
采用 :
var image = …;
var data = JSON.parse(JSON.stringify(image).data);
var arr = new Uint8ClampedArray(data);
var copy = new ImageData(arr, image.width, image.height);
一个ImageData对象包含一个Uint8ClampedArray
,它本身包含一个ArrayBuffer
。
要克隆此ArrayBuffer
,可以使用其slice
方法,也可以使用TypedArray视图中的方法:
var ctx = canvas.getContext('2d'); ctx.fillStyle = 'orange'; ctx.fillRect(0,0,300,150); var original = ctx.getImageData(0,0,300,150); var copiedData = original.data.slice(); var copied = new ImageData(copiedData, original.width, original.height); // now both hold the same values console.log(original.data[25], copied.data[25]); // but can be modified independently copied.data[25] = 0; console.log(original.data[25], copied.data[25]);
<canvas id="canvas"></canvas>
但是在您的情况下,一个更简单的解决方案是调用两次ctx.getImageData
。
var ctx = canvas.getContext('2d'); ctx.fillStyle = 'orange'; ctx.fillRect(0,0,300,150); var original = ctx.getImageData(0,0,300,150); var copied = ctx.getImageData(0,0,300,150); // both hold the same values console.log(original.data[25], copied.data[25]); // and can be modified independently copied.data[25] = 0; console.log(original.data[25], copied.data[25]);
<canvas id="canvas"></canvas>
还有一个完整的例子:
var ctx = canvas.getContext('2d'); var img = new Image(); // keep these variables globally accessible to our script var initialImageData, filterImageData; var current = 0; // just to be able to switch easily img.onload = function(){ // prepare our initial state canvas.width = img.width/2; canvas.height = img.height/2; ctx.drawImage(img, 0,0, canvas.width, canvas.height); // this is the state we want to save initialImageData = ctx.getImageData(0,0,canvas.width,canvas.height); // get an other, independent, copy of the current state filterImageData = ctx.getImageData(0,0,canvas.width,canvas.height); // now we can modify one of these copies applyFilter(filterImageData); button.onclick = switchImageData; switchImageData(); } // remove red channel function applyFilter(image){ var d = image.data; for(var i = 0; i < d.byteLength; i+=4){ d[i] = 0; } } function switchImageData(){ // use either the original one or the filtered one var currentImageData = (current = +!current) ? filterImageData : initialImageData; ctx.putImageData(currentImageData, 0, 0); log.textContent = current ? 'filtered' : 'original'; } img.crossOrigin = 'anonymous'; img.src = 'https://upload.wikimedia.org/wikipedia/commons/5/55/John_William_Waterhouse_A_Mermaid.jpg';
<button id="button">switch imageData</button> <code id="log"></code><br> <canvas id="canvas"></canvas>
与slice
相同:
var ctx = canvas.getContext('2d'); var img = new Image(); // keep these variables globally accessible to our script var initialImageData, filterImageData; var current = 0; // just to be able to switch easily img.onload = function(){ // prepare our initial state canvas.width = img.width/2; canvas.height = img.height/2; ctx.drawImage(img, 0,0, canvas.width, canvas.height); // this is the state we want to save initialImageData = ctx.getImageData(0,0,canvas.width,canvas.height); // get an other, independent, copy of the current state filterImageData = new ImageData(initialImageData.data.slice(), initialImageData.width, initialImageData.height); // now we can modify one of these copies applyFilter(filterImageData); button.onclick = switchImageData; switchImageData(); } // remove red channel function applyFilter(image){ var d = image.data; for(var i = 0; i < d.byteLength; i+=4){ d[i] = 0; } } function switchImageData(){ // use either the original one or the filtered one var currentImageData = (current = +!current) ? filterImageData : initialImageData; ctx.putImageData(currentImageData, 0, 0); log.textContent = current ? 'filtered' : 'original'; } img.crossOrigin = 'anonymous'; img.src = 'https://upload.wikimedia.org/wikipedia/commons/5/55/John_William_Waterhouse_A_Mermaid.jpg';
<button id="button">switch imageData</button> <code id="log"></code><br> <canvas id="canvas"></canvas>
复制类型数组的正确方法是通过静态函数from
例如
var imageData = ctx.getImageData(0,0,100,100);
var copyOfData = Uint8ClampedArray.from(imageData.data); // create a Uint8ClampedArray copy of imageData.data
它还将允许您转换类型
var copyAs16Bit = Uint16Array.from(imageData.data); // Adds high byte. 0xff becomes 0x00ff
请注意,转换为较小的类型时,多余的位将被截断为整数。 从浮点数转换时,不会复制值。 当符号和无符号整数之间复制位被复制例如Uint8Array
到Int8Array
将转换255 -1。 当从小int转换为更大的uint时,例如将Int8Array
为Uint32Array
将在位-1上加上0xffff
您还可以添加可选的地图功能
// make a copy with aplha set to half.
var copyTrans = Uint8ClampedArray.from(imageData.data, (d, i) => i % 4 === 3 ? d >> 1 : d);
typedArray.from
将创建类似或可迭代对象的任何数组的副本。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.