是否可以以编程方式检测数据 url 的大小限制? [英] Is it possible to programmatically detect size limit for data url?

查看:21
本文介绍了是否可以以编程方式检测数据 url 的大小限制?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 javascript 和 html canvas 来调整 jpeg 图像的大小.调整大小后,我使用 canvas.toDataURL 作为锚标记中的 href 属性,以提供用户可以下载调整大小的图像的链接.

这在达到特定图像尺寸时效果很好.

似乎不同的浏览器对数据 url 的大小有不同的限制,如下所述: 来自这个 blob.object URL 的 URI 很小,并且在具有 download 属性的锚点中不会遇到这种长度限制.

所以在你的情况下最好的可能是直接使用 canvas.toBlob 方法 (一个 polyfill 在 mdn 上可用),并将 object URL 的 URI 作为 href你的锚.

var img = new Image();img.crossOrigin = "匿名";img.onload = 函数(){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);//将我们的画布转换为 png blob//(对于类型使用第二个参数,如果类型是 image/jpeg 或 image/webp,则第三个是用于质量)ctx.canvas.toBlob(函数(blob){myAnchor.href = URL.createObjectURL(blob);});//因为我们是在处理use文件,所以绝对需要尽快撤销ObjectURLvar revokeURL = function(){//但我们必须等待浏览器真正准备好要下载的文件请求动画帧(函数(){//我们已经等了一帧,似乎已经足够了URL.revokeObjectURL(this.href);this.href=null;});this.removeEventListener('click', revokeURL);};myAnchor.addEventListener('click', revokeURL);};img.src = 'http://lorempixel.com/200/200/';

download

[ 现场演示 ] (自 download 属性被 SE-Snippets 中的某些 UA 阻止)

但请注意,即使 object URL 的字符串表示 (URI) 很短,它实际上也会占用浏览器内存中文件的大小,因此直到您硬刷新页面(清除缓存),或关闭您创建此对象 URL 的选项卡.所以你绝对需要调用 URL.revokeObjectURL() 来清除这个空间.
但是,由于没有事件知道下载是否真的成功,您会被 onclick 事件困住,该事件将在文件下载发生之前触发.从我的测试来看,等待带有 requestAnimationFrame 的单帧就足够了,但我可能错了.

<小时>

对于那些带着其他来源而不是画布来获取 dataURI 的人来说,SO 中已经有很多关于将 dataURI 转换为 blob 的帖子,您可以查看上面提供的 mdn polyfill,他们也在做.

I'm using javascript and html canvas to resize jpeg images. After resizing, I use canvas.toDataURL as the href attribute in an anchor tag in order to provide a link where users can download the resized images.

This works nicely up to a certain image size.

It seems that different browsers have different limits on the size of data urls as mentioned here: https://developer.mozilla.org/en-US/docs/Web/HTTP/data_URIs

In chrome, when I'm over the data url size limit, nothing happens when I click on the download link; no errors or anything (as far as I can tell).

Is there a some way to programmatically detect whether a data url is too large? Maybe some browser event that will show me whether clicking a download link failed?

Ideally, I'd like to detect whether the download was successful. When data urls are too large, I'd like to display an explanation to the end user describing how to right click on the image and choose "save as ...", which always seems to work.

Update 1:

It looks like using canvas.toBlob is the best workaround for now. Here's the api documentation: https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toBlob.

Here's a jsfiddle that demonstrates how anchor href download links fail when using toDataURL for larger canvases, but toBlob seems to work:

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

Here are some related stackoverflow questions: canvas.toDataURL() download size limit

Data protocol URL size limitations

解决方案

No, there doesn't seem to be any event letting you know if an anchor with the download attribute actually succeeded to download the resource.

But, the limitation you are facing seems to only concern this situation : an anchor element <a> with the download attribute.

The browser can handle way longer dataURI (I think that in most browsers the limitation is the same as the one for strings length). E.g, it can load it to <img> element, and more importantly in your case, it can process the dataURI string.

This is important because it allows you to convert this dataURI to a blob, then to create an object URL from this blob. object URL's URI are small and don't face this length limitation in anchors with download attribute.

So the best in your case is probably to directly use the canvas.toBlob method (a polyfill is available on mdn), and to pass the object URL's URI as the href of your anchor.

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 ] (since download attribute is blocked by some UA in SE-Snippets)

But note that even if the string representation (URI) of the object URL is short, it will actually take the size of your file in browser's memory, and so until you hard-refresh the page (clearing cache), or close the tab where you created this object URL. So you'll absolutely need to call URL.revokeObjectURL() to clear this space.
But, since there is no event to know if the downloading actually succeeded, you're stuck with the onclick event, which will fire before the file downloading occurred. From my tests, waiting for a single frame with requestAnimationFrame is enough, but I may be wrong.


And for the ones coming here with an other source than a canvas for their dataURI, there are already a lot of posts in SO about converting a dataURI to a blob, and you can just check the mdn polyfill provided above, they're doing it too.

这篇关于是否可以以编程方式检测数据 url 的大小限制?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