﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-唐吉诃德-文章分类-图片处理</title><link>http://www.cppblog.com/tdweng/category/16051.html</link><description /><language>zh-cn</language><lastBuildDate>Sun, 07 Apr 2013 00:51:28 GMT</lastBuildDate><pubDate>Sun, 07 Apr 2013 00:51:28 GMT</pubDate><ttl>60</ttl><item><title>BMP图片显示</title><link>http://www.cppblog.com/tdweng/articles/146009.html</link><dc:creator>心羽</dc:creator><author>心羽</author><pubDate>Mon, 09 May 2011 03:13:00 GMT</pubDate><guid>http://www.cppblog.com/tdweng/articles/146009.html</guid><wfw:comment>http://www.cppblog.com/tdweng/comments/146009.html</wfw:comment><comments>http://www.cppblog.com/tdweng/articles/146009.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tdweng/comments/commentRss/146009.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tdweng/services/trackbacks/146009.html</trackback:ping><description><![CDATA[<strong><span style="COLOR: red">1.</span></strong><a id=viewpost1_TitleUrl href="http://www.cppblog.com/zgysx/archive/2006/12/30/17029.html"><span style="COLOR: red"><strong>在Static控件中显示BMP</strong></span></a>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<p>首先，给Static控件添加一个Control变量（ID要改了以后才能添加变量，也就是说ID不能为IDC_STATIC），本例为m_staticTest。<br>然后，用ModifyStyle函数修改Static控件的Style，让它可以显示图片：</p>
<p>m_staticTest.ModifyStyle(0, SS_BITMAP | SS_CENTERIMAGE);</p>
<p>最后，就是Load文件显示出来：</p>
<p>CRect rect;<br>m_staticTest.GetWindowRect(&amp;rect);</p>
<p><font color=#339966>//&nbsp; 下面的方法是按照Static控件的大小显示bmp，如果要安装图片实际大小显示，用这个方法Load图片：<br>//&nbsp; HBITMAP hBmp = (HBITMAP)::LoadImage(0, _T("D:\\test.bmp"), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);<br></font>HBITMAP hBmp = (HBITMAP)::LoadImage(0, _T("D:\\test.bmp"), IMAGE_BITMAP, rect.Width(), rect.Height(), LR_LOADFROMFILE);</p>
<p>m_staticTest.SetBitmap(hBmp);<br>DeleteObject(hBmp);</p>
<img src ="http://www.cppblog.com/tdweng/aggbug/146009.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tdweng/" target="_blank">心羽</a> 2011-05-09 11:13 <a href="http://www.cppblog.com/tdweng/articles/146009.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>BMP文件结构</title><link>http://www.cppblog.com/tdweng/articles/140512.html</link><dc:creator>心羽</dc:creator><author>心羽</author><pubDate>Wed, 23 Feb 2011 06:12:00 GMT</pubDate><guid>http://www.cppblog.com/tdweng/articles/140512.html</guid><wfw:comment>http://www.cppblog.com/tdweng/comments/140512.html</wfw:comment><comments>http://www.cppblog.com/tdweng/articles/140512.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tdweng/comments/commentRss/140512.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tdweng/services/trackbacks/140512.html</trackback:ping><description><![CDATA[<div class=articleContent id=articleBody style="BACKGROUND-COLOR: #ffffff">1：<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">BMP</strong>文件组成<br><strong style="COLOR: red; BACKGROUND-COLOR: #ffffff">BMP</strong>文件由文件头、位图信息头、颜色信息和图形数据四部分组成。<br>2：<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">BMP</strong>文件头(14字节)<br><strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">BMP</strong>文件头数据<strong style="COLOR: black; BACKGROUND-COLOR: #99ff99">结构</strong>含有<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">BMP</strong>文件的类型、文件大小和位图起始位置等信息。<br>其<strong style="COLOR: black; BACKGROUND-COLOR: #99ff99">结构</strong>定义如下:<br>typedef struct tagBITMAPFILEHEADER<br>{<br>WORDbf Type; // 位图文件的类型，必须为<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">BMP</strong>(0-1字节)<br>DWORD bfSize; // 位图文件的大小，以字节为单位(2-5字节)<br>WORD bfReserved1; // 位图文件保留字，必须为0(6-7字节)<br>WORD bfReserved2; // 位图文件保留字，必须为0(8-9字节)<br>DWORD bfOffBits; // 位图数据的起始位置，以相对于位图(10-13字节)<br>// 文件头的偏移量表示，以字节为单位<br>} BITMAPFILEHEADER;<br>3：位图信息头(40字节)<br><strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">BMP</strong>位图信息头数据用于说明位图的尺寸等信息。<br>typedef struct tagBITMAPINFOHEADER{<br>DWORD biSize; // 本<strong style="COLOR: black; BACKGROUND-COLOR: #99ff99">结构</strong>所占用字节数(14-17字节)<br>LONG biWidth; // 位图的宽度，以像素为单位(18-21字节)<br>LONG biHeight; // 位图的高度，以像素为单位(22-25字节)<br>WORD biPlanes; // 目标设备的级别，必须为1(26-27字节)<br>WORD biBitCount;// 每个像素所需的位数，必须是1(双色),(28-29字节)<br>// 4(16色)，8(256色)或24(真彩色)之一<br>DWORD biCompression; // 位图压缩类型，必须是 0(不压缩),(30-33字节)<br>// 1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)之一<br>DWORD biSizeImage; // 位图的大小，以字节为单位(34-37字节)<br>LONG biXPelsPerMeter; // 位图水平分辨率，每米像素数(38-41字节)<br>LONG biYPelsPerMeter; // 位图垂直分辨率，每米像素数(42-45字节)<br>DWORD biClrUsed;// 位图实际使用的颜色表中的颜色数(46-49字节)<br>DWORD biClrImportant;// 位图显示过程中重要的颜色数(50-53字节)<br>} BITMAPINFOHEADER;<br>4：颜色表<br>颜色表用于说明位图中的颜色，它有若干个表项，每一个表项是一个RGBQUAD类型的<strong style="COLOR: black; BACKGROUND-COLOR: #99ff99">结构</strong>，定义一种颜色。RGBQUAD<strong style="COLOR: black; BACKGROUND-COLOR: #99ff99">结构</strong>的定义如下:<br>typedef struct tagRGBQUAD {<br>BYTE rgbBlue;// 蓝色的亮度(值范围为0-255)<br>BYTE rgbGreen; // 绿色的亮度(值范围为0-255)<br>BYTE rgbRed; // 红色的亮度(值范围为0-255)<br>BYTE rgbReserved;// 保留，必须为0<br>} RGBQUAD;<br>颜色表中RGBQUAD<strong style="COLOR: black; BACKGROUND-COLOR: #99ff99">结构</strong>数据的个数有biBitCount来确定:<br>当biBitCount=1,4,8时，分别有2,16,256个表项;<br>当biBitCount=24时，没有颜色表项。<br>位图信息头和颜色表组成位图信息，BITMAPINFO<strong style="COLOR: black; BACKGROUND-COLOR: #99ff99">结构</strong>定义如下:<br>typedef struct tagBITMAPINFO {<br>BITMAPINFOHEADER bmiHeader; // 位图信息头<br>RGBQUAD bmiColors[1]; // 颜色表<br>} BITMAPINFO;<br>5：位图数据<br>位图数据记录了位图的每一个像素值，记录顺序是在扫描行内是从左到右,扫描行之间是从下到上。位图的一个像素值所占的字节数:<br>当biBitCount=1时，8个像素占1个字节;<br>当biBitCount=4时，2个像素占1个字节;<br>当biBitCount=8时，1个像素占1个字节;<br>当biBitCount=24时,1个像素占3个字节;<br>Windows规定一个扫描行所占的字节数必须是<br>4的倍数(即以long为单位),不足的以0填充，<br>biSizeImage = ((((bi.biWidth * bi.biBitCount) + 31) &amp; ~31) / 8) * bi.biHeight;<br>具体数据举例：<br>如某<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">BMP</strong>文件开头：<br>4D42 4690 0000 0000 0000 4600 0000 2800 0000 8000 0000 9000 0000 0100*1000 0300 0000 0090 0000 A00F 0000 A00F 0000 0000 0000 0000 0000*00F8 0000 E007 0000 1F00 0000 0000 0000*02F1 84F1 04F1 84F1 84F1 06F2 84F1 06F2 04F2 86F2 06F2 86F2 86F2 .... ....<br><strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">BMP</strong>文件可分为四个部分：位图文件头、位图信息头、彩色板、图像数据阵列，在上图中已用*分隔。<br>一、图像文件头<br>1）1：(这里的数字代表的是"字",即两个字节,下同)图像文件头。0x4D42=&#8217;BM&#8217;，表示是Windows支持的<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">BMP</strong>格式。<br>2）2-3：整个文件大小。4690 0000，为00009046h=36934。<br>3）4-5：保留，必须设置为0。<br>4）6-7：从文件开始到位图数据之间的偏移量。4600 0000，为00000046h=70，上面的文件头就是35字=70字节。<br>二、位图信息头<br>5）8-9：位图图信息头长度。<br>6）10-11：位图宽度，以像素为单位。8000 0000，为00000080h=128。<br>7）12-13：位图高度，以像素为单位。9000 0000，为00000090h=144。<br>8）14：位图的位面数，该值总是1。0100，为0001h=1。<br>9）15：每个像素的位数。有1（单色），4（16色），8（256色），16（64K色，高彩色），24（16M色，真彩色），32（4096M色，增强型真彩色）。1000为0010h=16。<br>10）16-17：压缩说明：有0（不压缩），1（RLE 8，8位RLE压缩），2（RLE 4，4位RLE压缩，3（Bitfields，位域存放）。RLE简单地说是采用像素数+像素值的方式进行压缩。T408采用的是位域存放方式，用两个字节表示一个像素，位域分配为r5b6g5。图中0300 0000为00000003h=3。<br>11）18-19：用字节数表示的位图数据的大小，该数必须是4的倍数，数值上等于（&#8805;位图宽度的最小的4的倍数）&#215;位图高度&#215;每个像素位数。0090 0000为00009000h=80&#215;90&#215;2h=36864。<br>12）20-21：用象素/米表示的水平分辨率。A00F 0000为0000 0FA0h=4000。<br>13）22-23：用象素/米表示的垂直分辨率。A00F 0000为0000 0FA0h=4000。<br>14）24-25：位图使用的颜色索引数。设为0的话，则说明使用所有调色板项。<br>15）26-27：对图象显示有重要影响的颜色索引的数目。如果是0，表示都重要。<br>三、彩色板<br>16）28-....(不确定)：彩色板规范。对于调色板中的每个表项，用下述方法来描述RGB的值：<br>1字节用于蓝色分量<br>1字节用于绿色分量<br>1字节用于红色分量<br>1字节用于填充符(设置为0)<br>对于24-位真彩色图像就不使用彩色板，因为位图中的RGB值就代表了每个象素的颜色。<br>如，彩色板为00F8 0000 E007 0000 1F00 0000 0000 0000，其中：<br>00FB 0000为FB00h=1111100000000000（二进制），是蓝色分量的掩码。<br>E007 0000为 07E0h=0000011111100000（二进制），是绿色分量的掩码。<br>1F00 0000为001Fh=0000000000011111（二进制），是红色分量的掩码。<br>0000 0000总设置为0。<br>将掩码跟像素值进行&#8220;与&#8221;运算再进行移位操作就可以得到各色分量值。看看掩码，就可以明白事实上在每个像素值的两个字节16位中，按从高到低取5、6、5位分别就是r、g、b分量值。取出分量值后把r、g、b值分别乘以8、4、8就可以补齐第个分量为一个字节，再把这三个字节按rgb组合，放入存储器（同样要反序），就可以转换为24位标准<strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">BMP</strong>格式了。<br>四、图像数据阵列<br>17)27(无调色板)-．．．：每两个字节表示一个像素。阵列中的第一个字节表示位图左下角的象素，而最后一个字节表示位图右上角的象素。<br>五、存储算法<br><strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">BMP</strong>文件通常是不压缩的，所以它们通常比同一幅图像的压缩图像文件格式要大很多。例如，一个800&#215;600的24位几乎占据1.4MB空间。因此它们通常不适合在因特网或者其它低速或者有容量限制的媒介上进行传输。根据颜色深度的不同，图像上的一个像素可以用一个或者多个字节表示，它由n/8所确定（n是位深度，1字节包含8个数据位）。图片浏览器等基于字节的ASCII值计算像素的颜色，然后从调色板中读出相应的值。更为详细的信息请参阅下面关于位图文件的部分。 n位2n种颜色的位图近似字节数可以用下面的公式计算： <strong style="COLOR: black; BACKGROUND-COLOR: #a0ffff">BMP</strong>文件大小约等于 54+4*2的n次方+（w*h*n)/8<br>，其中高度和宽度都是像素数。需要注意的是上面公式中的54是位图文件的文件头，是彩色调色板的大小。另外需要注意的是这是一个近似值，对于n位的位图图像来说，尽管可能有最多2n中颜色，一个特定的图像可能并不会使用这些所有的颜色。由于彩色调色板仅仅定义了图像所用的颜色，所以实际的彩色调色板将小于。如果想知道这些值是如何得到的，请参考下面文件格式的部分。由于存储算法本身决定的因素，根据几个图像参数的不同计算出的大小与实际的文件大小将会有一些细小的差别。 </div>
<script type=text/javascript><!--
google_ad_client = "pub-1076724771190722";
/* JE个人博客468x60 */
google_ad_slot = "5506163105";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script><script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type=text/javascript>
</script><script src="http://pagead2.googlesyndication.com/pagead/js/r20101117/r20110208/show_ads_impl.js"></script><script src="http://pagead2.googlesyndication.com/pagead/expansion_embed.js"></script><script src="http://googleads.g.doubleclick.net/pagead/test_domain.js"></script><script src="http://pagead2.googlesyndication.com/pagead/render_ads.js"></script><script>google_protectAndRun("render_ads.js::google_render_ad", google_handleError, google_render_ad);</script>
<img src ="http://www.cppblog.com/tdweng/aggbug/140512.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tdweng/" target="_blank">心羽</a> 2011-02-23 14:12 <a href="http://www.cppblog.com/tdweng/articles/140512.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>（转帖）jpeglib使用指南 </title><link>http://www.cppblog.com/tdweng/articles/140452.html</link><dc:creator>心羽</dc:creator><author>心羽</author><pubDate>Tue, 22 Feb 2011 08:32:00 GMT</pubDate><guid>http://www.cppblog.com/tdweng/articles/140452.html</guid><wfw:comment>http://www.cppblog.com/tdweng/comments/140452.html</wfw:comment><comments>http://www.cppblog.com/tdweng/articles/140452.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/tdweng/comments/commentRss/140452.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/tdweng/services/trackbacks/140452.html</trackback:ping><description><![CDATA[<p>您可以到<a href="http://www.ijg.org/"><u><font color=#810081>www.ijg.org</font></u></a>网站下载libjpeg的源码， IJG JPEG Library就是jpeg压缩库，是以源码的形式提供给软件开发人员的，当然在软件包里也有编译好的库文件，我们这里就只用到其中的libjpeg.lib，jconfig.h，jmorecfg.h，jpeglib.h这几个文件，下面我就介绍一下怎样在自己的程序里嵌入图像压缩功能。</p>
<p>　　一、建立编译环境</p>
<p>　　所谓建立编译环境，其实非常简单，就是把上面提到的４个文件拷贝到你的项目文件夹下，把libjpeg.lib添加到你的项目中，然后在你完成压缩功能的那个文件里加入#include "jpeglib.h"，需要注意的是，libjpeg.lib是用c语言开发的，如果要用在你的C++程序里，需要用到extern "C"，如下：</p>
<p>// TestLibjpeg.cpp : Defines the entry point for the console application.<br>//</p>
<p>#include "stdafx.h"<br>#include "memory.h"<br>extern "C" {<br>&nbsp;#include "jpeglib.h"<br>}</p>
<p>　　二、压缩步骤</p>
<p>　　１、申请并初始化jpeg压缩对象，同时要指定错误处理器</p>
<p>&nbsp;struct jpeg_compress_struct jcs;</p>
<p>&nbsp;// 声明错误处理器，并赋值给jcs.err域<br>&nbsp; struct jpeg_error_mgr jem;<br>&nbsp; jcs.err = jpeg_std_error(&amp;jem);</p>
<p>&nbsp; jpeg_create_compress(&amp;jcs);</p>
<p>　　２、指定压缩后的图像所存放的目标文件，注意，目标文件应以二进制模式打开</p>
<p>&nbsp;f=fopen("03.jpg","wb");<br>&nbsp; if (f==NULL) <br>&nbsp; {<br>&nbsp;&nbsp;&nbsp; delete [] data;<br>&nbsp;&nbsp;&nbsp; delete [] pDataConv;<br>&nbsp;&nbsp;&nbsp; return 0;<br>&nbsp; }<br>&nbsp; jpeg_stdio_dest(&amp;jcs, f);</p>
<p>　　３、设置压缩参数，主要参数有图像宽、高、色彩通道数（１：索引图像，３：其他），色彩空间（JCS_GRAYSCALE表示灰度图，JCS_RGB表示彩色图像），压缩质量等，如下：</p>
<p>&nbsp; jcs.image_width = nWidth;&nbsp;&nbsp;&nbsp; // 为图的宽和高，单位为像素 <br>&nbsp; jcs.image_height = nHeight;<br>&nbsp; jcs.input_components = 1;&nbsp;&nbsp; // 在此为1,表示灰度图， 如果是彩色位图，则为3 <br>&nbsp; jcs.in_color_space = JCS_GRAYSCALE; //JCS_GRAYSCALE表示灰度图，JCS_RGB表示彩色图像 </p>
<p>&nbsp; jpeg_set_defaults(&amp;jcs); <br>&nbsp;jpeg_set_quality (&amp;jcs, 80, true);</p>
<p>需要注意的是，jpeg_set_defaults函数一定要等设置好图像宽、高、色彩通道数计色彩空间四个参数后才能调用，因为这个函数要用到这四个值，调用jpeg_set_defaults函数后，jpeglib库采用默认的设置对图像进行压缩，如果需要改变设置，如压缩质量，调用这个函数后，可以调用其它设置函数，如jpeg_set_quality函数。其实图像压缩时有好多参数可以设置，但大部分我们都用不着设置，只需调用jpeg_set_defaults函数值为默认值即可。</p>
<p>　　４、上面的工作准备完成后，就可以压缩了，压缩过程非常简单，首先调用jpeg_start_compress，然后可以对每一行进行压缩，也可以对若干行进行压缩，甚至可以对整个的图像进行一次压缩，压缩完成后，记得要调用jpeg_finish_compress函数，如下：</p>
<p>&nbsp; jpeg_start_compress(&amp;jcs, TRUE);</p>
<p>&nbsp; JSAMPROW row_pointer[1];&nbsp;&nbsp; // 一行位图<br>&nbsp; int row_stride;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 每一行的字节数 </p>
<p>&nbsp; row_stride = jcs.image_width;&nbsp; // 如果不是索引图,此处需要乘以3</p>
<p>&nbsp; // 对每一行进行压缩<br>&nbsp; while (jcs.next_scanline &lt; jcs.image_height) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; row_pointer[0] = &amp; pDataConv[jcs.next_scanline * row_stride];<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; jpeg_write_scanlines(&amp;jcs, row_pointer, 1);<br>&nbsp; }</p>
<p>&nbsp; jpeg_finish_compress(&amp;jcs);</p>
<p>　　５、最后就是释放压缩工作过程中所申请的资源了，主要就是jpeg压缩对象，由于在本例中我是直接用的局部变量，所以只需调用jpeg_destroy_compress这个函数即可，如下：</p>
<p>&nbsp;jpeg_destroy_compress(&amp;jcs);</p>
<p>　　三、解压缩步骤<br>　　解压缩步骤与压缩步骤非常相似，只是解压缩对象为jpeg_decompress_struct类型，步骤如下：<br>　　1、声明并初始化解压缩对象，同时制定错误信息管理器<br>&nbsp;struct jpeg_decompress_struct cinfo;<br>&nbsp;struct jpeg_error_mgr jerr;</p>
<p>&nbsp;cinfo.err = jpeg_std_error(&amp;jerr);<br>&nbsp;jpeg_create_decompress(&amp;cinfo);<br>　　2、打开jpg图像文件，并指定为解压缩对象的源文件<br>&nbsp;FILE *f = fopen(strSourceFileName,"rb");<br>&nbsp;if (f==NULL)<br>&nbsp;{<br>&nbsp; printf("Open file error!\n");<br>&nbsp; return;<br>&nbsp;}<br>&nbsp;// <br>&nbsp;jpeg_stdio_src(&amp;cinfo, f);<br>　　3、读取图像信息<br>&nbsp;jpeg_read_header(&amp;cinfo, TRUE);<br>　　4、根据图像信息申请一个图像缓冲区<br>&nbsp;data = new BYTE cinfo.image_width*cinfo.image_height*cinfo.num_components];<br>　　5、开始解压缩<br>&nbsp;jpeg_start_decompress(&amp;cinfo);</p>
<p>&nbsp;JSAMPROW row_pointer[1];<br>&nbsp;while (cinfo.output_scanline &lt; cinfo.output_height)<br>&nbsp;{<br>&nbsp; row_pointer[0] = &amp;data[(cinfo.output_height - cinfo.output_scanline-1)*cinfo.image_width*cinfo.num_components];<br>&nbsp; jpeg_read_scanlines(&amp;cinfo,row_pointer ,<br>&nbsp;&nbsp;&nbsp;&nbsp; 1);<br>&nbsp;}<br>&nbsp;jpeg_finish_decompress(&amp;cinfo);<br>　　6、释放资源<br>&nbsp;jpeg_destroy_decompress(&amp;cinfo);</p>
<p>&nbsp;fclose(f);</p>
<p>　　好了，利用IJG JPEG Library进行图像压缩就介绍到这里，希望对大家有所帮助，实例代码已经实现了图像的压缩和解压缩的全部功能</p>
<h3><span id=_ctl1__ctl0_ForumName>Embedded VC</span></h3>
<h3>Jpeg图像处理程序和代码(使用Indepedent JPEG Group的JpegLib)</h3>
<p>用Independent JPEG Group发行的JpegLib进行Jpeg图像的读取与保存。<br>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;这里只加了一个简单的处理示例——负片。其他的处理可以用与这个类似的方法，有了处理的算法对像素数据进行操作。或者加上鼠标事件的处理来完成绘画功能等等，这里主要是对JPEG文件进行操作的部分。<br>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;注意：程序中的CTScreenBuffer并未使用，原因是使用它加载后有段内存没有释放，加上BMP数据本来就比较好处理，所以自己写一段，将BMP数据加上头信息就可以CreateDIBSection了。<br>&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;保存的默认质量Q=85，大家在使用时可以按照要求改变。</p>
<h3>详细的使用方法以及JpegLib库</h3>
<hr>
<p><span class=inlineLink onclick="function onclick()&#13;&#10;{&#13;&#10;window.open('/ccs/user/Profile.aspx?UserID=2628')&#13;&#10;}">MacintoshM</span> 2006-05-14, 11:38 <br><span style="FONT-SIZE: 12px">详细的使用方法：<br><br>1.系统需求<br>&nbsp;&nbsp;Microsoft eMbedded Visual C++ 4.0 + Pocket PC 2003 SDK<br>&nbsp;&nbsp;Pocket PC的JpegLib库(在本帖的附件中)<br>2.背景<br>&nbsp;&nbsp;Jpeg库的由以下两个文件配置:jconfig.h和jmorecfg.h。一般使用时是不需要改变jmorecfg.h的，但这样可能在Pocket PC中运行时遇到问题，所以这里还是对jmorecfg.h进行了修改。下面将讨论这个修改，以使这个库在Pocket PC上正常使用。不过这里能够下载的附件已经做好了这个修改。<br><br>3.将JpegLib引入Pocket PC<br>&nbsp;&nbsp;jmorecfg.h文件含有与Embedded Visual Studio冲突的定义.需要做以下修改: <br><br>(1)代码: <br><br>#ifndef XMD_H&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br>typedef long INT32;<br>#endif<br><br><br>改为: <br><br>#if !defined(XMD_H) &amp;&amp; !defined(_BASETSD_H_)<br>typedef long INT32;<br>#endif<br><br><br>(2)代码: <br><br>#ifdef NEED_FAR_POINTERS<br>#define FAR&nbsp;&nbsp;far<br>#else<br>#define FAR<br>#endif<br><br><br>用下面的ifdef代替<br><br>#ifndef FAR<br>....<br>#endif<br><br>4.使用JpegLib加载Jpeg图片<br>&nbsp;&nbsp;在前面的附件的程序中，已经有这个程序的框架，这里不再赘述。只讲主要的部分。<br>&nbsp;&nbsp;(1)加载Jpeg图片的函数：<br>&nbsp;&nbsp;void CImageView::LoadImage(const CString &amp;strFileName)<br>{<br>&nbsp; &nbsp; &nbsp; &nbsp; FILE * pFile;<br>&nbsp; &nbsp; &nbsp; &nbsp; struct jpeg_error_mgr jerr;<br>&nbsp; &nbsp; &nbsp; &nbsp; struct jpeg_decompress_struct cinfo;<br>&nbsp; &nbsp; &nbsp; &nbsp; int i,start;<br>&nbsp; &nbsp; &nbsp; &nbsp; start=0;<br>&nbsp; &nbsp; &nbsp; &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; if ((pFile = _tfopen(strFileName, _T("rb"<img alt="" src="http://bbs.pdafans.com/images/smilies/wink.gif" align=absMiddle border=0>)) == NULL) {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; CString strError;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; strError.Format(_T("无法打开文件 '%s'"<img alt="" src="http://bbs.pdafans.com/images/smilies/wink.gif" align=absMiddle border=0>, strFileName);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; AfxMessageBox(strError);<br>&nbsp; &nbsp; &nbsp; &nbsp; }<br>&nbsp; &nbsp; &nbsp; &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; cinfo.err = jpeg_std_error(&amp;jerr);<br>&nbsp; &nbsp; &nbsp; &nbsp; jpeg_create_decompress(&amp;cinfo);<br>&nbsp; &nbsp; &nbsp; &nbsp; jpeg_stdio_src(&amp;cinfo, pFile);<br>&nbsp; &nbsp; &nbsp; &nbsp; jpeg_read_header(&amp;cinfo, TRUE);<br>&nbsp; &nbsp; &nbsp; &nbsp; jpeg_start_decompress(&amp;cinfo);<br>&nbsp; &nbsp; &nbsp; &nbsp; nRowSize = cinfo.output_width * cinfo.output_components;<br>&nbsp; &nbsp; &nbsp; &nbsp; Width=cinfo.output_width;<br>&nbsp; &nbsp; &nbsp; &nbsp; Height=cinfo.output_height;<br><br>&nbsp; &nbsp; &nbsp; &nbsp; if(bmpLoaded)<br>&nbsp; &nbsp; &nbsp; &nbsp; {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; delete bmpBuffer;<br>&nbsp; &nbsp; &nbsp; &nbsp; }<br>&nbsp; &nbsp; &nbsp; &nbsp; bmpBuffer=new BYTE[(Height+1)*Width*3]; //这里多申请一行，是因为在模拟器执行时，会出现无法加载的错误，但在机器上正常<br><br>&nbsp; &nbsp; &nbsp; &nbsp; bmpLoaded=TRUE;<br><br>&nbsp; &nbsp; &nbsp; &nbsp; pBuffer = (*cinfo.mem-&gt;alloc_sarray)<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ((j_common_ptr) &amp;cinfo, JPOOL_IMAGE, nRowSize, 1);<br>&nbsp; &nbsp; &nbsp; &nbsp; while(cinfo.output_scanline &lt; cinfo.output_height) <br>&nbsp; &nbsp; &nbsp; &nbsp; {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; jpeg_read_scanlines(&amp;cinfo, pBuffer, 1);<br><br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; start=nRowSize*cinfo.output_scanline;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for(i=0;i&lt;nRowSize;i++)<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; bmpBuffer[start+i]=pBuffer[0]<img alt="Idea [I]" src="http://writeblog.csdn.net/ccs/emoticons/emotion-55.gif">;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; }<br><br>&nbsp; &nbsp; &nbsp; &nbsp; CreateBitmap();<br>&nbsp; &nbsp; &nbsp; &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; jpeg_finish_decompress(&amp;cinfo);<br>&nbsp; &nbsp; &nbsp; &nbsp; jpeg_destroy_decompress(&amp;cinfo);<br>&nbsp; &nbsp; &nbsp; &nbsp; fclose(pFile);<br><br>}<br><br>&nbsp; &nbsp; (2)将加载后的像素数据建立一个HBITMAP对象的函数<br>&nbsp; &nbsp; 注意这里没有使用CSTScreenBuffer,因为在我实验时，用这个函数加载后，内存资源没有释放，这样每加载一幅图或做一次处理，就会多消耗几兆内存,Pocket PC内存很快就会被耗尽。所以这里将像素数据加上头信息就可以CreateDIBSection了。<br>&nbsp; &nbsp; void CImageView::CreateBitmap()<br>{<br>&nbsp; &nbsp; &nbsp; &nbsp; int m_nCorrectedWidth,m_nWidth,m_nHeight;<br><br>&nbsp; &nbsp; &nbsp; &nbsp; m_nCorrectedWidth = ( ( Width + 3 ) / 4 ) * 4;<br>&nbsp; &nbsp; &nbsp; &nbsp; m_nWidth = Width;<br>&nbsp; &nbsp; &nbsp; &nbsp; m_nHeight = Height;<br><br>&nbsp; &nbsp; &nbsp; &nbsp; DIBINFO&nbsp;&nbsp;dibInfo;<br>&nbsp; &nbsp; &nbsp; &nbsp; BGRColor *m_pBuffer;<br><br>&nbsp; &nbsp; &nbsp; &nbsp; dibInfo.bmiHeader.biBitCount = 24;<br>&nbsp; &nbsp; &nbsp; &nbsp; dibInfo.bmiHeader.biClrImportant = 0;<br>&nbsp; &nbsp; &nbsp; &nbsp; dibInfo.bmiHeader.biClrUsed = 0;<br>&nbsp; &nbsp; &nbsp; &nbsp; dibInfo.bmiHeader.biCompression = 0;<br>&nbsp; &nbsp; &nbsp; &nbsp; dibInfo.bmiHeader.biHeight = m_nHeight;<br>&nbsp; &nbsp; &nbsp; &nbsp; dibInfo.bmiHeader.biPlanes = 1;<br>&nbsp; &nbsp; &nbsp; &nbsp; dibInfo.bmiHeader.biSize = 40;<br>&nbsp; &nbsp; &nbsp; &nbsp; dibInfo.bmiHeader.biSizeImage = m_nCorrectedWidth*m_nHeight*3;<br>&nbsp; &nbsp; &nbsp; &nbsp; dibInfo.bmiHeader.biWidth = m_nCorrectedWidth;<br>&nbsp; &nbsp; &nbsp; &nbsp; dibInfo.bmiHeader.biXPelsPerMeter = 3780;<br>&nbsp; &nbsp; &nbsp; &nbsp; dibInfo.bmiHeader.biYPelsPerMeter = 3780;<br>&nbsp; &nbsp; &nbsp; &nbsp; dibInfo.bmiColors[0].rgbBlue = 0;<br>&nbsp; &nbsp; &nbsp; &nbsp; dibInfo.bmiColors[0].rgbGreen = 0;<br>&nbsp; &nbsp; &nbsp; &nbsp; dibInfo.bmiColors[0].rgbRed = 0;<br>&nbsp; &nbsp; &nbsp; &nbsp; dibInfo.bmiColors[0].rgbReserved = 0;<br><br>&nbsp; &nbsp; &nbsp; &nbsp; HDC hDC = ::GetDC(NULL);<br><br>&nbsp; &nbsp; &nbsp; &nbsp; if(m_hBitmap)<br>&nbsp; &nbsp; &nbsp; &nbsp; {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; :<img alt="" src="http://bbs.pdafans.com/images/smilies/biggrin.gif" align=absMiddle border=0>eleteObject(m_hBitmap);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; m_hBitmap=0;<br>&nbsp; &nbsp; &nbsp; &nbsp; }<br>&nbsp; &nbsp; &nbsp; &nbsp; m_hBitmap = CreateDIBSection(hDC, (const BITMAPINFO*)dibInfo, DIB_RGB_COLORS, (void**)&amp;m_pBuffer, NULL, 0);<br>&nbsp; &nbsp; &nbsp; &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; ::ReleaseDC(NULL,hDC);<br><br>&nbsp; &nbsp; &nbsp; &nbsp; int nPosition = 0;<br>&nbsp; &nbsp; &nbsp; &nbsp; int nDataPosition = 0;<br><br>&nbsp; &nbsp; &nbsp; &nbsp; for (int y=0; y&lt;Height; y++) {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; nPosition = m_nCorrectedWidth*(m_nHeight-y-1);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; nDataPosition = Width*3*y;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for (int x=0; x&lt;Width; x++) {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; m_pBuffer[nPosition].m_R = bmpBuffer[nDataPosition++];<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; m_pBuffer[nPosition].m_G = bmpBuffer[nDataPosition++];<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; m_pBuffer[nPosition].m_B = bmpBuffer[nDataPosition++];<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; nPosition++;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br>&nbsp; &nbsp; &nbsp; &nbsp; }<br><br>}<br>&nbsp; &nbsp; (3)在绘画函数中，这里是OnDraw()，加入如下代码：<br>&nbsp; &nbsp; if (m_hBitmap) <br>&nbsp; &nbsp; &nbsp; &nbsp; {<br>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;CDC memDc;<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; VERIFY(memDc.CreateCompatibleDC(&amp;dc));<br>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;HBITMAP hOldBitmap = (HBITMAP)::SelectObject(memDc.GetSafeHdc(), m_hBitmap);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; VERIFY(dc.BitBlt(-LeftTop.x, -LeftTop.y, Width, Height, &amp;memDc, 0, 0, SRCCOPY));<br>&nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;::SelectObject(memDc.GetSafeHdc(), hOldBitmap);<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; VERIFY( memDc.DeleteDC() );<br>&nbsp; &nbsp; &nbsp; &nbsp; }<br><br>5.使用JpegLib库保存Jpeg图片<br>&nbsp; &nbsp; 这里是一种实现方法：<br>&nbsp; &nbsp;void CImageView::SaveImage(const CString &amp;strFileName)<br>{&nbsp; &nbsp; &nbsp; &nbsp; <br>&nbsp; &nbsp; &nbsp; &nbsp; int nQuality=85; //保存质量Q值为85<br><br>&nbsp; &nbsp; &nbsp; &nbsp; if(!::WriteRGBBytesIntoJpegFile(strFileName,Width,Height,nQuality,bmpBuffer))<br>&nbsp; &nbsp; &nbsp; &nbsp; {<br>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ::AfxMessageBox(GetJpegWriterError());<br>&nbsp; &nbsp; &nbsp; &nbsp; }<br>}<br><br>其他的更详细内容的看例程中的其他消息处理函数就可以了。</span> </p>
<p>1.问题的由来<br>&nbsp;&nbsp;&nbsp; Jpeg图片在图像处理领域已经用的相当广泛了。但在编程领域，尤其是嵌入式编程领域使用的还不是很广。主要的原因是Jpeg的数据结构和算法远较bmp复杂，非图像算法的专业人士，通常是无法理解这些的。（我有个同事，他曾经花了半个月，研究过Jpeg的原理，还为此在team内部举办了一个讲座，讲了足足有一个小时，令众人对之仰慕万分，但他却说，仅得皮毛，未得要害。从此我对Jpeg的原理近而远之。）<br>&nbsp;&nbsp;&nbsp; 近来，因工作需要，要在wince平台下，为程序添加Jpeg支持。一般来说，此类问题最容易的解决方案是使用OS提供的相关库，毕竟现在不支持Jpeg的OS几乎没有。但在wince下这里出了个问题。目前绝大多数的wince设备是wince 4.X或5.X的，不过碰巧在图像处理这块，5.X和4.X的方法是不一样的。4.X提供的方法在IMGDECMP.DLL中，而5.X提供的方法在Imaging.DLL中，而且不止是链接库不同，库的接口也是完全两样的。因此，如果软件采用OS提供的相关库的话，在这里就要准备两套接口，非常的麻烦。况且，我们的软件不仅要在wince下部署，将来还打算推广到其他的平台，因此这种方案显然是不太好的。<br>&nbsp;&nbsp;&nbsp; 这时我想到了JpegLib。JpegLib是Independent JPEG Group——一个非Jpeg官方组织推出的Jpeg库。这是个开源免费的库，支持多种平台和编译器，你可以在<a href="http://www.ijg.org/" target=_blank><span style="COLOR: #96b0af"><u>www.ijg.org</u></span></a>中获得它的最新版本。在PC上它的效率比不了intel的Jpeg库，因为后者进行了汇编优化。但在wince上应该和系统库的效率相当。事实上如果查看系统的版权信息的话，Microsoft在wince中也使用了这个库。RISC的芯片也基本没有汇编优化的问题。<br>&nbsp;&nbsp;&nbsp; 网上的中文资料以以下两篇文章最为详尽。<br>&nbsp;&nbsp;&nbsp; <a href="http://mobile.winfans.net/ccs/forums/516/PrintPost.aspx" target=_blank><span style="COLOR: #96b0af"><u>http://mobile.winfans.net/ccs/forums/516/PrintPost.aspx</u></span></a> （文献A）<br>&nbsp;&nbsp;&nbsp; <a href="http://blog.csdn.net/zhao3728/archive/2007/08/22/1754877.aspx" target=_blank><span style="COLOR: #96b0af"><u>http://blog.csdn.net/zhao3728/archive/2007/08/22/1754877.aspx</u></span></a> （文献B）<br>&nbsp;&nbsp;&nbsp; 所以我的这篇文章主要作为补遗之用。<br><br>2.编译JpegLib库<br>&nbsp;&nbsp;&nbsp; 文献A和B都是使用现成的JpegLib库，这样的库只在特定的平台下才能用，完全体现不出JpegLib的优势。所以掌握编译JpegLib库的方法，是很有必要的。<br>&nbsp;&nbsp;&nbsp; JpegLib库源代码的组成<br>&nbsp;&nbsp;&nbsp; 1）makefile。JpegLib库中有很多文件名为makefile的文件。它的后缀名表示它所用于的平台或用途。随便打开一个，就可以看到JpegLib库源代码的组成。<br>&nbsp;&nbsp;&nbsp; 2）makefile中LIBSOURCES变量所代表的文件是JpegLib的核心算法部分。<br>&nbsp;&nbsp;&nbsp; 3）makefile中SYSDEPSOURCES变量所代表的文件是JpegLib中负责内存分配的部分。这部分是系统相关的，所以根据需要选用一个就行了。<br>&nbsp;&nbsp;&nbsp; 4）makefile中APPSOURCES变量所代表的文件是JpegLib中提供诸如命令行压缩Jpeg之类的功能的部分，实际上就是一些小工具。不过在编译JpegLib库时，不要将之添加到工程中。<br>&nbsp;&nbsp;&nbsp; 5）makefile中INCLUDES变量所代表的文件是源代码中用到的头文件。不是所有的头文件都被核心算法部分使用到，因此有些头文件在编译JpegLib库时，是不必要的，当然将之添加到工程中也不会出错。<br>&nbsp;&nbsp;&nbsp; 6）makefile中DOCS变量所代表的文件是一些文档、测试用例之类的东西。其中最有用的是example.c，文献A和B的示例最重要的部分，就来自这里。<br>&nbsp;&nbsp;&nbsp; 7）jconfig。JpegLib库中还有很多和makefile类似的jconfig，这是针对不同平台的类型声明。在使用时，应根据需要，将适当的jconfig文件的后缀名改为h。<br>&nbsp;&nbsp;&nbsp; 以上这些内容更详细的说明见JpegLib库的文档，以及<br>&nbsp;&nbsp;&nbsp; <a href="http://blog.csdn.net/axlrosek/archive/2007/03/29/1545496.aspx" target=_blank><span style="COLOR: #96b0af"><u>http://blog.csdn.net/axlrosek/archive/2007/03/29/1545496.aspx</u></span></a><br>&nbsp;&nbsp;&nbsp; VC:不同版本的VC、EVC都差不多，参照文献A的步骤修改相关文件，然后新建一个空工程，然后打开JpegLib中的makefile.vc文件,将2）和3）、5）、7）中的文件添加到工程中。将生成文件的类型定为lib就行了。此外，还需要针对调用的情况选择适当的运行时库，否则可能会出LNK2005错误。<br><br>3.使用JpegLib库<br>&nbsp;&nbsp;&nbsp; JpegLib库的使用参照文献A和B，以及example.c就可以了。但文献A的示例是有问题的。<br>&nbsp;&nbsp;&nbsp; bmpBuffer[start+i]=pBuffer[0];<br>应改为<br>&nbsp;&nbsp;&nbsp; bmpBuffer[start+i]=pBuffer[0][i];<br>&nbsp;&nbsp;&nbsp; jpeg_read_scanlines(&amp;cinfo, pBuffer, 1)执行之后，<span style="FONT-WEIGHT: bold">扫描线的内容被放到pBuffer[0]，而不是pBuffer中</span>，用memcpy将扫描线的内容转移到其他的缓冲区就行了，无需用循环语句。<br><br>4.流输入的Jpeg的处理<br>&nbsp;&nbsp;&nbsp; 上面的示例处理的都是从文件读入的Jpeg，在现实中，还存在流输入的Jpeg。在很多PC游戏中，程序的数据都被集中起来放入一个大文件之中，最典型的当属暴雪的mpq文件。当这些文件被读入内存时，就形成了字节流形式的文件。将之存为临时文件，然后再用之前的方法，显然是笨方法。这时可以采用jpeg_arr_src函数来替换jpeg_stdio_src函数。<br>&nbsp;&nbsp;&nbsp; 这一点还可以参考以下文档，不过该文针对的好像是旧版本，使用时要注意。<br>&nbsp;&nbsp;&nbsp; <a href="http://blog.china.com/u/060803/5544/200608/15355.html" target=_blank><span style="COLOR: #96b0af"><u>http://blog.china.com/u/060803/5544/200608/15355.html</u></span></a></p>
<img src ="http://www.cppblog.com/tdweng/aggbug/140452.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/tdweng/" target="_blank">心羽</a> 2011-02-22 16:32 <a href="http://www.cppblog.com/tdweng/articles/140452.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>