服务热线:13616026886

技术文档 欢迎使用技术文档,我们为你提供从新手到专业开发者的所有资源,你也可以通过它日益精进

位置:首页 > 技术文档 > JAVA > 新手入门 > 基础入门 > 查看文档

png文件结构分析之二(在手机上生成png文件)

上面我们已经对png的存储格式有了了解,因此,生成png图片只需要按照以上的数据块写入文件即可。

(由于ihdr、plte的结构都非常简单,因此,这里我们只是重点讲一讲idat的生成方法,ihdr和plte的数据内容都沿用以上的数据内容)

问题确实是这样的,我们知道,对于大多数的图形文件来说,我们都可以将实际的图像内容映射为一个二维的颜色数组,对于上面的png文件,由于它用的是16色的调色板(实际是13色),因此,对于图片的映射可以如下:

png文件结构分析之二(在手机上生成png文件)(图一)
(调色板对照图)

12 11 10 9 8 7 6 5
11 10 9 8 7 6 5 4
10 9 8 7 6 5 4 3
9 8 7 6 5 4 3 2
8 7 6 5 4 3 2 1
7 6 5 4 3 2 1 0
6 5 4 3 2 1 0 0
5 4 3 2 1 0 0 0

png spec中指出,如果png文件不是采用隔行扫描方法存储的话,那么,数据是按照行(scanline)来存储的,为了区分第一行,png规定在每一行的前面加上0以示区分,因此,上面的图像映射应该如下:

0 12 11 10 9 8 7 6 5
0 11 10 9 8 7 6 5 4
0 10 9 8 7 6 5 4 3
0 9 8 7 6 5 4 3 2
0 8 7 6 5 4 3 2 1
0 7 6 5 4 3 2 1 0
0 6 5 4 3 2 1 0 0
0 5 4 3 2 1 0 0 0

另外,需要注意的是,由于png在存储图像时为了节省空间,因此每一行是按照位(bit)来存储的,而并不是我们想象的字节(byte),如果你没有忘记的话,我们的ihdr数据块中的色深就指明了这一点,所以,为了凑成png所需要的idat,我们的数据得改成如下:

0 203 169 135 101
0 186 152 118 84
0 169 135 101 67
0 152 118 84 50
0 135 101 67 33
0 118 84 50 16
0 101 67 33 0
0 84 50 16 0

最后,我们对这些数据进行lz77压缩就可以得到idat的正确内容了。

然而,事情并不是这么简单,因为我们研究的是手机上的png,如果需要在手机上完成lz77压缩工作,消耗的时间是可想而知的,因此,我们得再想办法加减少压缩时消耗的时间。

好在lz77也提供了无压缩的压缩方法(奇怪吧?),因此,我们只需要简单的使用无压缩的方式写入数据就可以了,这样虽然浪费了空间,却换回了时间!

好了,让我们看一看怎么样凑成无压缩的lz77压缩块:

字节
意义
0~2压缩信息,固定为0x78, 0xda, 0x1
3~6压缩块的len和nlen信息
压缩的数据
最后4字节adler32信息

其中的len是指数据的长度,占用两个字节,对于我们的图像来说,第一个scan line包含了5个字节(如第一行的0, 203, 169, 135, 101),所以len的值为5(字节/行) * 8(行) = 40(字节),生成字节为28 00(低字节在前),nlen是len的补码,即nlen = len ^ 0xffff,所以nlen的为 d7 ff,adler32信息为24 a7 0b a4(具体算法见源程序),因此,按照这样的顺序,我们生成idat数据块,最后,我们将ihdr、plte、idat和iend数据块写入文件中,就可以得到png文件了,如图:

png文件结构分析之二(在手机上生成png文件)(图二)

点击查看大图

(选中的部分为生成的“压缩”数据)

至此,我们已经能够采用最快的时间将数组转换为png图片了。

生成的png文件:png文件结构分析之二(在手机上生成png文件)(图三)

范例(附源程序)

  • 有效的减少png格式文件的大小
  • 通过改变调色板实现类似云彩流动的效果(源程序包含在此jar文件中)

扫描关注微信公众号