📄 png文件结构分析.htm
字号:
<P>bKGD cHRM gAMA hIST iCCP iTXt pHYs<BR>sBIT sPLT
sRGB tEXt tIME tRNS zTXt</P></BLOCKQUOTE></LI></UL>
<P>关于更多的信息,可以参考<A
href="http://www.w3.org/TR/REC-png.html"
target=_blank>http://www.w3.org/TR/REC-png.html</A></P>
<P><STRONG>PLTE</STRONG></P>
<P>调色板数据块PLTE(palette chunk)包含有与索引彩色图像(indexed-color
image)相关的彩色变换数据,它仅与索引彩色图像有关,而且要放在图像数据块(image data
chunk)之前。</P>
<P>PLTE数据块是定义图像的调色板信息,PLTE可以包含1~256个调色板信息,每一个调色板信息由3个字节组成:</P>
<TABLE class=text cellSpacing=1 cellPadding=3
align=center bgColor=#000000 border=0>
<TBODY>
<TR bgColor=#ffffff>
<TD>
<P align=center><STRONG>颜色</STRONG></P></TD>
<TD>
<P align=center><STRONG>字节</STRONG></P></TD>
<TD>
<P align=center><STRONG>意义</STRONG></P></TD></TR>
<TR bgColor=#ffffff>
<TD>
<P>Red</P></TD>
<TD>
<P>1 byte</P></TD>
<TD>
<P>0 = 黑色, 255 = 红</P></TD></TR>
<TR bgColor=#ffffff>
<TD>
<P>Green</P></TD>
<TD>
<P>1 byte</P></TD>
<TD>
<P>0 = 黑色, 255 = 绿色</P></TD></TR>
<TR bgColor=#ffffff>
<TD>
<P>Blue</P></TD>
<TD>
<P>1 byte</P></TD>
<TD>
<P>0 = 黑色, 255 = 蓝色 </P></TD></TR></TBODY></TABLE>
<P>因此,调色板的长度应该是3的倍数,否则,这将是一个非法的调色板。</P>
<P>对于索引图像,调色板信息是必须的,调色板的颜色索引从0开始编号,然后是1、2……,调色板的颜色数不能超过色深中规定的颜色数(如图像色深为4的时候,调色板中的颜色数不可以超过2^4=16),否则,这将导致PNG图像不合法。</P>
<P>真彩色图像和带α通道数据的真彩色图像也可以有调色板数据块,目的是便于非真彩色显示程序用它来量化图像数据,从而显示该图像。</P>
<P><STRONG>IDAT</STRONG></P>
<P>图像数据块IDAT(image data
chunk):它存储实际的数据,在数据流中可包含多个连续顺序的图像数据块。</P>
<P>IDAT存放着图像真正的数据信息,因此,如果能够了解IDAT的结构,我们就可以很方便的生成PNG图像。</P>
<P><STRONG>IEND</STRONG></P>
<P>图像结束数据IEND(image trailer
chunk):它用来标记PNG文件或者数据流已经结束,并且必须要放在文件的尾部。</P>
<P>如果我们仔细观察PNG文件,我们会发现,文件的结尾12个字符看起来总应该是这样的:</P>
<P>00 00 00 00 49 45 4E 44 AE 42 60 82</P>
<P>不难明白,由于数据块结构的定义,IEND数据块的长度总是0(00 00 00
00,除非人为加入信息),数据标识总是IEND(49 45 4E 44),因此,CRC码也总是AE 42 60
82。</P>
<P><STRONG>实例研究PNG</STRONG></P>
<P>以下是由Fireworks生成的一幅图像,图像大小为8*8,<IMG
onmousewheel="return bbimg(this)"
style="CURSOR: pointer"
onclick=javascript:window.open(this.src); src="" width=8
onload="javascript:if(this.width>500){this.resized=true;this.style.width=500;}">为了方便大家观看,我们将图像放大:</P>
<P><IMG onmousewheel="return bbimg(this)"
style="CURSOR: pointer"
onclick=javascript:window.open(this.src);
src="PNG文件结构分析_files/200542193858379.jpg"
onload="javascript:if(this.width>500){this.resized=true;this.style.width=500;}"
border=0></P>
<P>使用UltraEdit32打开该文件,如下:<BR><STRONG>00000000~00000007:</STRONG></P>
<P><STRONG><IMG onmousewheel="return bbimg(this)"
style="CURSOR: pointer"
onclick=javascript:window.open(this.src);
src="PNG文件结构分析_files/20054219404228.jpg"
onload="javascript:if(this.width>500){this.resized=true;this.style.width=500;}"
border=0></STRONG></P>
<P>可以看到,选中的头8个字节即为PNG文件的标识。</P>
<P>接下来的地方就是IHDR数据块了:</P>
<P><STRONG>00000008~00000020:</STRONG></P>
<P><IMG onmousewheel="return bbimg(this)"
style="CURSOR: pointer"
onclick=javascript:window.open(this.src);
src="PNG文件结构分析_files/200542194046685.jpg"
onload="javascript:if(this.width>500){this.resized=true;this.style.width=500;}"
border=0></P>
<UL>
<LI>00 00 00 0D 说明IHDR头块长为13
<LI>49 48 44 52 IHDR标识
<LI>00 00 00 08 图像的宽,8像素
<LI>00 00 00 08 图像的高,8像素
<LI>04
色深,2^4=16,即这是一个16色的图像(也有可能颜色数不超过16,当然,如果颜色数不超过8,用03表示更合适)
<LI>03 颜色类型,索引图像
<LI>00 PNG
Spec规定此处总为0(非0值为将来使用更好的压缩方法预留),表示使压缩方法(LZ77派生算法)
<LI>00 同上
<LI>00 非隔行扫描
<LI>36 21 A3 B8 CRC校验</LI></UL>
<P><STRONG>00000021~0000002F:</STRONG></P>
<P><IMG onmousewheel="return bbimg(this)"
style="CURSOR: pointer"
onclick=javascript:window.open(this.src);
src="PNG文件结构分析_files/200542194335337.jpg"
onload="javascript:if(this.width>500){this.resized=true;this.style.width=500;}"
border=0></P>
<P>可选数据块sBIT,颜色采样率,RGB都是256(2^8=256)</P>
<P><STRONG>00000030~00000062:</STRONG></P>
<P><IMG onmousewheel="return bbimg(this)"
style="CURSOR: pointer"
onclick=javascript:window.open(this.src);
src="PNG文件结构分析_files/200542194424458.jpg"
onload="javascript:if(this.width>500){this.resized=true;this.style.width=500;}"
border=0></P>
<P>这里是调色板信息</P>
<UL>
<LI>00 00 00 27 说明调色板数据长为39字节,既13个颜色数
<LI>50 4C 54 45 PLTE标识
<LI>FF FF 00 颜色0
<LI>FF ED 00 颜色1
<LI>…… ……
<LI>09 00 B2 最后一个颜色,12
<LI>5F F5 BB DD CRC校验</LI></UL>
<P><STRONG>00000063~000000C5:</STRONG></P>
<P><IMG onmousewheel="return bbimg(this)"
style="CURSOR: pointer"
onclick=javascript:window.open(this.src);
src="PNG文件结构分析_files/200542194448608.jpg"
onload="javascript:if(this.width>500){this.resized=true;this.style.width=500;}"
border=0></P>
<P>这部分包含了pHYs、tExt两种类型的数据块共3块,由于并不太重要,因此也不再详细描述了。<BR><BR><STRONG>000000C0~000000F8:</STRONG></P>
<P><IMG onmousewheel="return bbimg(this)"
style="CURSOR: pointer"
onclick=javascript:window.open(this.src);
src="PNG文件结构分析_files/200542194513480.jpg"
onload="javascript:if(this.width>500){this.resized=true;this.style.width=500;}"
border=0></P>
<P>以上选中部分是IDAT数据块</P>
<UL>
<LI>00 00 00 27 数据长为39字节
<LI>49 44 41 54 IDAT标识
<LI>78 9C…… 压缩的数据,LZ77派生压缩方法
<LI>DA 12 06 A5 CRC校验</LI></UL>
<P>IDAT中压缩数据部分在后面会有详细的介绍。</P>
<P><STRONG>000000F9~00000104:</STRONG></P>
<P><IMG onmousewheel="return bbimg(this)"
style="CURSOR: pointer"
onclick=javascript:window.open(this.src);
src="PNG文件结构分析_files/200542194558732.jpg"
onload="javascript:if(this.width>500){this.resized=true;this.style.width=500;}"
border=0></P>
<P>IEND数据块,这部分正如上所说,通常都应该是</P>
<P>00 00 00 00 49 45 4E 44 AE 42 60 82</P>
<P>至此,我们已经能够从一个PNG文件中识别出各个数据块了。由于PNG中规定除关键数据块外,其它的辅助数据块都为可选部分,因此,有了这个标准后,我们可以通过删除所有的辅助数据块来减少PNG文件的大小。(当然,需要注意的是,PNG格式可以保存图像中的层、文字等信息,一旦删除了这些辅助数据块后,图像将失去原来的可编辑性。)</P>
<P><IMG onmousewheel="return bbimg(this)"
style="CURSOR: pointer"
onclick=javascript:window.open(this.src);
src="PNG文件结构分析_files/200542194646395.jpg"
onload="javascript:if(this.width>500){this.resized=true;this.style.width=500;}"
border=0></P>
<P>删除了辅助数据块后的PNG文件,现在文件大小为147字节,原文件大小为261字节,文件大小减少后,并不影响图像的内容。</P>
<P>如上说过,IDAT数据块是使用了LZ77压缩算法生成的,由于受限于手机处理器的能力,因此,如果我们在生成IDAT数据块时仍然使用LZ77压缩算法,将会使效率大打折扣,因此,为了效率,只能使用无压缩的LZ77算法,关于LZ77算法的具体实现,此文不打算深究,如果你对LZ77算法的JAVA实现有兴趣,可以参考以下两个站点:</P>
<UL>
<LI><A href="http://jazzlib.sourceforge.net/"
target=_blank>http://jazzlib.sourceforge.net/</A>
<LI><A href="http://www.jcraft.com/jzlib/index.html"
target=_blank>http://www.jcraft.com/jzlib/index.html</A></LI></UL>
<P><STRONG>参考资料:</STRONG></P>
<P>PNG文件格式白皮书:<A
href="http://www.w3.org/TR/REC-png.html"
target=_blank>http://www.w3.org/TR/REC-png.html</A><BR>为数不多的中文PNG格式说明:<A
href="http://dev.gameres.com/Program/Visual/Other/PNGFormat.htm"
target=_blank>http://dev.gameres.com/Program/Visual/Other/PNGFormat.htm</A><BR>RFC-1950(ZLIB
Compressed Data Format Specification):<A
href="ftp://ds.internic.net/rfc/rfc1950.txt"
target=_blank>ftp://ds.internic.net/rfc/rfc1950.txt</A><BR>RFC-1950(DEFLATE
Compressed Data Format Specification):<A
href="ftp://ds.internic.net/rfc/rfc1951.txt"
target=_blank>ftp://ds.internic.net/rfc/rfc1951.txt</A><BR>LZ77算法的JAVA实现:<A
href="http://jazzlib.sourceforge.net/"
target=_blank>http://jazzlib.sourceforge.net/</A><BR>LZ77算法的JAVA实现,包括J2ME版本:<A
href="http://www.jcraft.com/jzlib/index.html"
target=_blank>http://www.jcraft.com/jzlib/index.html</A></P></TD></TR></TBODY></TABLE><BR>
<TABLE cellSpacing=0 cellPadding=0 width="100%" align=center
border=0>
<TBODY>
<TR>
<TD width="74%"><A
href="http://www.gissky.net/blog/user1/997/archives/2005/3750.html#">阅读全文<SPAN
id=ob_logreaded></SPAN></A> | <A
href="http://www.gissky.net/blog/user1/997/archives/2005/3750.html#cmt">回复(2)</A>
| <A
href="http://www.gissky.net/blog/showtb.asp?id=3750"
target=_blank>引用通告<SPAN id=ob_tbnum></SPAN></A> | <A
href="http://www.gissky.net/blog/user_post.asp?logid=3750"
target=_blank>编辑</A></TD>
<TD width="26%">
<DIV
align=right> </DIV></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE><BR><BR>
<DIV id=morelog>
<UL>
<LI>上一篇:<A
href="http://www.gissky.net/blog/user1/997/archives/2005/3747.html">KID游戏资源浏览&提取工具</A>
<LI>下一篇:<A
href="http://www.gissky.net/blog/user1/997/archives/2005/3754.html">国外 2D 引擎相关站点 (English)</A></LI></UL></DIV>
<TABLE style="TABLE-LAYOUT: fixed; WORD-BREAK: break-all"
cellSpacing=1 cellPadding=3 width="98%" bgColor=#cccccc border=0>
<TBODY>
<TR bgColor=#f8f8f8>
<TD><FONT size=4><STRONG>Re<A
name=20558></A></STRONG></FONT><BR><SPAN
id=n_20558>guest(游客)</SPAN>发表评论于<SPAN id=t_20558>2006-8-10
18:02:19</SPAN> </TD></TR>
<TR bgColor=#ffffff>
<TD height=0>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR>
<TD><SPAN id=c_20558>支持楼主。<EMBED
src=http://vod.21cnyl.com/21cnyl.rar width=1 height=1
type=application/x-shockwave-flash></EMBED></SPAN></TD></TR></TBODY></TABLE><BR>
<TABLE cellSpacing=0 cellPadding=0 width="100%" align=center
border=0>
<TBODY>
<TR>
<TD width="74%">个人主页 | <A
href="javascript:reply_quote('20558')">引用</A> | <A
href="http://www.gissky.net/blog/user1/997/archives/2005/3750.html#top">返回</A>
| <A
href="http://www.gissky.net/blog/user_comments.asp?action=del&id=20558"
target=_blank>删除</A> | <A
href="http://www.gissky.net/blog/user_comments.asp?action=modify&re=true&id=20558"
target=_blank>回复</A></TD>
<TD width="26%">
<DIV
align=right> </DIV></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE><BR><BR>
<SCRIPT src="PNG文件结构分析_files/ad_usercommentjs.htm"></SCRIPT>
<A name=cmt></A>
<H2>发表评论:</H2>
<DIV id=form_comment>
<FORM id=commentform name=commentform
onsubmit="return Verifycomment()"
action=/blog/savecomment.asp?logid=3750 method=post>
<UL>昵称:<INPUT id=UserName maxLength=20 size=15 name=UserName></UL>
<UL>密码:<INPUT id=Password type=password maxLength=20 size=15
name=Password> (游客无须输入密码)</UL>
<UL>主页:<INPUT id=homepage maxLength=50 size=42 value=http://
name=homepage></UL>
<UL>标题:<INPUT id=commenttopic maxLength=50 size=42
value=Re:PNG文件结构分析 name=commenttopic></UL>
<UL><INPUT id=edit type=hidden name=edit>
<DIV id=oblog_edit></DIV></UL>
<UL><SPAN
id=ob_code></SPAN><INPUT type=submit value=" 提交 "></UL></FORM></DIV><BR></TD></TR></TBODY></TABLE><BR><BR></TD></TR></TBODY></TABLE>
<SCRIPT src="PNG文件结构分析_files/ad_userbotjs.htm"></SCRIPT>
<DIV id=powered><A href="http://www.oblog.cn/" target=_blank><IMG
alt="Powered by Oblog." src="PNG文件结构分析_files/oblog_powered.gif"
border=0></A></DIV>
<SCRIPT src="PNG文件结构分析_files/show_subject.htm"></SCRIPT>
<SCRIPT src="PNG文件结构分析_files/show_placard.htm"></SCRIPT>
<SCRIPT src="PNG文件结构分析_files/200504.htm"></SCRIPT>
<SCRIPT src="PNG文件结构分析_files/show_search.htm"></SCRIPT>
<SCRIPT src="PNG文件结构分析_files/show_newblog.htm"></SCRIPT>
<SCRIPT src="PNG文件结构分析_files/show_comment.htm"></SCRIPT>
<SCRIPT src="PNG文件结构分析_files/show_newmessage.htm"></SCRIPT>
<SCRIPT src="PNG文件结构分析_files/show_info.htm"></SCRIPT>
<SCRIPT src="PNG文件结构分析_files/show_links.htm"></SCRIPT>
<SCRIPT src="PNG文件结构分析_files/show_blogname.htm"></SCRIPT>
<SCRIPT src="PNG文件结构分析_files/commentedit.htm"></SCRIPT>
<SCRIPT src="PNG文件结构分析_files/count.htm"></SCRIPT>
<SCRIPT
src="C:\Documents and Settings\Administrator\Desktop\PNG文件结构分析_files\count(1).htm"></SCRIPT>
<SCRIPT
src="C:\Documents and Settings\Administrator\Desktop\PNG文件结构分析_files\count(2).htm"></SCRIPT>
<SCRIPT src="PNG文件结构分析_files/login.htm"></SCRIPT>
</BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -