是否可以通过编程方式检测数据 url 的大小限制?
Is it possible to programmatically detect size limit for data url?
我正在使用 javascript 和 html canvas 来调整 jpeg 图片的大小。调整大小后,我使用 canvas.toDataURL
作为锚标记中的 href 属性,以便提供 link 用户可以在其中下载调整大小的图像。
对于特定的图像大小,此方法效果很好。
似乎不同的浏览器对数据url的大小有不同的限制,如下所述:
https://developer.mozilla.org/en-US/docs/Web/HTTP/data_URIs
在chrome中,当我超过数据url大小限制时,点击下载时没有任何反应link;没有错误或任何东西(据我所知)。
是否有某种方法可以通过编程方式检测数据 url 是否过大?也许一些浏览器事件会告诉我点击下载 link 是否失败?
理想情况下,我想检测是否下载成功。当数据 url 太大时,我想向最终用户显示说明,说明如何右键单击图像并选择 "save as ...",这似乎总是有效。
更新 1:
看起来使用 canvas.toBlob
是目前最好的解决方法。这是 api 文档:https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toBlob。
这是一个 jsfiddle,演示了在使用 toDataURL
较大的 canvases 时锚点 href 下载 links 如何失败,但 toBlob
似乎有效:
https://jsfiddle.net/upgradingdave/c76q34ac/3/
以下是一些相关的 Whosebug 问题:
Data protocol URL size limitations
不,似乎没有任何事件可以让您知道具有 download
属性的锚点是否真的成功下载了资源。
但是,您面临的限制似乎只涉及这种情况:具有 download
属性的锚元素 <a>
。
浏览器可以处理更长的 dataURI(我认为在大多数浏览器中,限制与字符串长度的限制相同)。例如,它可以将其加载到 <img>
元素,更重要的是,在您的情况下,它可以处理 dataURI 字符串。
这很重要,因为它允许您将此 dataURI 转换为 blob,然后从该 blob 创建 object URL
。 object URL
的 URI 很小,在具有 download
属性的锚点中不会面临这种长度限制。
所以在你的情况下最好的可能是直接使用 canvas.toBlob
方法(a polyfill is available on 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'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 屏蔽了)
但请注意,即使 object URL
的字符串表示形式 (URI) 很短,它实际上也会占用浏览器内存中文件的大小,因此直到您硬刷新页面(清除缓存),或关闭您创建此对象的选项卡 URL。所以你绝对需要调用 URL.revokeObjectURL()
来清除这个 space.
但是,由于没有事件可以知道下载是否真正成功,因此您将陷入 onclick
事件,该事件将在文件下载发生 之前 触发。根据我的测试,等待 requestAnimationFrame
的单帧就足够了,但我可能错了。
对于那些使用其他来源而非 canvas 作为其 dataURI 的人来说,SO 中已经有很多关于将 dataURI 转换为 blob 的帖子,您可以查看 mdn上面提供的polyfill,他们也在做。
我正在使用 javascript 和 html canvas 来调整 jpeg 图片的大小。调整大小后,我使用 canvas.toDataURL
作为锚标记中的 href 属性,以便提供 link 用户可以在其中下载调整大小的图像。
对于特定的图像大小,此方法效果很好。
似乎不同的浏览器对数据url的大小有不同的限制,如下所述: https://developer.mozilla.org/en-US/docs/Web/HTTP/data_URIs
在chrome中,当我超过数据url大小限制时,点击下载时没有任何反应link;没有错误或任何东西(据我所知)。
是否有某种方法可以通过编程方式检测数据 url 是否过大?也许一些浏览器事件会告诉我点击下载 link 是否失败?
理想情况下,我想检测是否下载成功。当数据 url 太大时,我想向最终用户显示说明,说明如何右键单击图像并选择 "save as ...",这似乎总是有效。
更新 1:
看起来使用 canvas.toBlob
是目前最好的解决方法。这是 api 文档:https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toBlob。
这是一个 jsfiddle,演示了在使用 toDataURL
较大的 canvases 时锚点 href 下载 links 如何失败,但 toBlob
似乎有效:
https://jsfiddle.net/upgradingdave/c76q34ac/3/
以下是一些相关的 Whosebug 问题:
Data protocol URL size limitations
不,似乎没有任何事件可以让您知道具有 download
属性的锚点是否真的成功下载了资源。
但是,您面临的限制似乎只涉及这种情况:具有 download
属性的锚元素 <a>
。
浏览器可以处理更长的 dataURI(我认为在大多数浏览器中,限制与字符串长度的限制相同)。例如,它可以将其加载到 <img>
元素,更重要的是,在您的情况下,它可以处理 dataURI 字符串。
这很重要,因为它允许您将此 dataURI 转换为 blob,然后从该 blob 创建 object URL
。 object URL
的 URI 很小,在具有 download
属性的锚点中不会面临这种长度限制。
所以在你的情况下最好的可能是直接使用 canvas.toBlob
方法(a polyfill is available on 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'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 屏蔽了)
但请注意,即使 object URL
的字符串表示形式 (URI) 很短,它实际上也会占用浏览器内存中文件的大小,因此直到您硬刷新页面(清除缓存),或关闭您创建此对象的选项卡 URL。所以你绝对需要调用 URL.revokeObjectURL()
来清除这个 space.
但是,由于没有事件可以知道下载是否真正成功,因此您将陷入 onclick
事件,该事件将在文件下载发生 之前 触发。根据我的测试,等待 requestAnimationFrame
的单帧就足够了,但我可能错了。
对于那些使用其他来源而非 canvas 作为其 dataURI 的人来说,SO 中已经有很多关于将 dataURI 转换为 blob 的帖子,您可以查看 mdn上面提供的polyfill,他们也在做。