这篇文章发布于 2015年12月5日,星期六,20:08,归类于 Canvas相关。 阅读 162010 次, 今日 15 次 41 条评论
by zhangxinxu from http://www.zhangxinxu.com
本文地址:http://www.zhangxinxu.com/wordpress/?p=5081
一、屋外:寒风吹,雪花飘;屋内:空调吹,代码飘
上午出去买菜,正好下雨了,还夹杂着冰珠子。鄙人大意,穿的是一件帅气但单薄的黄色大衣,立马冻成了中华田园犬。原本计划去钓鱼的,科科,作罢,上午在家看CCTV5 骑士队vs鹈鹕队,下午补动漫码代码做文章,好生惬意。
对于习惯性刷微博的我,总时不时会看到类似下面的游戏:
测测你今天会发生什么?ie浏览器的同学可以按esc键(或截屏),据说在哪个词暂停,哪个词就是你哦!
OK, 这里出现一个浏览器特性,就是通过ESC快捷键,暂停gif的播放。据说FireFox浏览器以前也有,后来被干掉了,根据@紫云妃的说法是:
是这样的,Firefox原来的表现是:在页面load事件完成,同时x按钮变成刷新按钮之后,esc仍然有几个作用,中断当前正在发送的ajax、websocket,停止gif、apng动画的播放.但这些功能太小众了,影响了普通用户的使用,可能不小心按了esc,结果ajax断了,网页出错了.所以Firefox20修改成:网页加载完成后,esc键完全失效.
然而,这种隐晦的但似乎会影响正常功能的小技巧显然是无法实现真正意义上的gif动态图片的停止与播放的。一是兼容性,二是功能性,三是移动端没有ESC键。
所以,如果我们遇到需要可以随时随地停止gif动态图片播放的需求的时候,就需要寻找其他的出路。好,寒冬里的暖身结束,开始进入正题~~
二、gif图片自己可控前提下的方法一:多img资源控制处理
假如说,我们希望暂停的gif是自己(开发人员)传上去的,不是用户可以随机上传不可控的gif. 我们可以这么处理,就是准备2套图片,一个是gif动态图片,还有一个是只有一帧的静止的图片。然后使用JS来回切换<img>
的src
值为这两张图片地址就好了。
此方法甚简单,我就不放实例了。
img.src="animate.gif";
// 或者呈现的是
img.src="static.png";
这个方法最大的优点就是兼容性强,所有浏览器都可以实现停止效果。然而,这种方法有个局限,就是,暂停时候呈现的图片永远是同一张。基本上可以说是停止,而不是暂停。
那有没有什么方法可以真正意义上的暂停呢?还真有!
三、gif图片自己可控前提下的方法二:CSS3 animation控制
也就是我们看到的gif效果并不是一个真正的gif图片,而是使用CSS3的animation属性控制形成的逐帧动态图片效果。我搜了下,@DO1路人乙有篇文章“css3-animation制作逐帧动画”专门介绍了这种技术。说穿了就是animation控制Sprites图片的background-position值模拟gif效果。
例如,新版twitter的Like的效果,貌似就有使用该技术:
使用CSS3 animation实现类gif效果的好处在于,图片可以无损,且我们可以很轻松地控制图片动画的暂停和播放,使用的是:animation-play-state: paused;
这个声明。
您可以狠狠地点击这里:使用CSS3 animation实现gif动图的暂停和播放demo
点击demo页面的暂停按钮,您会发现,直接就停住了,如下截图示意,截自IE10浏览器:
再次点击,就会在暂停画面之后继续播放了。从而实现了我们对动画图片的精确控制效果。
此方法看上去完美,但是,1. IE10+等支持CSS3 animation的浏览器才行;2. 最大的问题是图片需要是自己控制,如果想控制用户上传的真正意义的gif图片,只能……望洋兴叹……………………吗?
四、自己无法控制的gif图片的停止与播放
比方说,页面上用户上传了些gif图片,哎呀,闪瞎了我的中华田园眼,我要全部暂停,肿么办?如果后台同学没有对gif进行静态处理,此时,只能靠前端小伙伴,有什么办法吗?
有一个。HTML5 canvas可以读取图片信息,绘制当前图片。于是可以实现图片马赛克,模糊,色值过滤等很多图片特效。我们这里不用那么复杂,只要读取我们的图片,重绘下就可以。
您可以狠狠地点击这里:使用JS和canvas实现gif动图的停止和播放demo
点击按钮,然后:
如何使用?
我对HTMLImageElement原型进行了扩展,增加了stop()
和play()
两个方法,如下:
if ('getContext' in document.createElement('canvas')) { HTMLImageElement.prototype.play = function() { if (this.storeCanvas) { // 移除存储的canvas this.storeCanvas.parentElement.removeChild(this.storeCanvas); this.storeCanvas = null; // 透明度还原 image.style.opacity = ''; } if (this.storeUrl) { this.src = this.storeUrl; } }; HTMLImageElement.prototype.stop = function() { var canvas = document.createElement('canvas'); // 尺寸 var width = this.width, height = this.height; if (width && height) { // 存储之前的地址 if (!this.storeUrl) { this.storeUrl = this.src; } // canvas大小 canvas.width = width; canvas.height = height; // 绘制图片帧(第一帧) canvas.getContext('2d').drawImage(this, 0, 0, width, height); // 重置当前图片 try { this.src = canvas.toDataURL("image/gif"); } catch(e) { // 跨域 this.removeAttribute('src'); // 载入canvas元素 canvas.style.position = 'absolute'; // 前面插入图片 this.parentElement.insertBefore(canvas, this); // 隐藏原图 this.style.opacity = '0'; // 存储canvas this.storeCanvas = canvas; } } }; }
大家只要在页面中自己的JS文件中复制上面的代码,然后就可以直接:
var image = document.getElementsByTagName("img")[0]; // 停止gif图片 image.stop(); // 播放gif图片 image.play();
//zxx: 上面代码并未详尽测试,以及可能的体验问题(IE闪动)没有具体处理(影响原理示意),若要实际使用,需要自己再微调完美下。
不足
1. IE9+支持。IE7/IE8不支持canvas没搞头。
2. 只能停止gif,不能真正意义的暂停。因为canvas获得的gif图片信息为第一帧的信息,后面的貌似获取不到。要想实现暂停,而不是停止,还需要进一步研究,如果你有方法,非常欢迎分享。
更新于2020-08-11
可以试试使用libgif.js这个项目库暂停GIF,https://github.com/buzzfeed/libgif-js
可以对GIF文件进行完全的解析,因此,暂停具体的某一帧不在话下。
更新于2021-09-12
如果想要对 APNG 动图进行播放与暂停设置,可以参考这篇文章“APNG在线制作、兼容、播放和暂停”。
五、结束语
是胡不是霍,是霍躲不过!哈哈!
上面这个gif也是demo示意gif强力候选。后来一琢磨,看我文章的还是宅男多,腐女少,所以,你懂的……
——我是多年不见的低调的分隔线—–
本文gif比较多,如果您是移动设备查看本文,会发现,怎么我的电池怎么越来越瘦了!不是因为天冷冻小了,而是gif比较耗电。所以,从这个角度讲,我们其实有必要在移动端默认停止这些gif的播放,用户点击再播放。一来省流量,二来省电。
如果没有静态图片资源支持,那不妨试试文章出现的一些方法,有心得记得来这里反馈哈!
最后,本文的方法都是有瑕疵的,自己也尚未在实际项目中使用过。因此,假如阅读本文的您:
1. 有更完美的gif暂停与播放方法;
2. 发现文中方法有不足和遗漏;
都非常希望可以不吝赐教!
感谢阅读!周末温暖!
本文为原创文章,包含脚本行为,会经常更新知识点以及修正一些错误,因此转载请保留原出处,方便溯源,避免陈旧错误知识的误导,同时有更好的阅读体验。
本文地址:http://www.zhangxinxu.com/wordpress/?p=5081
(本篇完)
- 使用ImageDecoder API让GIF图片暂停播放 (0.524)
- HTML audio基础API完全使用指南 (0.424)
- JS实现图片相似度的判断 (0.125)
- 再说CSS3 animation实现点点点loading动画 (0.112)
- 渐进式jpeg(progressive jpeg)图片及其相关 (0.110)
- 前端设计必会技能-gif动画图片制作 (0.110)
- 纯前端实现可传图可字幕台词定制的GIF表情生成器 (0.100)
- 关于gif图片(或png8)杂边锯齿的问题 (0.085)
- 我要上头条——鑫表情包1.0正式发布 (0.085)
- APNG历史、特性简介以及APNG制作演示 (0.085)
- 告别图片—使用字符实现兼容性的圆角尖角效果beta版 (RANDOM - 0.025)
感谢楼主,跨越了八年的文章,心理上还是有些伤感的
很棒
能不能 把图片 分享一下 ……
想实现gif只播放一次的需求,查到这篇,很有帮助,谢谢旭哥
这个需求可以不用这个,gif默认导出来是无限播放的,你改一下你资源的播放次数为1次就可以了。PS时间轴那里可以看到和修改
请问你是怎么实现只播放一次的需求的,不改图片资源
旭爷、你#四的demo的gif挂啦。
感谢反馈。
突然发现你是我学长啊,谢谢啦,很好的文章
f (‘getContext’ in document.createElement(‘canvas’))是什么意思啊?
in运算符:测试一个对象中是否存在一种属性。
image.classList里面的classList哪里来的
classList是什么?
已发现问题。菜鸟就是菜鸟,哎
安卓手机动画不会动,加了-webkit- -moz- -o- 前缀也不会动。本人使用小米C4手机测试。装逼失败却不知道原因,求解答
为什么是28帧呢,这个怎么知道的
我也不明白啊,不是有29个图么?
css3控制的动态效果,是不是需要图片比较多呢
用canvas 我之前可以的,今天买个新电脑装的谷歌浏览器 把我以前的打开居然又不行了,难道是谷歌浏览器版本高了 就不兼容了?谷歌版本51.0.2704.106 m,而且你提供的链接地址 (http://www.zhangxinxu.com/study/201512/gif-stop-and-play-by-js-canvas.html)浏览器也实现不了停止,点停止就跑到第一针去了
见过一个gif转mp4,实现暂停。
大赞。。。
求gif图片出处!老司机带带我,给我个种子呀!/pt/pt/pt
嗯,以后腐女也是多多的
前端不看张鑫旭,看遍博客也枉然,望大牛能带领我们走向光明
可以试一试 JavaScript GIF parser and player
https://github.com/buzzfeed/libgif-js
this is done by downloading the GIF (with XMLHttpRequest), parsing it, and drawing it on a .
问题 : 为什么 Firefox 的 命令行工具 能完美 截取 任意状态的网页? 包括 gif animation。。。
shift +F2 : screenshot 4.png
只是 Firefox 的黑科技么?
忘解答,谢谢
下载下来,然后解析出每一帧
回复主要是说,这种文还是有腐女会看的
+1,我也想说这个
文中看到曾经本人写的博客专门探讨的一个内容
css3 animation过渡函数Steps
有兴趣的同学可以看看我的这篇文章哦:
http://www.cnblogs.com/danielweb/p/4513081.html
demo的图片能不能别搞妹子。。都不敢上班的时候看
是的啊,最好加个功能切换,上班模式/下班模式
话说 那个 `canvas暂停gif` 惊到我的中华田园眼了 很有料(代码跟动画内容)
我想问一个疑惑,在“新版twitter的Like的效果”的DEMO页面中,“.love”方法有一个“background-size: 2900%;”的设置,为什么不使用“background-size: auto 100%;”的设置呢?如果后期要再加减一些效果,前者的写法,不是需要修改CSS文件吗,请指教!
@张 你确定
background-size: auto 100%
是你想要的效果?说是疑惑,是因为我在各浏览器都有测试一下,
background-size:auto 100%
和background-size:2900%
并没有发现什么区别,而在我看来,前者的写法,更适合扩展,所以不理解。这里,请指教!
或者情点拨一下,是哪方面的问题,谢谢!
https://gist.github.com/MaverickTse/b56792794c62a9e0ab20
这里有解答,是因为有29帧的缘故
赞。。。
为何这么叼
赞。。。
鑫神 666