web-dev-qa-db-ja.com

fabric.jsでCanvasをPNGとしてダウンロードし、ネットワークエラーを返します

Fabric.jsを使用してCanvasをPNGとしてダウンロードしたい。ダウンロード中に、画像を拡大したい。そこで、toDataURL()関数のmultiplierプロパティを使用します。しかし、失敗したネットワークエラーが表示されます

PS:multiplierプロパティを指定していない場合はダウンロードされますが、domultiplierプロパティを使用したいので、画像

これは私がやっていることです:

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

}
22
Abhinav

あなたが直面している問題は、fabricjsとは直接関係ありません(キャンバスもjavascript btwでもありません)が、いくつかのブラウザ(Chromeを含む)がアンカーのsrc属性の最大長に持っている制限から来ていますdonwload属性を持つ要素(_<a>_)。

この制限に達すると、コンソールにあるこのキャッチできない「ネットワークエラー」のみが得られます。ダウンロードは失敗しましたが、開発者であるあなたはそれを知ることができません。

これで提案されているように(you-refused-to-mark-as-)duplicate 、解決策は直接取得するか、使用可能なBlob(キャンバスの場合、 toBlob() メソッドを呼び出すか、最初にdataURIをBlobに変換してから、 オブジェクトURL を作成します=このBlobから。

FabricjsにはtoBlob関数がまだ実装されていないようですので、正確なケースでは、後で実行する必要があります。
dataURIをBlobに変換する多くのスクリプトを見つけることができます。1つは MDNのpolyfill 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);
_
37
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});
}

注: 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();
} 
14
Abhinav

前の2つの回答は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
B T