billfeller.github.io
billfeller.github.io copied to clipboard
浏览器环境下获取图片内容能力调研
需求背景
将图片从Web页面快速分享到聊天窗口,当前实现方案是传图片url参数给客户端,然后客户端通过url拉取图片内容,将图片复制粘贴到聊天窗口。这种实现方法需要二次加载图片,影响用户体验,所以想调研下是否可以从本地直接获取图片内容,优化用户体验。
方向调研
- Web是否可以获取
图片内容?
- 客户端是否可以访问本地临时缓存资源池获取图片内容?
1. Web是否可以获取
图片内容?
首先,来看下 DOM接口定义如下:
[NamedConstructor=Image(optional unsigned long width, optional unsigned long height)]
interface HTMLImageElement : HTMLElement {
attribute DOMString alt;
attribute DOMString src;
attribute DOMString crossOrigin;
attribute DOMString useMap;
attribute boolean isMap;
attribute unsigned long width;
attribute unsigned long height;
readonly attribute unsigned long naturalWidth;
readonly attribute unsigned long naturalHeight;
readonly attribute boolean complete;
};
由此可见,接口设计没有暴露图片内容相关的数据给Web应用层访问,所以new Image是无法直接获取图片内容。
那么是否存在折中的方法呢?很幸运,Canvas提供了这样的能力,我们可以利用Canvas drawImage将Image写入到Canvas中,再调用toDataURL/toBlob导出图片内容来获取图片内容,由此来实现我们的目的。
var img = new Image,
canvas = document.createElement("canvas"),
ctx = canvas.getContext("2d"),
src = "http://example.com/image"; // insert image url here
img.crossOrigin = "Anonymous";
img.onload = function() {
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage( img, 0, 0 );
localStorage.setItem( "savedImageData", canvas.toDataURL("image/png") );
}
img.src = src;
// make sure the load event fires for cached images too
if ( img.complete || img.complete === undefined ) {
img.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";
img.src = src;
}
这种实现方式需要解决如下两个问题:
- 对于跨域的图片资源(诸如图片存储在CDN),需要【启用了 CORS 的图片】来避免污染Canvas;推荐使用Fiddler->Rules->Custom Rules自定义响应头模拟测试:
static function OnBeforeResponse(oSession: Session) { // ... if (oSession.HostnameIs("static.xxximg.com")) { oSession.oResponse["Access-Control-Allow-Origin"] = "*"; } }
- 对于动画图片(诸如动画gif格式,apng格式的图片),由于drawImage的实现机制,导致toDataURL只能获取单帧静态图片,详情请见testrefs.2d.drawImage.animated.image
When the drawImage() method is passed an animated image as its image argument, the user agent must use the poster frame of the animation, or, if there is no poster frame, the first frame of the animation # 2d.drawImage.animated.gif 2d.drawImage.animated.apng 2d.drawImage.animated.poster .
结论:
- 对于同源静态图片,Web可以通过Canvas获取图片内容;
- 对于跨域静态图片,需要图片服务器开启CORS,此时,Web可以通过Canvas获取图片内容;
- 对于动画图片,目前Canvas仅能获取海报帧或首帧,无法获取原始图片;