AxeSlide软件项目梳理   canvas绘图系列知识点整理

背景介绍

我们的软件支持插入gif图片,并且展示在软件里是动态的,例如插入下面这张gif图。

在软件里显示的同样是这样的动态效果:

那么这张动态的图是怎么绘制到canvas上面的呢,如果只是像绘制一张普通图片用context.drawImage(img,x,y),这样绘制出来的只是当前显示到img标签的一个静态画面。

下面介绍我们项目中使用的方法:

1. 解析gif文件信息

安装Node.js的gify-parse模块,该模块用于解析gif文件信息的API。

具体使用和介绍参见: https://www.npmjs.com/package/gify-parse

我们读取上面那张gif图到buffer然后用该模块解析出的结果如下图:

注意:解析出来的结果有点小问题,宽高的值是颠倒的

利用上面图1中的gifInfo信息,我们用animated=true判定这张图确实是gif图,它是由24张图组成,每张图的宽高为384*288

利用上面图2中的delay这个属性值,它表示两张图变换的间隔时间,在接下来的第3步绘制大图到canvas中会用到这个属性。

2. 拼大图

我们的思路就是把gif中包含的24张图拼成一张大图片,拼大图我们利用canvas,将24张图挨个绘制到临时的一个canvas上面,最后将canvas保存成本地png文件。

下面的代码用来计算我们的画布tempCanvas的宽高:

 1 var tempCavas = <HTMLCanvasElement>document.createElement("canvas");
 2 //canvas元素的宽在大约40000的时候,将无法进行绘图
 3 //设置30000为最大值
 4 var shouldWidth = gifInfo.width * gifInfo.images.length;
 5 if (shouldWidth > 30000) {
 6     tempCavas.width = Math.floor(30000 / gifInfo.width) * gifInfo.width;
 7     tempCavas.height = Math.ceil(gifInfo.images.length / Math.floor(30000 / gifInfo.width))*gifInfo.height;
 8 }else {
 9     tempCavas.width = shouldWidth;
10     tempCavas.height = gifInfo.height;
11 }

gify-parse模块只解析出来了宽高等一部分有用信息那么,不能得到每张具体的图片。

我们需要引入gif模块,https://github.com/liufangfang/gif 从这里下载即可,该模块很简单只有一个函数function(gifSrcPath, callBack) {},传入gif图片文件路径和一个回调函数,回调函数接收错误信息和每个帧存储到本地的图片路径callBack(null, pathList)。

下面就看我们的回调函数如何利用这个文件列表files:

1)基本思路就是通过createElement("img")创建IMG标签

2)img.onload之后将图片绘制到canvas.context上,当然绘制的位置是需要根据当前图片是gif图中第几帧位置去计算的

3)绘制完最后一张后,将canvas转换成图片信息保存到本地

cxt.drawImage(tempImage, 0, 0, gifInfo.width, gifInfo.height, startx, starty, gifInfo.width, gifInfo.height);
 1 require('gif')(path,(error, files: Array<string>) => {
 2     if (error) {
 3         Logger.setErrLog(LogCode.image, "文件:File,方法:node_modules-gif,异常信息:" + error);
 4         callBack(null);
 5     }
 6     files.forEach((file, index) => {
 7         var targetDir = FileSytem.imageTempDir + id + index + ".jpg";
 8
 9         FileSytem.copySync(file, targetDir);
10
11         try
12         {
13             var tempImage = <HTMLImageElement>document.createElement("img");
14             var tempImageSrc = targetDir;
15             tempImage.id = index.toString();
16             tempImage.src = tempImageSrc;
17             tempImage.onload = (ev: Event) => {
18                 try
19                 {  //计算该张图片绘制到canvas上的位置
20                     var atWidth = gifInfo.width * Number(tempImage.id);
21                     var startx = atWidth % tempCavas.width;
22                     var starty = (atWidth / tempCavas.width | 0) * gifInfo.height;
23
24                     cxt.drawImage(tempImage, 0, 0, gifInfo.width, gifInfo.height, startx, starty, gifInfo.width, gifInfo.height);
25                     FileSytem.remove(tempImageSrc, null);
26                     ev.target = null;
27                     loadCounter++;
28                     if (gifInfo.images.length == loadCounter) {
29                         var dataBuffer = new Buffer(tempCavas.toDataURL("image/png").replace(/^data:image\/\w+;base64,/, ""), 'base64');
30                         var dataPath = FileSytem.imageDir + id + ".png";
31                         FileSytem.fileSaveSync(dataPath, dataBuffer);
32                         callBack(dataPath, tempCavas.width);
33                         tempCavas.width = 0;
34                         tempCavas.height = 0;
35                     }
36                 }
37                 catch (e) {
38                     Logger.setErrLog(LogCode.image, "文件:File,方法:gifToPng_1,异常信息:" + e);
39                     callBack(null);
40                 }
41             }
42         }
43         catch (e) {
44             Logger.setErrLog(LogCode.image, "文件:File,方法:gifToPng_2,异常信息:" + e);
45             callBack(null);
46         }
47     });
48 });

最后我们拼成的一张大图如下,如果帧数多或者较宽,因为我们设置了最宽30000px 所以就会出现多行的大图。

3.将大图绘制到canvas

插入gif到生成大图的过程已经写清楚了,那么怎么利用这张大图来绘制到canvas形成一张动态的效果图呢?

之前我们提到过插入的任何元素都继承自commonElement类,Image是继承commonElement,我们针对gif图插入的功能专门有一个类GifImage,而它继承自Image。这个类里面有个最主要的函数:将大图中的每一部分一张张的循环绘制,具体代码如下:

 1         private drawGif() {
 2             if (this.element && this.context) {
 3                 var lastFrame = this.gifInfo.images[this.currentFrame % this.gifInfo.images.length]
 4                 var nowTime = this.tempNowTime || Date.now();
 5                 if (nowTime- this.lastDrawTime >= lastFrame.delay) {//控制绘制的速度
 6                     this.currentFrame++;
 7                     this.lastDrawTime = nowTime;
 8                 }
 9                 var frameNum = this.currentFrame % this.gifInfo.images.length;//计算是该绘制第几张图
10
11                 this.context.save();
12                 this.rotate();
13                 //计算截取大图某一部分绘制到画布的其实坐标
14                 var atWidth = this.gifInfo.width * frameNum;
15                 var startx = atWidth % this.totalWidth;
16                 var starty = (atWidth / this.totalWidth | 0) * this.gifInfo.height;
17                 this.context.drawImage(this.element, startx, starty, this.gifInfo.width, this.gifInfo.height, this.config.translate.x, this.config.translate.y, this.config.width, this.config.height);
18                 this.context.restore();
19             }
20         }

转载于:https://www.cnblogs.com/fangsmile/p/6273714.html

软件项目技术点(9)——如何将gif动态图拆分绘制相关推荐

  1. 软件项目技术点(21)——自动保存和恢复

    AxeSlide软件项目梳理   canvas绘图系列知识点整理 自动保存的基本思路 1)软件每次打开都会创建一个保存画布元素信息的文件,文件名是在打开软件时生成的唯一字符串.可同时打开多个窗口,所以 ...

  2. 软件项目技术路线图_创建基本的项目路线图

    软件项目技术路线图 Continuing from my previous article, at this checkpoint, I have two things with me: 上一篇文章的 ...

  3. 软件项目技术路线图_为您的项目创建路线图

    软件项目技术路线图 Scrum has a tool for roadmap and release planning as well. We use two different mechanisms ...

  4. 软件项目技术点(4)——实现点击画布上元素

    AxeSlide软件项目梳理   canvas绘图系列知识点整理 元素和影子 我们在主画布上绘制所有添加到画布上的元素,主画布上的所有元素存储在commonElements中. 在hitCanvas上 ...

  5. 软件项目技术点(1)——Tween算法及缓动效果

    AxeSlide软件项目梳理   canvas绘图系列知识点整理 Tween算法及缓动效果 软件里在切换步序时需要有过渡动画效果,从当前位置的画面缓动到目标位置的画面.动画效果可重新查看文章系列第一篇 ...

  6. 软件项目技术点(25)——提升性能之检测绘制范围

    AxeSlide软件项目梳理   canvas绘图系列知识点整理 软件里的一个画面包含很多个元素,但是当缩放到某个局部位置时,需要绘制的元素个数就很少.那么怎么判断某个元素是否需要进行绘制呢? 我们在 ...

  7. 软件项目技术点(7)——在canvas上绘制自定义图形

    AxeSlide软件项目梳理   canvas绘图系列知识点整理 图形种类 目前我们软件可以绘制出来的形状有如下这几种,作为开发者我们一直想支持用户可以拖拽的类似word里面图形库,但目前还没有找到比 ...

  8. 软件项目技术点(20)——导出视频

    AxeSlide软件项目梳理   canvas绘图系列知识点整理 导出的视频和播放器自动播放效果时一样的,这样用户就可以传到视频网站分享出去,或者mp4文件发送分享给朋友. 导出视频过程 我们导出视频 ...

  9. 软件项目技术点(19)——文件的保存和打开(解压缩)

    AxeSlide软件项目梳理   canvas绘图系列知识点整理 保存文件 保存内容有哪些? 我们需要保存的内容信息 1)context.json 存储画布状态信息和所有元素的配置信息(这个文件在过程 ...

最新文章

  1. php远程下载头像,远程使用gravatar头像
  2. Apache Software Foundation Distribution Directory
  3. 查看python进程_[原创] 如何查看一个Python进程在”干什么”: py-spy 来帮忙 – 编码无悔 / Intent Focused...
  4. 1600k 打印头测试软件,更换LQ-1600K打印头断针的技巧
  5. 不缓存调用js的方法
  6. 自托管websocket和webapi部署云服务器域名及远程访问
  7. 苹果用户每天解锁iPhone手机80次
  8. 【2018蓝桥省赛A组C/C++】全球变暖(两次bfs+状态标记 or 一次dfs)
  9. ubuntu更新pip
  10. MATLAB简单实现ID3算法
  11. 透明这种颜色的html,透明颜色HTML5帆布
  12. 冷门游戏脚本开发软件-TC
  13. Chromedriver适用谷歌浏览器的各个版本
  14. 微信js-sdk引入!绝对干货
  15. PDF文件如何转成HTML格式?说一种思路
  16. 重学Android基础系列篇(五):Android虚拟机指令
  17. ssm毕设项目水果生鲜销售系统7826c(java+VUE+Mybatis+Maven+Mysql+sprnig)
  18. 一分钟了解Java Attach机制
  19. 2021年入职体检有哪些项目?
  20. 模态逻辑中的必然和可能

热门文章

  1. jsp文件第一行报错The superclass javax.servlet.http.HttpServlet was not found on the Jav
  2. 51单片机模拟交通信号灯控制系统设计
  3. 【毕业设计】爱琴海——基于HTML5的婚庆用品商城网页设计
  4. 源码分析 @angular/cdk 之 Portal 1
  5. 世界级压力传感器国际十大排名榜(干货)
  6. Springer出版社Word模板
  7. PyQt5实例 画板小程序
  8. Vue3.0 难产?Vue 最黑暗的一天
  9. 用友t3选择服务器无响应,用友T3用友通客户端访问服务器时响应很慢
  10. seaborn 0.9 文档翻译活动期待大家的参与~