合成GIF时的透明处理与优化
在与图片相关的开发中难免会遇到gif的处理,由于gif这种格式的局限性,可能合成的gif文件和自己预想的出现明显差别。在我们的项目中就曾长期受到,透明图片合成gif后,透明位置变成黑色的问题困扰,我们就将bitmap添加一个白色的不透明背景,但是显而易见,这不是根本上解决问题的方法。想要解决这个问题需要从gif文件内部处理,改进编码器的代码,而且合理地利用gif中的透明,还能带来其它的一些好处。
Gif文件解析
gif是基于颜色列表的,最多只支持8位(256色),图像中每一个像素被映射为一个在颜色列表中的索引值,GIF文件内部是按块划分的,包括控制块和数据块,GIF文件内部分成许多存储块,用来存储多幅图象或者是决定图象表现行为的控制块,用以实现动画和交互式应用。关于gif文件的解析可以参考[https://blog.csdn.net/wzy198852/article/details/17266507]。
图形控制扩展块可以放在一个图象块的前面,用来控制该图形控制扩展块后面跟着的这个图像渲染形式。
更改图形控制扩展块的信息,是使合成的gif支持透明的关键。透明颜色标志(Transparent Color Flag):置位表示使用透明颜色。透明色索引(Transparent Color Index),表示透明色索引值,也就是说,如果图像块中的一个像素是透明色索引值,那么在该帧渲染的时候这个像素是会作为透明处理的。
Gif支持透明的处理方法
透明色索引
上文已经说明了透明色索引的作用,如果能够确定透明色索引的值就能确定图像中的哪些位置是透明的。因为透明色索引值是颜色列表0-255中的一个,所以会使人进入一个误区,认为透明索引和颜色列表之间有着紧密的关系,往往会考虑是不是该优化生成颜色列表的方法,找到合适的透明索引的值。实际上二者之间可以没有必然的关联,透明色索引值只是让图像块中与该值相等的像素表现为透明,这与颜色列表没有任何关系。
所以,可以直接给透明色索引值设为0-255中的一个,比如,我们直接将该值设定为255。
// 是否透明
int transparent = -1;
int transIndex = -1;
//分析每一个像素
for (int i = 0; i < data.length; i++) {
//存在透明
if (dispose == 0 ((data[i] >> 24) & 0xFF) == 0) {
transparent = 1;
}
...
}
//有透明像素则将透明索引赋255
if (transparent != -1) {
transIndex = 255;
}
颜色列表
在gif中有全局颜色列表和局部颜色列表,当一个图像块有局部颜色列表就会使用局部颜色列表,没有局部颜色列表才会使用全局颜色列表。通常都是根据该帧图片生成其对应的局部颜色列表,如果追求较高的质量,每一帧的局部颜色列表还是很有必要的。但是不管是什么颜色列表,最多只支持256色,在颜色列表中每个颜色索引对应的颜色由三个字节,按R、G、B的顺序排列组成。
由于之前,已经存在了透明色的索引,所以在播放gif的时候,如果某一像素是与透明色索引值相同,那么该像素就是透明的而不会再去考虑这个索引值在颜色列表中所表示的颜色,颜色列表中的这个索引位置存储的RGB信息其实是没有意义的。所以,做法就很简单了,我们在生成的颜色列表中要空出一位透明色索引的位置。比如,我们设定透明色索引的索引值为255,那么在256色的颜色列表中,只生成255色颜色列表数组,存储在颜色列表的前255位中。
for (int i = 0; i < data.length; i++) {
if (dispose == 0 && (