Можно ли программно определить ограничение по размеру для URL-адреса данных?

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

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

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

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

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

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

Обновление 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() размер ограничения загрузки

Ограничения на размер URL-адреса протокола передачи данных

Ответ 1

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

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

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

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

Итак, лучше всего в вашем случае, вероятно, использовать метод canvas.toBlob (a polyfill доступен на mdn) и передать object URL URI как 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 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- Отрывки)суб >

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


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