Загрузить Canvas как PNG в файле fabric.js, дающем сетевую ошибку
Я хочу загрузить Canvas как PNG с использованием fabric.js. Во время загрузки я хочу масштабировать изображение. Поэтому я использую свойство multiplier
функции toDataURL()
. Но я получаю Failed-Network Error
PS: Если я не даю свойство multiplier
, он загружается, но я do хочу использовать свойство 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();
}
Ответы
Ответ 1
Проблема, с которой вы сталкиваетесь, напрямую не связана с fabricjs (ни холстом, ни даже javascript btw), но исходит из ограничений, которые некоторые браузеры (включая Chrome) имеют максимальную длину для атрибута src
привязки Элемент (<a>
) с атрибутом donwload.
Когда этот предел будет достигнут, тогда единственное, что у вас есть, - это нечеткая "Сетевая ошибка" в консоли; загрузка не удалась, но вы, как разработчик, не можете знать об этом.
Как было предложено в этом (вы-отказано пометить-как-) дубликат, решение либо напрямую получить Blob, когда доступно (для холста, вы можете вызвать его toBlob()
или сначала преобразовать свой dataURI в Blob, а затем создать URL объекта из этого Blob.
У Fabricjs пока не реализована функция toBlob
, поэтому в вашем конкретном случае вам нужно будет сделать это позже.
Вы можете найти много сценариев для преобразования dataURI в Blob, один из них доступен в MDN polyfill в 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 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);
Ответ 2
Я понял. Проработал так, как предложил Кайидо
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();
}
Ответ 3
Поскольку предыдущие два ответа работают только для 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 answer at https://stackoverflow.com/info/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)
})