基友写的一个libgif终于出现了虫子,只要导出一张纯色的gif立刻卒,症状为导出文件正常,然而无法播放,资源管理器无法查看预览和缩略图,所有浏览器包括Edge、IE、Chrome、FF打开它全挂。PS打开正常,扔到QQ里能正常播放但是发送直接提示发送失败,甚是邪门。于是一脸不甘心的探个究竟。
打开gif89a specification,直接上UE,翻到Image Descriptor部分,如图:
按照文档,颜色表标记为0x80,表示为本地颜色表存在|不排序|非交错|颜色表大小为2^(0+1)个,而后6字节为颜色表,0x01起为LZW压缩段落,看上去貌似一切正常。
一脸不死心拽了一个NGif,调试起来,竟然能正常解码!这说明LZW段落没有问题。用GDI+随便加了一个颜色像素点,导出的GIF各种可以播放。试着缩小文件大小,依然导出纯色GIF,诶!GDI+可以正常加载了,windows图片浏览也可以正常查看了。逐渐放大这个值,发现图像大小在286*286时至少可以在IE/GDI+下正常运作,当扩大到287*287时,图片挂掉。但是即使是极小的单色GIF,其他浏览器也无法正常显示。
GDI+和IE或者图片浏览统一用WIC解码,一起挂掉属于必然。LZW段又没有问题,所以问题还是出现在本地颜色表上。
仔细看gif89a描述文档,它是这么说的:
如果没有本地颜色表,颜色表大小的数值需要为0。这和我们上面生成的GIF刚好反过来:我们是存在本地颜色表,但是数值依然为0(来表示实际上颜色表大小为2)。这实质上可能对图像解码造成歧义,导致解码器误认为不存在本地颜色表,直接把后面颜色表部分当成是LZW压缩段而解析失败。当数值为1(表示颜色表大小为4)时,歧义消失,图像可以正常解析。
最后解决办法当然是:
篡改encoder代码,强行使量化后有效颜色大于3(原本是纯色+透明色),使颜色表大小至少为2^2,问题解决。
不过至今不知道为什么WIC的解码器可以识别某个阈值大小下的图像。PS能解析大概是因为啊逗逼的猴子按照文档正直的识别了下来,至于其他主流浏览器,大概直接弃疗了吧╮(╯-╰)╭
网友评论