[英]Get pixel data back from programmatically generated image
我在客戶端JavaScript代碼中生成像素數組,並將其轉換為blob。 然后,我將Blob的URL作為image.src傳遞,並在image.onload回調中將其撤消。 我沒有保留對先前步驟生成的數據的任何引用,因此GC可以釋放這些數據。
用這種方法生成的圖像很多,而且效果很好。 但是有時用戶可能想通過單擊圖像附近的“保存”按鈕來保存生成的圖像。 我不想再次生成圖像,因為生成速度很慢,並且圖像已經生成並且可以在屏幕上看到。 所以我想從圖像中恢復像素。 我嘗試再次創建畫布,在其上繪制圖像,然后調用toBlob,但是瀏覽器將此圖像視為交叉原點,並引發異常:“無法在'HTMLCanvasElement'上執行'toBlob':污染的畫布可能無法導出”。 我在canvas.toDataUrl和canvasContext.getImageData中遇到類似的錯誤。
有解決此問題的方法嗎?
我還嘗試創建畫布而不是圖像,但是當我創建第二個畫布時,第一個畫布的內容將清除。
已添加僅在Chrome和其他WebKit瀏覽器中會發生此錯誤。 Firefox和MS Edge可以正常工作。 當我注釋掉吊銷Blob網址的代碼行時,此錯誤消失了-我可以在畫布上繪制圖像並獲取其像素數據而沒有CORS問題。 但這是沒有意義的,因為我已經有未刪除的Blob。 但是我的頁面可能會生成許多圖像-它取決於它的用戶,並且不受限制。 圖像的大小也是無限的-甚至生成4096x4096的圖像也可能有用。 因此,我想盡可能減少頁面的內存消耗。 所有這些圖像都應該可以下載。 大多數圖像的生成使用以前生成的圖像,因此要重新生成鏈中的最后一個圖像,我必須重新生成所有圖像。
因此,我僅需要針對Chrome瀏覽器的解決方法。
添加了2,我嘗試在JS Fiddle中重現此問題,但未能成功。 但是在本地我的代碼不起作用-我在本地開發了我的應用程序,也沒有嘗試在服務器上運行它。 在計算機上創建test.html文件,然后在瀏覽器中打開(本地,沒有服務器):
<html>
<body>
<pre id="log"></pre>
</body>
<script>
var log = document.getElementById("log");
var canvas = document.createElement("canvas");
canvas.width = canvas.height = 256;
var ctx = canvas.getContext("2d");
canvas.toBlob(function(blob) {
var img = new Image();
var blobUrl = URL.createObjectURL(blob);
img.src = blobUrl;
img.onload = function()
{
URL.revokeObjectURL(blobUrl);
ctx.drawImage(img, 0, 0);
try { canvas.toBlob(function(blob) { log.textContent += 'success\n'; }); }
catch(e) {log.textContent += e.message + '\n';}
};
});
</script>
</html>
它將Failed to execute 'toBlob' on 'HTMLCanvasElement': Tainted canvases may not be exported.
打印“ Failed to execute 'toBlob' on 'HTMLCanvasElement': Tainted canvases may not be exported.
。 因此,我認為,我的解決方法是檢測該頁面是否在WebKit瀏覽器和file:///
協議的組合上運行。 而且我可以推遲吊銷Blob URL,直到僅針對此組合卸載頁面為止。
這確實聽起來像chrome的實現中的錯誤, 您可能要報告它 。
似乎發生的情況是,chrome在第一次在畫布上繪制圖像時僅檢查圖像是否通過干凈的原點加載。
因為此時您已經撤消了blobURI,所以它無法將此URI映射到干凈的原始位置(在chrome上, file://
協議非常嚴格)。
但是似乎有一個簡單的解決方法:
通過在 [齊磊的]繪制此圖像*帆布撤銷blobURI之前,Chrome將迎來形象干凈,並記住它。
* [edit]實際上看來它必須是同一張畫布...
因此,您可以簡單地預先創建導出畫布,並在其上繪制每個圖像(為節省內存,您甚至可以在不將其用於導出時將其設置為1x1px), 然后再撤消圖像的src:
// somewhere accessible to the export logic
var reviver = document.createElement('canvas').getContext('2d');
// in your canvas to img logic
canvas.toBlob(function(blob){
var img = new Image();
img.onload = function(){
reviver.canvas.width = reviver.canvas.height = 1; // save memory
reviver.drawImage(this, 0,0); // mark our image as origin clean
URL.revokeObjectURL(this.src);
}
img.src = URL.createObjectURL(blob);
probablySaveInAnArray(img);
};
// and when you want to save your images to disk
function reviveBlob(img){
reviver.canvas.width = img.width;
reviver.canvas.height = img.height;
reviver.drawImage(img,0,0);
reviver.canvas.toBlob(...
}
但是請注意,此方法將創建一個新的 Blob,而不是檢索先前的Blob,該Blob可能已由GarbageCollector收集。 不幸的是,這是您撤消blobURI的唯一方法。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.