9

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

这在一定的图像尺寸下效果很好。

似乎不同的浏览器对数据 url 的大小有不同的限制,如此处所述: https ://developer.mozilla.org/en-US/docs/Web/HTTP/data_URIs

在 chrome 中,当我超过数据 url 大小限制时,单击下载链接时没有任何反应;没有错误或任何东西(据我所知)。

是否有某种方法可以以编程方式检测数据 url 是否太大?也许一些浏览器事件会告诉我点击下载链接是否失败?

理想情况下,我想检测下载是否成功。当数据 url 太大时,我想向最终用户显示一个解释,描述如何右键单击图像并选择“另存为 ...”,这似乎总是有效的。

更新1:

看起来 usingcanvas.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 大小限制

4

1 回答 1

10

不,似乎没有任何事件让您知道具有该download属性的锚点是否确实成功下载了资源。

但是,您面临的限制似乎只涉及这种情况:<a>具有download属性的锚元素。

浏览器可以处理更长的 dataURI(我认为在大多数浏览器中,限制与字符串长度的限制相同)。例如,它可以将其加载到<img>元素,更重要的是,在您的情况下,它可以处理 dataURI 字符串。

这很重要,因为它允许您将此 dataURI 转换为 blob,然后object URL从该 blob 创建一个。的 URI 很小,并且在具有属性object URL的锚点中不会遇到这种长度限制。download

因此,在您的情况下,最好的方法可能是直接使用该canvas.toBlob方法(在 mdn 上提供了一个 polyfill),并将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'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属性被 SE-Snippets 中的一些 UA 阻止)

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


对于那些带着其他来源而不是其 dataURI 的画布的人,SO 中已经有很多关于将 dataURI 转换为 blob 的帖子,你可以检查上面提供的 mdn polyfill,他们正在这样做也。

于 2016-04-30T05:59:12.417 回答