簡體   English   中英

如何將畫布圖像數據復制到其他變量?

[英]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

請注意,轉換為較小的類型時,多余的位將被截斷為整數。 從浮點數轉換時,不會復制值。 當符號和無符號整數之間復制位被復制例如Uint8ArrayInt8Array將轉換255 -1。 當從小int轉換為更大的uint時,例如將Int8ArrayUint32Array將在位-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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM