簡體   English   中英

從以編程方式生成的圖像中獲取像素數據

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

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