簡體   English   中英

在fabric.js中將畫布下載為PNG,出現網絡錯誤

[英]Download Canvas as PNG in fabric.js giving network Error

我想使用 fabric.js 將 Canvas 下載為 PNG。 下載時我想縮放圖像。 所以我使用toDataURL()函數的multiplier屬性。 但我收到失敗的網絡錯誤

PS:如果我不提供multiplier屬性,它正在下載但我確實想使用multiplier屬性,因為我必須縮放圖像

這就是我正在做的:

HTML代碼:

<canvas width="400" height="500" id="canvas" ></canvas>
 <a id='downloadPreview' href="javascript:void(0)"> Download Image </a>

JS

document.getElementById("downloadPreview").addEventListener('click', downloadCanvas, false);

var _canvasObject = new fabric.Canvas('canvas');

var downloadCanvas =    function(){
    var link = document.createElement("a");

link.href = _canvasObject.toDataURL({format: 'png', multiplier: 4});
      link.download = "helloWorld.png";
     link.click();

}

您面臨的問題與fabricjs(也不是canvas,甚至不是javascript btw)沒有直接關系,而是來自某些瀏覽器(包括Chrome)對錨元素( <a>src屬性的最大長度的限制) 與下載屬性。

當達到這個限制時,你唯一得到的就是控制台中這個無法捕捉的“網絡錯誤”; 下載失敗,但您作為開發人員無法知道。

正如在這個(you-refused-to-mark-as-) duplicate 中提出的,解決方案是在可用時直接獲取 Blob(對於畫布,您可以調用其toBlob()方法,或者首先將您的 dataURI 轉換為Blob,然后從這個 Blob 創建一個對象 URL

Fabricjs 似乎還沒有實現toBlob函數,因此在您的確切情況下,您必須稍后執行。
您可以找到許多將 dataURI 轉換為 Blob 的腳本,其中一種在MDN 的Canvas.toBlob() to Canvas.toBlob()方法中可用。

然后它看起來像這樣:

// edited from https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toBlob#Polyfill
function dataURIToBlob(dataURI, callback) {
  var binStr = atob(dataURI.split(',')[1]),
    len = binStr.length,
    arr = new Uint8Array(len);

  for (var i = 0; i < len; i++) {
    arr[i] = binStr.charCodeAt(i);
  }

  callback(new Blob([arr]));
}

var callback = function(blob) {
    var a = document.createElement('a');
    a.download = fileName;
    a.innerHTML = 'download';
    // the string representation of the object URL will be small enough to workaround the browser's limitations
    a.href = URL.createObjectURL(blob);
    // you must revoke the object URL, 
    //   but since we can't know when the download occured, we have to attach it on the click handler..
    a.onclick = function() {
      // ..and to wait a frame
      requestAnimationFrame(function() {
          URL.revokeObjectURL(a.href);
        });
        a.removeAttribute('href')
      };
    };

dataURIToBlob(yourDataURL, callback);

我知道了。 按照 Kaiido 的建議解決了

function dataURLtoBlob(dataurl) {
    var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
        bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
    while(n--){
        u8arr[n] = bstr.charCodeAt(n);
    }
    return new Blob([u8arr], {type:mime});
}

注意:從HTML5 / Javascript - DataURL 到 Blob & Blob 到 DataURL獲得上述功能

var downloadCanvas =    function(){
    var link = document.createElement("a");
      var imgData = _canvasObject.toDataURL({    format: 'png',
        multiplier: 4});
      var strDataURI = imgData.substr(22, imgData.length);
      var blob = dataURLtoBlob(imgData);
      var objurl = URL.createObjectURL(blob);

      link.download = "helloWorld.png";

      link.href = objurl;

     link.click();
} 

由於前兩個答案僅適用於具有 base64 數據的 dataURL,並且由於 href 屬性太大,此答案已被與“網絡錯誤”相關的更一般問題引用,因此這是我正在使用的代碼:

// must be called in a click handler or some other user action
var download = function(filename, dataUrl) {
    var element = document.createElement('a')

    var dataBlob = dataURLtoBlob(dataUrl)
    element.setAttribute('href', URL.createObjectURL(dataBlob))
    element.setAttribute('download', filename)

    element.style.display = 'none'
    document.body.appendChild(element)

    element.click()

    var clickHandler;
    element.addEventListener('click', clickHandler=function() {
        // ..and to wait a frame
        requestAnimationFrame(function() {
            URL.revokeObjectURL(element.href);
        })

        element.removeAttribute('href')
        element.removeEventListener('click', clickHandler)
    })

    document.body.removeChild(element)
}


// from Abhinav's answer at  https://stackoverflow.com/questions/37135417/download-canvas-as-png-in-fabric-js-giving-network-error/
var dataURLtoBlob = function(dataurl) {
    var parts = dataurl.split(','), mime = parts[0].match(/:(.*?);/)[1]
    if(parts[0].indexOf('base64') !== -1) {
        var bstr = atob(parts[1]), n = bstr.length, u8arr = new Uint8Array(n)
        while(n--){
            u8arr[n] = bstr.charCodeAt(n)
        }

        return new Blob([u8arr], {type:mime})
    } else {
        var raw = decodeURIComponent(parts[1])
        return new Blob([raw], {type: mime})
    }
}

使用這些函數,您可以將代碼更改為:

document.getElementById("downloadPreview").addEventListener('click', function() {
  var dataURL = _canvasObject.toDataURL({format: 'png', multiplier: 4})
  download("hellowWorld.png", dataURL)
})

我的網站上有多個畫布,並且在其中之一中遇到了同樣的問題。

畫布尺寸 1:750px x 500px(Window Chrome 上的網絡問題,在 Chrome Macos 上工作正常)

畫布尺寸 2:540 像素 x 1080 像素(無下載問題,適用於乘數 4)

我只是減少了下載大小,將乘數 4 更改為 2,效果很好。

然后我將乘數更改為 3,但它不再起作用。

然后我嘗試了 2.5,它再次正常工作。

用 4 Multiplier 創建這么大的文件不是我的要求,所以我選擇了 2.5。

這是解決此問題的最簡單和最快的方法。

就我而言,我只是使用了這個

 var callback = function(blob) {
var a = document.createElement('a');
var saveAs = $('input[name="extensionGrp"]:checked').val();


var link = document.createElement('a');
link.href = URL.createObjectURL(blob);
link.download = 'Image.' + saveAs;
document.body.appendChild(link);
link.click();

};

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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