2016-04-28 2 views
7

Я использую javascript и html canvas для изменения размеров jpeg-изображений. После изменения размера я использую canvas.toDataURL как атрибут href в теге привязки, чтобы предоставить ссылку, в которой пользователи могут загружать измененные изображения.Возможно ли программно определить ограничение по размеру для URL-адреса данных?

Это хорошо работает до определенного размера изображения.

кажется, что разные браузеры имеют различные ограничения на размер URL-адресов данных, как указано здесь: https://developer.mozilla.org/en-US/docs/Web/HTTP/data_URIs

В хроме, когда я за ограничение размера URL-адрес данных, ничего не происходит, когда я нажимаю на загрузку ссылка; никаких ошибок или чего-либо (насколько я могу судить).

Есть ли какой-то способ программно определить, является ли URL-адрес данных слишком большим? Может быть, какое-то событие в браузере, которое покажет мне, не удалось ли щелкнуть ссылку загрузки?

В идеале, я хотел бы определить, была ли загрузка успешной. Когда URL-адреса данных слишком велики, я хотел бы показать объяснение для конечного пользователя, описывающее, как щелкнуть правой кнопкой мыши по изображению и выбрать «сохранить как ...», который всегда работает.

Update 1:

Похоже, используя canvas.toBlob лучший обходной путь на данный момент. Вот документация api: https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toBlob.

Вот jsfiddle, который демонстрирует, как якорь HREF ссылки для скачивания сбой при использовании toDataURL для больших холстах, но toBlob, кажется, работает:

https://jsfiddle.net/upgradingdave/c76q34ac/3/

Вот некоторые StackOverflow вопросы: canvas.toDataURL() download size limit

Data protocol URL size limitations

+1

Таким образом, Chrome бесшумно выходит из строя ... Когда Chrome не может предоставить избыточный URL-адрес данных, 'console.log (theDataURL.length)' сообщает нулевую длину или что-то еще? – markE

+0

Спасибо за идею. Похоже, что 'theDataURL.length' возвращает правильную длину, даже если загрузка не удалась, к сожалению. – Upgradingdave

+0

Простой любопытство, какова длина строки? Также вы можете попытаться установить dataURI как src img во время прослушивания его события ошибки. Не уверен, что он срабатывает, так как я никогда не производил слишком длинный dataURI, но если это не так, я думаю, это ошибка. (В прошлый раз, когда я пытался достичь этих ограничений, (не пытаясь загрузить), я нажимал maxLength строки перед maxLength dataURI, вы уверены, что это не что-то вроде хита памяти?) – Kaiido

ответ

6

Нет, не представляется возможным провести какое-либо событие вы знаете, действительно ли привязке с атрибутом download удалось загрузить ресурс.

Но ограничение, с которым вы сталкиваетесь, похоже, касается только этой ситуации: анкерный элемент <a> с атрибутом download.

Браузер может обрабатывать более длинный dataURI (я думаю, что в большинстве браузеров ограничение такое же, как и для длины строк). Например, он может загрузить его в элемент <img>, и, что более важно, в вашем случае он может обрабатывать строку dataURI.

Это важно, потому что это позволяет вам преобразовать этот dataURI в blob, а затем создать object URL из этого blob. object URL URI являются маленькими и не сталкиваются с этим ограничением длины в якорях с атрибутом download.

Так что лучше в вашем случае, вероятно, напрямую использовать canvas.toBlob метод (a polyfill is available on mdn), и передать Ури object URL «s как href вашего якоря.

var img = new Image(); 
img.crossOrigin = "anonymous"; 

img.onload = function(){ 
    var ctx = document.createElement('canvas').getContext('2d'); 
    ctx.canvas.width = this.width*10; 
    ctx.canvas.height = this.height*10; 
    ctx.drawImage(this,0,0,ctx.canvas.width, ctx.canvas.height); 
    // convert our canvas to a png blob 
    // (for type use the second parameter, third is for quality if type is image/jpeg or image/webp) 
    ctx.canvas.toBlob(function(blob){ 
    myAnchor.href = URL.createObjectURL(blob); 
    }); 
    // since we are dealing with use files, we absolutely need to revoke the ObjectURL as soon as possible 
    var revokeURL = function(){ 
    // but we have to wait that the browser actually prepared the file to download 
    requestAnimationFrame(function(){ 
     // we've waited one frame, it's seems to be enough 
     URL.revokeObjectURL(this.href); 
     this.href=null; 
     }); 
    this.removeEventListener('click', revokeURL); 
    }; 

    myAnchor.addEventListener('click', revokeURL); 
    }; 

img.src = 'http://lorempixel.com/200/200/'; 
<a id="myAnchor" download="anAwesomeImage.png">download</a> 

[ Live Demo ] (поскольку download атрибут блокируется некоторыми UA в SE-Snippets)

Но обратите внимание, что даже если строковое представление (URI) из object URL коротка, она будет фактически возьмите размер вашего файла в памяти браузера, и так пока вы не обновите страницу (очистка кеша) или не закроете вкладку, на которой вы создали этот URL-адрес объекта. Поэтому вам необходимо позвонить URL.revokeObjectURL(), чтобы очистить это пространство.
Но, поскольку нет никакого события, чтобы узнать, действительно ли загрузка действительно преуспела, вы застряли в событии onclick, которое запустит до. Из моих тестов ждать одного кадра с requestAnimationFrame достаточно, но я могу ошибаться.


И для тех, приезжающих сюда с другим источником, чем холст для их dataURI, уже есть много сообщений в SO о преобразовании dataURI в сгусток, и вы можете просто проверить MDN polyfill при условии выше, они делают это тоже.