Каковы ограничения на .toDataUrl ()? [Дубликат]

16
задан Kaiido 11 May 2016 в 01:59
поделиться

3 ответа

Проблема, с которой вы сталкиваетесь, напрямую не связана с fabricjs (ни холстом, ни даже javascript btw), но исходит из ограничений, которые имеют некоторые браузеры (включая Chrome) на максимальной длине для атрибута src привязки Элемент (<a>) с атрибутом donwload.

Когда этот предел будет достигнут, тогда единственное, что у вас есть, - это неуправляемая «сетевая ошибка» в консоли; загрузка не удалась, но вы, как разработчик, не можете знать об этом.

Как было предложено в этом (вы отказались от метки-как) duplicate , решение должно либо напрямую получить Blob, если доступно (для холста вы можете вызвать его метод toBlob() или сначала преобразовать ваш dataURI в Blob, а затем создать URL-адрес объекта из этого Blob.

У Fabricjs пока не реализована функция toBlob, поэтому в вашем конкретном случае вам нужно будет сделать это позже. Вы можете найти много сценариев для преобразования dataURI в Blob, один из которых доступен в метод полифония MDN - 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);
25
ответ дан Kaiido 20 August 2018 в 21:36
поделиться
  • 1
    Thanx для подробного – Abhinav 11 May 2016 в 05:27
  • 2
    Ваши данныеURIToBlob плохо сформированы. Где определяется тип или качество? И this скорее всего ссылается на окно. – B T 20 June 2017 в 01:07
  • 3
    @BT, вы совершенно правы, я не знаю, как это могло остаться так долго, когда никто не заметил это (я первый). Благодарю. Но я должен, вероятно, просто удалить эту функцию dataURIToBlob сейчас, когда toBlob пробился в большинстве основных браузеров, это намного быстрее, чем преобразование дважды данных. – Kaiido 20 June 2017 в 01:14
  • 4
    Следует отметить еще одно: dataURIToBlob будет работать только для кодированных данных с кодировкой base64. – B T 20 June 2017 в 02:07
  • 5
    @BT Знаете ли вы много других способов получить dataURI из файла растрового изображения (или с холста)? Только текстовые файлы (например, языки разметки, такие как svg) могут быть представлены закодированным способом, отличным от b64 (URL_encoded), двоичные данные не могут быть представлены иначе. Этот вопрос касается экспорта холста fabricjs как PNG (следовательно, растрового и двоичного). – Kaiido 20 June 2017 в 02:11

Поскольку предыдущие два ответа работают только для dataURL, у которых есть данные base64, и поскольку на этот ответ ссылались более общие вопросы, связанные с «сетевыми ошибками» из-за слишком больших атрибутов 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 20 August 2018 в 21:36
поделиться
  • 1
    Не следует ли возобновить связанный вопрос? (по крайней мере, если он был закрыт). Это не дает слишком много полезной информации по текущему вопросу: «Скачать Canvas как PNG в fabric.js». Нет другого способа получить dataURI, представляющий PNG-файл, чем через base64, кодирующий его двоичные данные. – Kaiido 20 June 2017 в 02:23

Я понял. Проработал это, как было предложено 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 & amp; Blob to 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();
} 
11
ответ дан Community 20 August 2018 в 21:36
поделиться
  • 1
    У меня этот код отлично работает в Chrome и Edge, но в FF ничего не происходит. Вы знаете, если это сработало для вас в FF? – Ron 26 November 2016 в 08:28
  • 2
    Это для меня сегодня, поэтому я не могу проверить и сказать вам сейчас, но я думаю, что это сработало в FF, я все равно проверю в любом случае как можно скорее – Abhinav 26 November 2016 в 08:41
  • 3
    Потрясающие. Имел ту же проблему и решил ее с вашим решением. Спасибо! – Steevie 10 January 2017 в 17:54
Другие вопросы по тегам:

Похожие вопросы: