有一个Gif图片,我们想要获取它的总帧数,超过一定帧数的图片告知用户不可上传,在服务端有很多现成的库可以使用,这种做法不是很友好,前端需要先将gif上传至服务端,服务端解析完毕后将结果返回,大大降低了用户体验。,那么如何通过js在上传前就拿到它的总帧数来判断呢?本文就跟大家分享一种解决方案,并将其封装成插件发布至npm仓库,欢迎各位感兴趣的开发者阅读本文。,此插件已经发布至npm,采用原生JS编写支持任意一个前端框架,如果你对其实现原理不感兴趣,只是想拿来解决你的实际问题,可以直接通过npm/yarn来安装,命令如下:,文档地址请移步:README.md,我们都知道无论什么文件在计算机中都是以流的形式进行存储的,因此我们可以通过读取文件流来拿到它的所有信息。Gif类型的文件也是如此,我们只要能知道它的文件流结构就可以根据它的规则进行解析读取了。,Gif的全称是Graphics Interchange Format,是一种位图,以8位色重现真彩色的图像。采用LZW压缩算法进行编码,可以有效的减少图像文件在网上的传输时间,我们在网站上看到的会动的表情包,基本上都是Gif格式的。,正如上面所说,我们想解析gif就得先知道它的文件流结构,在What's In A GIF网站中我们知道了它是由多种不同类型的块组成,如下所示:,了解完gif的组成结构后,接下来我们来看下如何获取它的数据流,如下所示:,它的解码过程如下图所示:,GIF file stream diagram,注意:在读取过程中,每个块都有自己特殊的编码标记。,我们了解完gif的构成后,接下来我们来看下每一个具体的数据块的编码信息。,该数据块用于标记数据流的开始,位于文件头数据流的上下文内,里面包含了gif的签名与版本信息,它是必须存在的且只有一个。,该块在数据流中占6个字节,其中签名与版本信息各占3个字节,即:,我们以89a格式的gif为例,它的Header信息就如下所示:,GIF header block layout,我们来看下如何用代码来读取。,该数据块中定义了图像在设备中显示所需的参数,位于Header数据块的后面,它是必须存在的且只有一个,其值的坐标是相对于虚拟屏幕左上角计算出来的。,该块在数据流中占7个字节,包含的信息如下所示:,Global Color Table Flag 全局颜色标记,用于标识全局颜色表。如果值为0则表示不存在全局颜色块;如果值为1则表示全局颜色块紧跟于此块之后。,Color Resolution 颜色分辨率,即颜色的位数,有1位、8位、16位、32位等。在gif格式的图像定义中,它的颜色不能超过256种,深度不能超过8位。,Sort Flag 排序标记,0为未设置,1为按重要性递减排序,最重要的颜色在前。,Size of Global Color Table 全局颜色表的大小,如果值为1,则该字段中的值用于计算全局颜色表中包含的字节数。,GIF logical screen descriptor block layout,我们用代码来获取下它的宽度与高度。,该数据块包含了一个颜色表,由红-绿-蓝三元组的字节序列构成。正如前面所说,它并非必须存在,如果存在的话它将位于Logical Screen Descriptor块的后面。,所占的字节数为3*2^(N+1),N为全局颜色表的大小 + 1,该数据块在数据流中只存在一个,如下图所示。,GIF global color table block layout,我们来看下代码的实现。,该数据块包含了处理图形渲染块时需要使用的参数,它只包含了一个数据子块。该块中记录了7种数据的描述,如下所示:,Reserved for Future Use 保留模块。,Disposal Method 处理方法,表示图形在显示后的处理方式。,User Input Flag 用户输入标识,在继续之前是否需要用户输入,如果是0则不需要用户输入,1代表需要用户输入。输入的性质由程序决定(如回车、鼠标点击等)。,Transparency Color Flag 透明标识,用于描述是否在透明索引字段中给出了透明索引。0:未给出透明索引;1:给出了透明索引。,GIF graphic control extension block layout,此处我们最关心的就是如何取出gif每一帧的时长,我们来看下代码的实现。,一个gif文件可能会包含多个图像,每个图像都以一个图像描述符块开始。这个块在数据流中占10个字节。该块中记录了6种数据的描述,如下所示:,Local Color Table Flag 局部颜色表标志,紧跟在该图像描述符之后的局部颜色表的存在,0:不存在,则使用全局颜色表,1:存在,则使用紧跟其后的Local Color Table数据块。,Interlace Flag 隔行标志,标识图像是否是隔行的(图像以四遍交错模式交错)。,Sort Flag 排序标志 - 指示本地颜色表是否已排序。0:未设置排序,1:按重要性递减排序,最重要的颜色在前。,Size of Local Color Table 局部颜色表的大小。,GIF image descriptor block layout,该块由一系列子块组成,每个子块的大小最多为255字节,包含对图像中每个像素的活动颜色表的索引, 像素索引按从左到右和从上到下的顺序排列。每个索引必须在活动颜色表的大小范围内,从 0 开始。索引序列使用具有可变长度代码的 LZW 算法进行编码,如下所示。,GIF image data block layout,GIF image data block layout,每解析完一轮Image Descriptor都需要读取下Data Sub-blocks,直至所有子块被读取完毕。,通过前面的了解,我们知道了Gif图像中每个数据块的组成原理,接下来我们就可以编写代码来解决我们所遇到的问题了。,我们将数据块分析章节的思路整理下,核心代码如下所示:,最后,我们将插件打包,写一个简单的demo来测试下。,运行结果如下所示。,
© 版权声明
文章版权归作者所有,未经允许请勿转载。