博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
J2ME平台PNG图像压缩、解压与加密技术
阅读量:4046 次
发布时间:2019-05-24

本文共 3978 字,大约阅读时间需要 13 分钟。

在j2me平台上png图片格式几乎成为了标准,无数台手持设备上运行的j2me程序几乎都选用png来显示图像,包括大量的手机游戏以及手机应用,所以对png文件格式的了解,可以更有效的减少jar size,保护自有知识产权。

        cocomo曾经对png文件进行过一段时间的研究,包括图像压缩、解压以及加解密等,现将研究心得记录如下:

png文件格式:

        png文件格式分为png-24和png-8,其最大的区别是png-24是用24位来保存一个像素值,是真彩色,而png-8是用8位索引值来在调色盘中索引一个颜色,因为一个索引值的最大上限为2的8次方既128,故调色盘中颜色数最多为128种,所以该文件格式又被叫做png-8 128仿色。
       png-24因为其图片容量过大,而且在nokia和moto等某些机型上创建图片失败和显示不正确等异常时有发生,有时还会严重拖慢显示速度,故并不常用,cocomo认为这些异常和平台底层的图像解压不无关系。不过该格式最大的优点是可以保存alpha通道,同事也曾有过利用该图片格式实现alpha混合的先例,想来随着技术的发展,手机硬件平台的提升,alpha混合一定会被广泛的应用,到那时该格式的最大优势才会真正发挥。
       png-8文件是目前广泛应用的png图像格式,其主要有六大块组成:
1.文件头
2.ihdr块
3.plte块
4.trns块
5.idat块
6.文件尾
这六大块按顺序排列,也就是说idat块永远是在plte块之后,期间也会有许多其他的区块用来描述信息,例如图像的最后修改时间是多少,图像的创建者是谁等,不过这些区块的信息对我们来说都是可有可无的描述信息,故压缩时一般先向这些区块开刀。

 

数据块:

除了文件头,其中四大数据块和文件尾都是由统一的数据块文件结构描述的:
        chunk length: 4byte
        chunk type:   4byte
        chunk data:   chunk length的长度
        chunk crc:    4byte
例如ihdr块的数据长度为13,既
        chunk length = 13
        chunk type = "ihdr"

 

文件头:

用来标示png文件,为固定的64个字节:0x89504e47 0x0d0a1a0a

 

ihdr块:

用来描述图像的基本信息,其格式为:
       图像宽:    4byte
       图像高:    4byte
       图像色深: 4byte
       颜色类型: 1byte
       压缩方法: 1byte
       滤波方法: 1byte
       扫描方法: 1byte
曾经有人问过我,撒叫滤波方法和扫描方法,汗,说实话我也不知道,不过我们是在做手机游戏,不是在搞图形学不是嘛。

 

plte块:

这个就是传说中放置调色盘数据的地方啦,其格式为:
      循环
           red:    1byte
           green:1byte
           blue:  1byte
      end
循环长度嘛,不就是chunk length / 3的长度嘛,而且chunk length一定为3的倍数。

 

trns块:

这个块时有时无,主要是看你是否使用了透明色。该区块的格式为:
      循环
           if(对应调色盘颜色非透明)
               0xff:  1byte
           else
               0x00:  1byte
      end
循环长度为调色盘的颜色数,相当于调色盘颜色表的一个对应表,标识该颜色是否透明,0xff不透明,0x00透明。故如果用ultraedit查看png文件的二进制编码,如果看到一大片ff,一般就是trns区块啦,因为一个png文件一般只有一个透明色。

 

idat块:

这个就是存放图像数据的地方啦,这里要注意的是一个png文件可能有多个idat区块,而其他三大区块只可能有一个。
idat区块是经过压缩的,所以数据不可读,压缩算法一般为lz77滑动窗口算法,如果硬要看里面的数据的话,用zlib库也是可以的,cocomo当年就见过windows mobile上的帝国时代巨变态的用zlib库压缩和解压该区块来进一步减少png文件大小,真是寸k寸金啊。

 

iend块:

该区块虽然也按照数据块的结构,但chunk data是没有的,所以是固定的96个字节:0x00000000 0x49454e44 0xae426082

 

png图像压缩:

        了解了png的文件结构,压缩就有的放矢了。压缩有6个级别,可以根据需要选择。
level1:读取png文件,将除六大块之外的所有区块都过滤掉
level2:文件头是固定的0x89504e47 0x0d0a1a0a,文件尾是固定的0x00000000 0x49454e44 0xae426082,去掉!
level3:每个区块的chunk type我们是否需要呢?很明显,我们自己写的压缩格式自己应该清楚是按照什么样的顺序,去掉!
level4:每个区块的chunk length我们是否需要呢?
           ihdr块:定长13个字节,明显不需要,去掉。
           plte块:最多128个颜色,为撒要用4byte来记录区块长度而不是用1byte来记录颜色数呢?
           trns块:既然有颜色数,trns又是调色盘颜色表的对应表,既数量与颜色数相同,为撒还需要呢?
           idat块:我想这个是唯一需要4byte来记录长度的区块。
