简体   繁体   English

在fabric.js中将画布下载为PNG,出现网络错误

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

I want to download Canvas as PNG using fabric.js.我想使用 fabric.js 将 Canvas 下载为 PNG。 While downloading I want to scale the image.下载时我想缩放图像。 So I use multiplier property of toDataURL() function.所以我使用toDataURL()函数的multiplier属性。 But I get Failed-Network Error但我收到失败的网络错误

PS: If I dont give multiplier property,it is downloading but I do want to use multiplier property since I have to scale the image PS:如果我不提供multiplier属性,它正在下载但我确实想使用multiplier属性,因为我必须缩放图像

This is what I am doing:这就是我正在做的:

HTML Code: HTML代码:

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

JS 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();

}

The problem you are facing is not directly related to fabricjs, (nor canvas and not even javascript btw), but comes from limitations some browsers (including Chrome) does have on the maximum length for the src attribute of an Anchor Element ( <a> ) with the donwload attribute.您面临的问题与fabricjs(也不是canvas,甚至不是javascript btw)没有直接关系,而是来自某些浏览器(包括Chrome)对锚元素( <a>src属性的最大长度的限制) 与下载属性。

When this limit is reached, then the only thing you've got is this uncatchable "Network Error" in the console ;当达到这个限制时,你唯一得到的就是控制台中这个无法捕捉的“网络错误”; the download as failed, but you as the developer can't know about it.下载失败,但您作为开发人员无法知道。

As proposed in this (you-refused-to-mark-as-) duplicate , the solution is either to directly get a Blob when available (for canvas, you may call its toBlob() method, or to first convert your dataURI to a Blob, and then create an object URL from this Blob.正如在这个(you-refused-to-mark-as-) duplicate 中提出的,解决方案是在可用时直接获取 Blob(对于画布,您可以调用其toBlob()方法,或者首先将您的 dataURI 转换为Blob,然后从这个 Blob 创建一个对象 URL

Fabricjs doesn't seem to have a toBlob function implemented yet, so in your exact case, you'll have to do the later. Fabricjs 似乎还没有实现toBlob函数,因此在您的确切情况下,您必须稍后执行。
You can find many scripts to convert dataURI to Blob, one is available in MDN's polyfill to Canvas.toBlob() method.您可以找到许多将 dataURI 转换为 Blob 的脚本,其中一种在MDN 的Canvas.toBlob() to Canvas.toBlob()方法中可用。

Then it would look like this :然后它看起来像这样:

// 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);

I got it.我知道了。 Worked it out as suggested by Kaiido按照 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});
}

NOTE: Got the above function from HTML5 / Javascript - DataURL to Blob & Blob to DataURL注意:从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();
} 

Since the previous two answers only work for dataURLs that have base64 data, and because this answer has been referenced by more general questions related to "network errors" because of href attributes that are too large, here's the code I'm using:由于前两个答案仅适用于具有 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})
    }
}

With these functions you can change the code to this:使用这些函数,您可以将代码更改为:

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

I have multiple canvas on my website, and was struggling with same issue in One of them.我的网站上有多个画布,并且在其中之一中遇到了同样的问题。

Canvas size 1 : 750px x 500px (Network Issue on Window Chrome, works fine on Chrome Macos)画布尺寸 1:750px x 500px(Window Chrome 上的网络问题,在 Chrome Macos 上工作正常)

Canvas Size 2: 540px x 1080px (No download issue, works with multiplier 4)画布尺寸 2:540 像素 x 1080 像素(无下载问题,适用于乘数 4)

I simply reduced download size, changing multiplier 4 to 2 and it worked fine.我只是减少了下载大小,将乘数 4 更改为 2,效果很好。

Then I changed multiplier to 3 and it wasn't again working.然后我将乘数更改为 3,但它不再起作用。

then I tried 2.5 and it worked fine again.然后我尝试了 2.5,它再次正常工作。

Creating such a big file with 4 Multiplier wasn't my requirement, so I settled with 2.5.用 4 Multiplier 创建这么大的文件不是我的要求,所以我选择了 2.5。

This is the easiest and fastest solution to this problem.这是解决此问题的最简单和最快的方法。

In my case I just used this就我而言,我只是使用了这个

 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