level5:每个区块的chunk crc是否需要呢?
           因为计算crc需要一些时间,但对于字节较少的区块一般可以忽略不计,所以对于这个问题还是由程序员自己决定吧。对于crc的计算可以参看cocomo的另一篇blog“png文件的crc码计算”
level6:每个区块我们是否要原封不动的保存期数据呢?
          ihdr块:除了宽、高、色深是需要的,后面那4byte的信息是固定的0x03000000
          plte块:为撒要用3byte来表示rgb而不是2byte的565格式?压缩方法可以参看cocomo的另一篇blog“关于png图像压缩的一点感悟”
          trns块:我想trns块是冗余最多的区块了吧,大段大段的0xff明显没有必要,一般的png文件只有一个透明色,为撒要用对应表的方法而不是一个索引来记录到底哪个是透明色呢?由于颜色数最多128,所以只需1byte就可以代替trns那么多0xff啦。
          idat块:么想法,如果你够变态,把zlib加进来吧!

 

png图像解压:

        创建了自定义的文件,j2me端读取后,就面临解压的问题了。我们可以利用此函数来创建image:
static image
createimage(byte[] imagedata, int imageoffset, int imagelength)
     前提是传入的imagedata与png未被压缩前的一致。因为png文件格式是固定的,所以读取自定义的压缩文件后,开始将那些默认的数据再添加进去,实现解压的目的。下面就开始解压之旅吧!
首先要创建一个bytearrayoutputstream out,
1.写入文件头:
out.writeint(0x89504e47);
out.writeint(0x0d0a1a0a);
2.写入ihdr块
out.writeint(13);
out.writeint(0x49484452);  //0x49484452为chunk type "ihdr"
out.writeint(width);
out.writeint(height);
out.writebyte(depth);
out.writeint(0x03000000);  //压缩时舍掉的4byte,默认0x03000000
out.writeint(crc);
其他区块方法一致,故略过。。。
3.写入文件尾
out.writeint(0x00000000);
out.writeint(0x49454e44);
out.writeint(0xae426082);
4.转换成数组,创建image
byte[] pngbuffer = out.tobytearray();
image image = image.createimage(pngbuffer, 0, pngbuffer.length);
哈哈,大功告成。这里注意如果中途数据写入有错误,经常会出现创建image失败的异常,而且非常不好调试,不过只要自定的压缩格式定下来后,对应的创建image的函数只要写一次,以后基本不会出问题哈。

 

png图像加解密:

        很多人都担心自己辛苦创作的漂亮的美术图片很easy就被别人拿到了,究其原因是由于png文件格式是固定的,稍微了解的人用ultraedit很容易就能找到ihdr,plte等标识了。cocomo就经常看gameloft的图像文件,哈哈。一般是2byte的length,然后紧接着图片数据,都放在一个文件里,直接拷贝2进制然后粘贴到一个新文件里就是一幅图。后来的加密技术会把png分块,例如前100个字节一块,紧接着1k一块,最后剩余字节一块,然后把块顺序打乱,用2byte来记录总长度,1byte记录顺序,但是这并没有从根本上消除ihdr,iend这些显眼的定位标识,好像在对破解者说:嘿,看,我就在这里!
       现在了解了之前的压缩和解压技术,这个问题也就迎刃而解了,因为chunk length,chunk type和chunk crc这些东西都消失了,甚至连数据块本身的数据都修改了,我可以按照imagewidth、imageheight、imagedepth的顺序写数据,也可以倒过来写。我想再牛的png分析器也是无能为力的吧,唯一可以定位的就只有idat区块了,不过就算得到该区块的数据,也应该是一张黑白图。
       不过在加解密的领域真是道高一尺,魔高一丈,cocomo很希望和各位共同探讨,共同提高!

转载地址:http://jbedi.baihongyu.com/

你可能感兴趣的文章
coursesa课程 Python 3 programming Functions can call other functions 函数调用另一个函数
查看>>
coursesa课程 Python 3 programming The while Statement
查看>>
course_2_assessment_6
查看>>
coursesa课程 Python 3 programming course_2_assessment_7 多参数函数练习题
查看>>
coursesa课程 Python 3 programming course_2_assessment_8 sorted练习题
查看>>
在unity中建立最小的shader(Minimal Shader)
查看>>
1.3 Debugging of Shaders (调试着色器)
查看>>
关于phpcms中模块_tag.class.php中的pc_tag()方法的含义
查看>>
vsftp 配置具有匿名登录也有系统用户登录,系统用户有管理权限,匿名只有下载权限。
查看>>
linux安装usb wifi接收器
查看>>
多线程使用随机函数需要注意的一点
查看>>
getpeername,getsockname
查看>>
让我做你的下一行Code
查看>>
浅析:setsockopt()改善程序的健壮性
查看>>
关于对象赋值及返回临时对象过程中的构造与析构
查看>>
VS 2005 CRT函数的安全性增强版本
查看>>
SQL 多表联合查询
查看>>
Visual Studio 2010:C++0x新特性
查看>>
drwtsn32.exe和adplus.vbs进行dump文件抓取
查看>>
cppcheck c++静态代码检查
查看>>