﻿<?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++博客-swo2006-文章分类-vc图形算法</title><link>http://www.cppblog.com/swo2006/category/3203.html</link><description /><language>zh-cn</language><lastBuildDate>Mon, 19 May 2008 18:41:46 GMT</lastBuildDate><pubDate>Mon, 19 May 2008 18:41:46 GMT</pubDate><ttl>60</ttl><item><title>C++图形领域新闻与资源</title><link>http://www.cppblog.com/swo2006/articles/15119.html</link><dc:creator>swo</dc:creator><author>swo</author><pubDate>Mon, 13 Nov 2006 01:23:00 GMT</pubDate><guid>http://www.cppblog.com/swo2006/articles/15119.html</guid><wfw:comment>http://www.cppblog.com/swo2006/comments/15119.html</wfw:comment><comments>http://www.cppblog.com/swo2006/articles/15119.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/swo2006/comments/commentRss/15119.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/swo2006/services/trackbacks/15119.html</trackback:ping><description><![CDATA[http://www.kaidianle.com/article/list22277.html<img src ="http://www.cppblog.com/swo2006/aggbug/15119.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/swo2006/" target="_blank">swo</a> 2006-11-13 09:23 <a href="http://www.cppblog.com/swo2006/articles/15119.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>BMP位图文件结构及平滑缩放</title><link>http://www.cppblog.com/swo2006/articles/14750.html</link><dc:creator>swo</dc:creator><author>swo</author><pubDate>Mon, 06 Nov 2006 14:25:00 GMT</pubDate><guid>http://www.cppblog.com/swo2006/articles/14750.html</guid><wfw:comment>http://www.cppblog.com/swo2006/comments/14750.html</wfw:comment><comments>http://www.cppblog.com/swo2006/articles/14750.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/swo2006/comments/commentRss/14750.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/swo2006/services/trackbacks/14750.html</trackback:ping><description><![CDATA[
		<span class="unnamed3">
				<p>
						<font face="宋体" size="2">用普通方法显示BMP位图，占内存大，速度慢，在图形缩小时，失真严重,在低颜色位数的设备上显示高颜色位数的图形图形时失真大。本文采用视频函数显示BMP位图，可以消除以上的缺点。</font>
				</p>
				<p>
						<font face="宋体" size="2">一、BMP文件结构</font>
				</p>
				<p>
						<font face="宋体" size="2">BMP文件组成<br />BMP文件由文件头、位图信息头、颜色信息和图形数据四部分组成。 <br />BMP文件头<br />BMP文件头数据结构含有BMP文件的类型、文件大小和位图起始位置等信息。 <br />其结构定义如下:<br />typedef struct tagBITMAPFILEHEADER<br />{<br />WORDbfType; // 位图文件的类型，必须为BM<br />DWORD bfSize; // 位图文件的大小，以字节为单位 <br />WORDbfReserved1; // 位图文件保留字，必须为0<br />WORDbfReserved2; // 位图文件保留字，必须为0<br />DWORD bfOffBits; // 位图数据的起始位置，以相对于位图<br />// 文件头的偏移量表示，以字节为单位<br />} BITMAPFILEHEADER;</font>
				</p>
				<p>
						<br />
						<font face="宋体" size="2">3. 位图信息头</font>
				</p>
				<p>
						<br />
						<font face="宋体" size="2">BMP位图信息头数据用于说明位图的尺寸等信息。<br />typedef struct tagBITMAPINFOHEADER{<br />DWORD biSize; // 本结构所占用字节数<br />LONGbiWidth; // 位图的宽度，以像素为单位<br />LONGbiHeight; // 位图的高度，以像素为单位<br />WORD biPlanes; // 目标设备的级别，必须为1<br />WORD biBitCount// 每个像素所需的位数，必须是1(双色),<br />// 4(16色)，8(256色)或24(真彩色)之一<br />DWORD biCompression; // 位图压缩类型，必须是 0(不压缩),<br />// 1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)之一<br />DWORD biSizeImage; // 位图的大小，以字节为单位<br />LONGbiXPelsPerMeter; // 位图水平分辨率，每米像素数<br />LONGbiYPelsPerMeter; // 位图垂直分辨率，每米像素数<br />DWORD biClrUsed;// 位图实际使用的颜色表中的颜色数<br />DWORD biClrImportant;// 位图显示过程中重要的颜色数<br />} BITMAPINFOHEADER;</font>
				</p>
				<p>
						<br />
						<font face="宋体" size="2">4. 颜色表</font>
				</p>
				<p>
						<font face="宋体" size="2">　　颜色表用于说明位图中的颜色，它有若干个表项，每一个表项是一个RGBQUAD类型的结构，定义一种颜色。RGBQUAD结构的定义如下:<br />typedef struct tagRGBQUAD {<br />BYTErgbBlue;// 蓝色的亮度(值范围为0-255)<br />BYTErgbGreen; // 绿色的亮度(值范围为0-255)<br />BYTErgbRed; // 红色的亮度(值范围为0-255)<br />BYTErgbReserved;// 保留，必须为0<br />} RGBQUAD;<br />颜色表中RGBQUAD结构数据的个数有biBitCount来确定:<br />当biBitCount=1,4,8时，分别有2,16,256个表项;<br />当biBitCount=24时，没有颜色表项。<br />位图信息头和颜色表组成位图信息，BITMAPINFO结构定义如下:<br />typedef struct tagBITMAPINFO {<br />BITMAPINFOHEADER bmiHeader; // 位图信息头<br />RGBQUAD bmiColors[1]; // 颜色表<br />} BITMAPINFO;</font>
				</p>
				<p>
						<br />
						<font face="宋体" size="2">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 />一个扫描行所占的字节数计算方法:<br />DataSizePerLine= (biWidth* biBitCount+31)/8; <br />// 一个扫描行所占的字节数<br />DataSizePerLine= DataSizePerLine/4*4; // 字节数必须是4的倍数<br />位图数据的大小(不压缩情况下):<br />DataSize= DataSizePerLine* biHeight;</font>
				</p>
				<p>
						<br />
						<font face="宋体" size="2">二、BMP位图一般显示方法</font>
				</p>
				<p>
						<font face="宋体" size="2">1. 申请内存空间用于存放位图文件<br />　　GlobalAlloc(GHND，FileLength);</font>
				</p>
				<p>
						<font face="宋体" size="2">2. 位图文件读入所申请内存空间中<br />　　 LoadFileToMemory( mpBitsSrc，mFileName);</font>
				</p>
				<p>
						<font face="宋体" size="2">3. 在OnPaint等函数中用创建显示用位图<br />　　用CreateDIBitmap()创建显示用位图，用CreateCompatibleDC()创建兼容DC,<br />　　用SelectBitmap()选择显示位图。</font>
				</p>
				<p>
						<font face="宋体" size="2">4. 用BitBlt或StretchBlt等函数显示位图</font>
				</p>
				<p>
						<font face="宋体" size="2">5. 用DeleteObject()删除所创建的位图</font>
				</p>
				<p>
						<font face="宋体" size="2">　　以上方法的缺点是: 1)显示速度慢; 2) 内存占用大; 3) 位图在缩小显示时图形失真大,(可通过安装字体平滑软件来解决); 4) 在低颜色位数的设备上(如256显示模式)显示高颜色位数的图形(如真彩色)图形失真严重。</font>
				</p>
				<p>
						<font face="宋体" size="2">三、BMP位图缩放显示<br />　　 用DrawDib视频函数来显示位图，内存占用少，速度快，而且还可以对图形进行淡化(Dithering)处理。淡化处理是一种图形算法，可以用来在一个支持比图像所用颜色要少的设备上显示彩色图像。BMP位图显示方法如下:</font>
				</p>
				<p>
						<font face="宋体" size="2">1. 打开视频函数DrawDibOpen()，一般放在在构造函数中</font>
				</p>
				<p>
						<font face="宋体" size="2">2. 申请内存空间用于存放位图文件<br />　　GlobalAlloc(GHND，FileLength);</font>
				</p>
				<p>
						<font face="宋体" size="2">3. 位图文件读入所申请内存空间中---- <br />　　LoadFileToMemory( mpBitsSrc，mFileName);</font>
				</p>
				<p>
						<font face="宋体" size="2">4. 在OnPaint等函数中用DrawDibRealize()，DrawDibDraw()显示位图</font>
				</p>
				<p>
						<font face="宋体" size="2">5. 关闭视频函数DrawDibClose(),一般放在在析构函数中</font>
				</p>
				<p>
						<font face="宋体" size="2">　　以上方法的优点是: 1)显示速度快; 2) 内存占用少; 3) 缩放显示时图形失真小,4) 在低颜色位数的设备上显示高颜色位数的图形图形时失真小; 5) 通过直接处理位图数据，可以制作简单动画。</font>
				</p>
				<p>
						<font face="宋体" size="2">四、CViewBimap类编程要点</font>
				</p>
				<p>
						<font face="宋体" size="2">1. 在CViewBimap类中添加视频函数等成员</font>
				</p>
				<p>
						<font face="宋体" size="2">HDRAWDIB m_hDrawDib; // 视频函数<br />HANDLEmhBitsSrc; // 位图文件句柄(内存)<br />LPSTR mpBitsSrc; // 位图文件地址(内存)<br />BITMAPINFOHEADER *mpBitmapInfo; // 位图信息头</font>
				</p>
				<p>
						<font face="宋体" size="2">2. 在CViewBimap类构造函数中添加打开视频函数<br />　　m_hDrawDib= DrawDibOpen();</font>
				</p>
				<p>
						<font face="宋体" size="2">3. 在CViewBimap类析构函数中添加关闭视频函数</font>
				</p>
				<p>
						<font face="宋体" size="2">if( m_hDrawDib != NULL)<br />{<br />DrawDibClose( m_hDrawDib);<br />m_hDrawDib = NULL;<br />}</font>
				</p>
				<p>
						<font face="宋体" size="2">4. 在CViewBimap类图形显示函数OnPaint中添加GraphicDraw()<br />voidCViewBitmap::OnPaint()<br />{<br />CPaintDC dc(this); // device context for painting<br />GraphicDraw( );<br />}</font>
				</p>
				<p>
						<font face="宋体" size="2">voidCViewBitmap::GraphicDraw( void )<br />{<br />CClientDC dc(this); // device context for painting<br />BITMAPFILEHEADER *pBitmapFileHeader;<br />ULONG bfoffBits= 0;<br />CPoint Wid;</font>
				</p>
				<p>
						<font face="宋体" size="2">// 图形文件名有效 (=0 BMP)<br />if( mBitmapFileType &lt; ID_BITMAP_BMP ) return;</font>
				</p>
				<p>
						<font face="宋体" size="2">// 图形文件名有效 (=0 BMP)<br />// 准备显示真彩位图<br />pBitmapFileHeader= (BITMAPFILEHEADER *) mpBitsSrc;<br />bfoffBits= pBitmapFileHeader-&gt;bfOffBits;</font>
				</p>
				<p>
						<font face="宋体" size="2">// 使用普通函数显示位图</font>
				</p>
				<p>
						<font face="宋体" size="2">if( m_hDrawDib == NULL || mDispMethod == 0)<br />{<br />HBITMAP hBitmap=::CreateDIBitmap(dc.m_hDC,<br />mpBitmapInfo, CBM_INIT, mpBitsSrc+bfoffBits,<br />(LPBITMAPINFO) mpBitmapInfo,DIB_RGB_COLORS); <br />// 建立位图<br />HDC hMemDC=::CreateCompatibleDC(dc.m_hDC);// 建立内存<br />HBITMAP hBitmapOld= SelectBitmap(hMemDC, hBitmap); // 选择对象<br />// 成员CRect mDispR用于指示图形显示区域的大小.<br />// 成员CPoint mPos用于指示图形显示起始位置坐标.<br />if( mPos.x &gt; (mpBitmapInfo- &gt;biWidth - mDispR.Width() ))<br />mPos.x= mpBitmapInfo-&gt;biWidth - mDispR.Width() ;<br />if( mPos.y &gt; (mpBitmapInfo- &gt;biHeight- mDispR.Height()))<br />mPos.y= mpBitmapInfo- &gt;biHeight- mDispR.Height();<br />if( mPos.x &lt; 0 ) mPos.x= 0;<br />if( mPos.y &lt; 0 ) mPos.y= 0;</font>
				</p>
				<p>
						<font face="宋体" size="2">if( mFullViewTog == 0)<br />{<br />// 显示真彩位图<br />::BitBlt(dc.m_hDC,0,0, mDispR.Width(), mDispR.Height(),<br />hMemDC,mPos.x,mPos.y, SRCCOPY);<br />} else {<br />::StretchBlt(dc.m_hDC,0,0, mDispR.Width(), mDispR.Height(),<br />hMemDC,0,0, mpBitmapInfo- &gt;biWidth, mpBitmapInfo-<br />&gt;biHeight, SRCCOPY);<br />}<br />// 结束显示真彩位图<br />::DeleteObject(SelectObject(hMemDC,hBitmapOld)); <br />// 删 除 位 图<br />} else {</font>
				</p>
				<p>
						<font face="宋体" size="2">// 使用视频函数显示位图</font>
				</p>
				<p>
						<font face="宋体" size="2">if( mPos.x &gt; (mpBitmapInfo- &gt;biWidth - mDispR.Width() ))<br />mPos.x= mpBitmapInfo- &gt;biWidth - mDispR.Width() ;<br />if( mPos.y &gt; (mpBitmapInfo- &gt;biHeight- mDispR.Height()))<br />mPos.y= mpBitmapInfo- &gt;biHeight- mDispR.Height();<br />if( mPos.x &lt; 0 ) mPos.x= 0;<br />if( mPos.y &lt; 0 ) mPos.y= 0;</font>
				</p>
				<p>
						<font face="宋体" size="2">// 显示真彩位图<br />DrawDibRealize( m_hDrawDib, dc.GetSafeHdc(), TRUE);</font>
				</p>
				<p>
						<font face="宋体" size="2">if( mFullViewTog == 0)<br />{<br />Wid.x= mDispR.Width();<br />Wid.y= mDispR.Height();<br />// 1:1 显示时, 不能大于图形大小<br />if( Wid.x &gt; mpBitmapInfo- &gt;biWidth )<br />Wid.x = mpBitmapInfo- &gt;biWidth;<br />if( Wid.y &gt; mpBitmapInfo- &gt;biHeight)<br />Wid.y = mpBitmapInfo- &gt;biHeight;</font>
				</p>
				<p>
						<font face="宋体" size="2">DrawDibDraw( m_hDrawDib, dc.GetSafeHdc()<br />, 0, 0, Wid.x, Wid.y,<br />mpBitmapInfo, (LPVOID) (mpBitsSrc+bfoffBits),<br />mPos.x, mPos.y, Wid.x, Wid.y, DDF_BACKGROUNDPAL);<br />} else {<br />DrawDibDraw( m_hDrawDib, dc.GetSafeHdc(),<br />0, 0, mDispR.Width(), mDispR.Height(),<br />mpBitmapInfo, (LPVOID)</font>
				</p>
		</span>
<img src ="http://www.cppblog.com/swo2006/aggbug/14750.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/swo2006/" target="_blank">swo</a> 2006-11-06 22:25 <a href="http://www.cppblog.com/swo2006/articles/14750.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>位图[转载]</title><link>http://www.cppblog.com/swo2006/articles/11285.html</link><dc:creator>swo</dc:creator><author>swo</author><pubDate>Wed, 16 Aug 2006 05:09:00 GMT</pubDate><guid>http://www.cppblog.com/swo2006/articles/11285.html</guid><wfw:comment>http://www.cppblog.com/swo2006/comments/11285.html</wfw:comment><comments>http://www.cppblog.com/swo2006/articles/11285.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/swo2006/comments/commentRss/11285.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/swo2006/services/trackbacks/11285.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 位图[转载]																										一、概述																		     在Windows中每屏是一个图形图像，灵巧的Windows制作系统，面对庞大的图形编程任务，建立了为绘画多彩的边界、按钮、图标、字体的函数库。当然啦，通过WindowsAPI，这些函数都是可调用的。所谓Windows显示屏幕以...&nbsp;&nbsp;<a href='http://www.cppblog.com/swo2006/articles/11285.html'>阅读全文</a><img src ="http://www.cppblog.com/swo2006/aggbug/11285.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/swo2006/" target="_blank">swo</a> 2006-08-16 13:09 <a href="http://www.cppblog.com/swo2006/articles/11285.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一种位图缩放的快速算法&amp;PSD格式的开发&amp;PSD格式文件的读取</title><link>http://www.cppblog.com/swo2006/articles/11279.html</link><dc:creator>swo</dc:creator><author>swo</author><pubDate>Wed, 16 Aug 2006 02:42:00 GMT</pubDate><guid>http://www.cppblog.com/swo2006/articles/11279.html</guid><wfw:comment>http://www.cppblog.com/swo2006/comments/11279.html</wfw:comment><comments>http://www.cppblog.com/swo2006/articles/11279.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/swo2006/comments/commentRss/11279.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/swo2006/services/trackbacks/11279.html</trackback:ping><description><![CDATA[
		<table border="0" cellpadding="4" width="100%">
				<tbody>
						<tr>
								<td height="19">
										<table border="0" cellpadding="3" cellspacing="3" width="100%">
												<tbody>
														<tr>
																<td>
																		<a href="http://www.csdn.net/">CSDN</a> - <a href="http://dev.csdn.net/">文档中心</a>
      - <font color="#003399"><a id="ArticleTitle1_ArticleTitle1_hlClass" href="http://dev.csdn.net/articlelist.aspx?c=9">其他开发语言
</a></font></td>
																<td align="right">
      阅读：<span id="ArticleTitle1_ArticleTitle1_lblReadCount">42</span>
        评论：
      <span id="ArticleTitle1_ArticleTitle1_lblCommentCount">0</span>
         <a href="http://dev.csdn.net/develop/article/83/83401.shtm#Comment">参与评论</a></td>
														</tr>
												</tbody>
										</table>
										<table bgcolor="#eeeeee" border="0" cellpadding="3" cellspacing="3" width="100%">
												<tbody>
														<tr>
																<td height="0" nowrap="nowrap" width="60">
																		<br />
																</td>
																<td>
																		<br />
																</td>
														</tr>
														<tr>
																<td align="center" bgcolor="#003399" height="16" nowrap="nowrap">
																		<font color="#ffffff">标题</font>
																</td>
																<td>
																		<b> 
        <span id="ArticleTitle1_ArticleTitle1_lblTitle">一种位图缩放的快速算法&amp;PSD格式的开发&amp;PSD格式文件的读取</span></b>    
        选择自 <a id="ArticleTitle1_ArticleTitle1_AuthorLink" href="http://dev.csdn.net/user/byxdaz">byxdaz</a> 的 Blog
    </td>
														</tr>
														<tr>
																<td align="center" bgcolor="#003399" height="16">
																		<font color="#ffffff">关键字</font>
																</td>
																<td width="500"> 
      <span id="ArticleTitle1_ArticleTitle1_lblKeywords">一种位图缩放的快速算法&amp;PSD格式的开发&amp;PSD格式文件的读取</span></td>
														</tr>
														<tr>
																<td align="center" bgcolor="#003399" height="16">
																		<font color="#ffffff">出处</font>
																</td>
																<td> 
      <span id="ArticleTitle1_ArticleTitle1_lblSource"></span></td>
														</tr>
												</tbody>
										</table>
								</td>
						</tr>
						<tr>
								<td width="10">
										<br />
								</td>
								<td>
										<span id="ArticleContent1_ArticleContent1_lblContent">
												<p>一种位图缩放的快速算法&amp;PSD格式的开发&amp;PSD格式文件的读取</p>
												<p>一种位图缩放的快速算法 <img src="E:%5CBaseInfoImage.bmp" /><br /><br />　　给定一个位图，如何将它缩放至任意尺寸？很明显，唯一的方法是：放大时，在像素中间添加一些重复像
素，使图像拉宽；缩小时，把部分像素删除掉，使图像收缩。但是如何确定哪些像素该重复，哪些像素该删除呢？下面的方法是我自已想的，如果你有更好的方法，
请告诉我。我们只考虑水平方向（垂直方向跟水平方向是同样的道理）。下面先从简单的例子来说，最后再推出一个通用的算法：<br /><br />若要放大1倍，应将每一个像素都重复一次，N个像素变成了2N个像素，图像放大为2倍。这个不难；<br /><br />若要缩小1/2，应该每隔一个像素删除一个像素，2N个像素变成了N个像素，图像缩小一半。这个也不难；<br /><br />若要放大1.5倍，怎么办？假设原有2N个像素，现在欲变成3N个像素，须添加N个像素，所以应对原图每隔一个像素添加一个重复像素： <br /><br />若要缩小1/3，就是C的逆过程：每隔两个像素删除一个像素。 <br />　
　上面四个例子都是比较容易的特例。现在来考虑通用的算法。在四个例子的缩放过程可以这样理解。假设欲将长度为N1的像素列变成长度为N2的像素列，首
先，设立两个指针，一个作为源指针，指向原来的像素列，读取源像素，另一个作为目的指针，指向变换后的像素列，写入读取到的像素。然后，以拉伸后像素列的
长度为循环次数，循环N2次，每次循环中由源指针处COPY一个像素到目的指针处，然后目的指针加一，源指针根据每次循环的不同需要增加一定步长（放大时
步长是零或一，缩小时步长大于等于一）。<br />　　算法的框架解决了，但是中心内容仍没有解决：如何确定每次循环里源指针增加的步长？或者说，每次循环
里如何更新源指针的位置？容易看出，通过浮点运算很容易解决这个问题：设立一个初值为零的浮点变量，每次循环中，把这个浮点变量加上N1/N2，并将其结
果的整数部分作为源指针距离起始位置的偏移量；这样，经过N2次循环，浮点变量的值恰好达到N1，源指针也恰好“走”到原像素列的末尾。<br />　　这个
方法可行，但是太慢。如果能将浮点运算转化成整数运算就快多了。那么如何转化呢？我们可以设立一个值域为N1*N2的整数计数器，每次循环递增N1，并且
规定，计数器每增加N2，源指针就前进一个像素。这样，经过N2次循环，计数器共增加了N1*N2，源指针则增加了N1个单元，恰好“走”完全程。实际编
程中，我们是用一个值域为N2的整数计数器，超出值域部分取模处理。算法大致如下：<br /><br />　　void StrechPixels(int N1, int N2, PIXEL src_pixels[], PIXEL dest_pixels[])<br />　　{<br />　　　　ASSERT(N1 &lt;= N2);　　// N1 must &lt;= N2<br />　　　　int p1 = 0, count = 0;<br />　　　　for (int p2 = 0; p2 &lt; N2; p2++)<br />　　　　{<br />　　　　　　dest_pixels[p2] = src_pixels[p1];<br />　　　　　　count += N1;<br />　　　　　　while (count &gt;= N2)<br />　　　　　　{<br />　　　　　　　　count -= N2;<br />　　　　　　　　p1++;<br />　　　　　　}<br />　　　　}<br />　　}<br /><br />　
　上面算法只是水平缩放单行像素，对垂直方向也采用同样的算法，便实现了任意比例的位图缩放。经过以上算法的处理，放大时图像出现马赛克，缩小时图像出现
闪砾。若要获得高质量的缩放图形，须采用插值、过滤等技术。但是因为这些技术所需计算量太大，在游戏中通常靠硬件加速来实现，不宜软件解决。  <br /><br /><br />================================================================<br />PSD格式的开发 <br /><br /><br /><br />　
　我在做游戏时，因为要用到将PSD格式转换成BMP或者JPG格式的程序，而且，在转换时，要将PSD中的空格转成游戏中约定的透明色，这样的程序，只
能自己去写了。所以，我在网上搜了一阵子，找到了“中国游戏开发者”的网站，看到了一篇关于PSD格式的文章（这也是我开始向这个网站投稿的原因，也许这
就叫缘）。<br />　　本来是想偷点懒，省去了自己研究之苦，可以抄一抄别人现在的代码，再自己改改，又能省时间，又能学到东西，何乐而不为呢？可是，在
抄下这篇文章的代码之后，发现其运行居然是不能通过的。看来天下没有免费的午餐，我还是得自己研究。一个多小时的苦战之后，终于发现了问题所在，也许这并
不是一个问题，只是对于没有这个经验人来说，这确实是个大问题。我现在将这篇文章的一些地方进行改正，望各位朋友在开发PSD格式的读取问题上，不再有麻
烦。原文《PSD格式文件的读取》在这里http:
//cgd.pages.com.cn/cgd/develop/effect/200109/ReadPSD.htm，各位可以看看。我只将我的改正部
分写在下面： <br /><br />　　1）文件头是4个字节，只能读4个字节。<br />　　2）Photoshop的PSD格式用的是LIT格式存储。<br /><br />　
　这个LIT格式我以前只是听说过，没想到会被PSD用上。这个格式是将数据的高低位码交换了的，如果直接用ReadFile或者fread函数将其读出
来，它的高低位码是被交换了的。例如：640的16进制值是1E0，用DWORD方式存在硬盘里是0001E000，用读文件的函数读出来以后，将变成：
00E00100。所以，其高低位码被交换了，解决的方法是用转换函数，代码如下：<br /><br />　　WORD WORDBIGtoLIT(WORD code)　// 字型的处理<br />　　{<br />　　　　return ((a &gt;&gt; 8 &amp; 0xFF) | ((a &amp; 0x00FF) &lt;&lt; 8);　// 把高低位码再交换过来<br />　　}<br /><br />　　DWORD DWORDBIGtoLIT(DWORD code)　// 双字型的处理<br />　　{<br />　　　　WORD HiCode, LowCode;<br /><br />　　　　HiCode = code &amp; 0xFFFF0000;<br />　　　　LowCode = code &amp; 0x0000FFFF;<br />　　　　HiCode = ((HiCode &gt;&gt; 8) &amp; 0xFF) | ((HiCode &amp; 0x00FF) &lt;&lt; 8);<br />　　　　LowCode ((LowCode &gt;&gt; 8) &amp; 0xFF) | ((LowCode &amp; 0x00FF) &lt;&lt; 8);<br />　　　　return MAKELONG((WORD)(LowCode &lt;&lt; 16), (WORD)HiCode);<br />　　}<br /><br />　　当然，也可以定义成宏形式，如下：<br /><br />　　#define BIG2LIT(a) (WORD((a &gt;&gt; 8 &amp; 0xFF) | ((a &amp; 0x00FF) &lt;&lt; 8)))<br />　　#define DWORDBIG2LIT(b) MAKELONG(BIG2LIT(HIWORD(b)), BIG2LIT(LOWORD(b)))<br /><br />　　看起来简单一些，哈哈……。其它的，原文没有什么错误，不过，我建议大家还是最好自己去解决问题，呵呵，因为有一句话说得很好：老师能教你读书写字，但是不能教你做天下文章。 <br /><br /><br />================================================================<br />PSD格式文件的读取 <br /><br /><br />　
　PhotoShop，我想没有人会不知道吧。如今最新的版本是6.0，其图象文件*.PSD和5.5相比变化并不太大。以下我就介绍*.PSD文件的读
取方法，并提供完整读取函数。其中：m_Rect为目标区域，m_lpDDS7为目标DirectDraw表面，m_pbAlphaMask为目标
Aplha通告指针。Read16函数为从指定文件当前位置读取一个WORD，Read32函数为从指定文件当前位置读取一个DWORD。
MAX_PSD_CHANNELS为24。以下就是*.PSD文件的读取方法，有兴趣的朋友可以继续深入研究，到时可别忘了发我一份。<br /><br />　　HRESULT LoadPSD( LPSTR strFilename ) // 读取PSD文件<br />　　{<br />　　　　DWORD dwWidth, dwHeight; // 宽高<br />　　　　long lSurfWidth = m_Rect.right - m_Rect.left;<br />　　　　long lSurfHeight = m_Rect.bottom - m_Rect.top;<br />　　　　WORD CompressionType; // 压缩类型<br />　　　　HDC hDC;<br />　　　　FILE *fpPSD;<br />　　　　WORD ChannelCount; // 通道数<br /><br />　　　　// 打开PSD文件<br />　　　　if ( ( fpPSD = fopen ( strFilename, "rb" ) ) == NULL ) {<br />　　　　　　return E_FAIL;<br />　　　　}<br /><br />　　　　// 头四个字节为"8BPS"<br />　　　　char signature[5];<br />　　　　signature[0] = fgetc( fpPSD );<br />　　　　signature[1] = fgetc( fpPSD );<br />　　　　signature[2] = fgetc( fpPSD );<br />　　　　signature[3] = fgetc( fpPSD );<br />　　　　signature[4] = '\0';<br />　　　　if ( strcmp( signature,"8BPS" ) != 0 ) {<br />　　　　　　return E_FAIL;<br />　　　　}<br /><br />　　　　// 版本必须为1<br />　　　　if ( Read16( fpPSD ) != 1 ) {<br />　　　　　　return E_FAIL;<br />　　　　}<br /><br />　　　　// 跳过一些数据 (总是0)<br />　　　　Read32( fpPSD );<br />　　　　Read16( fpPSD );<br /><br />　　　　// 读取通道数<br />　　　　ChannelCount = Read16( fpPSD );<br /><br />　　　　// 确定至少有一个通道<br />　　　　if ( ( ChannelCount &lt; 0 ) || ( ChannelCount &gt; MAX_PSD_CHANNELS ) ) {<br />　　　　　　return E_FAIL;<br />　　　　}<br /><br />　　　　// 读入宽和高<br />　　　　dwHeight = Read32( fpPSD );<br />　　　　dwWidth = Read32( fpPSD );<br />　　　　if ( dwWidth != ( DWORD )lSurfWidth || dwHeight != ( DWORD )lSurfHeight ) {<br />　　　　　　return E_FAIL;<br />　　　　}<br /><br />　　　　// 只读入8位通道<br />　　　　if ( Read16( fpPSD ) != 8 ) {<br />　　　　　　return E_FAIL;<br />　　　　}<br /><br />　　　　// 确定模式为RGB.<br />　　　　// 可能值：<br />　　　　// 0: 位图<br />　　　　// 1: 灰阶<br />　　　　// 2: 索引<br />　　　　// 3: RGB<br />　　　　// 4: CMYK<br />　　　　// 7: Multichannel<br />　　　　// 8: Duotone<br />　　　　// 9: Lab<br />　　　　if ( Read16( fpPSD ) != 3 ) {<br />　　　　　　return E_FAIL;<br />　　　　}<br /><br />　　　　// 跳过数据（如调色板）<br />　　　　int ModeDataCount = Read32( fpPSD );<br />　　　　if ( ModeDataCount )<br />　　　　　　fseek( fpPSD, ModeDataCount, SEEK_CUR );<br /><br />　　　　// 跳过数据（如：pen tool paths, etc）<br />　　　　int ResourceDataCount = Read32( fpPSD );<br />　　　　if ( ResourceDataCount )<br />　　　　　　fseek( fpPSD, ResourceDataCount, SEEK_CUR );<br /><br />　　　　// 条过保留数据<br />　　　　int ReservedDataCount = Read32( fpPSD );<br />　　　　if ( ReservedDataCount )<br />　　　　　　fseek( fpPSD, ReservedDataCount, SEEK_CUR );<br /><br />　　　　// 0: 非压缩<br />　　　　// 1: RLE压缩<br />　　　　CompressionType = Read16( fpPSD );<br />　　　　if ( CompressionType &gt; 1 ) {<br />　　　　　　return E_FAIL;<br />　　　　}<br /><br />　　　　BYTE* PSDPixels = new BYTE[ ( lSurfWidth * lSurfHeight ) * 4 ];<br /><br />　　　　// 解包数据<br />　　　　UnPackPSD( fpPSD, lSurfWidth, lSurfHeight, PSDPixels, ChannelCount, CompressionType );<br /><br />　　　　fclose( fpPSD );<br /><br />　　　　// 复制信息<br />　　　　BITMAPINFO BitmapInfo;<br />　　　　ZeroMemory( &amp;BitmapInfo, sizeof( BitmapInfo ) );<br />　　　　BitmapInfo.bmiHeader.biSize = sizeof( BitmapInfo.bmiHeader );<br />　　　　BitmapInfo.bmiHeader.biWidth = lSurfWidth;<br />　　　　BitmapInfo.bmiHeader.biHeight = -lSurfHeight;<br />　　　　BitmapInfo.bmiHeader.biPlanes = 1;<br />　　　　BitmapInfo.bmiHeader.biBitCount = 32;<br /><br />　　　　m_lpDDS7-&gt;GetDC( &amp;hDC );<br /><br />　　　　int rc = StretchDIBits( hDC,<br />　　　　　　　　　　　　　　　　0,<br />　　　　　　　　　　　　　　　　0,<br />　　　　　　　　　　　　　　　　lSurfWidth,<br />　　　　　　　　　　　　　　　　lSurfHeight,<br />　　　　　　　　　　　　　　　　0,<br />　　　　　　　　　　　　　　　　0,<br />　　　　　　　　　　　　　　　　lSurfWidth,<br />　　　　　　　　　　　　　　　　lSurfHeight,<br />　　　　　　　　　　　　　　　　PSDPixels,<br />　　　　　　　　　　　　　　　　&amp;BitmapInfo,<br />　　　　　　　　　　　　　　　　DIB_RGB_COLORS,<br />　　　　　　　　　　　　　　　　SRCCOPY );<br /><br />　　　　m_lpDDS7-&gt;ReleaseDC( hDC );<br /><br />　　　　if ( rc == GDI_ERROR ) {<br />　　　　　　H_ARRAY_DELETE( PSDPixels );<br /><br />　　#ifdef _DEBUG<br />　　　　g_pHERR-&gt;OutDebugMsg( 3, H2DSERR_INVALID_PSD );<br />　　#endif<br />　　　　return E_FAIL;<br /><br />　　　　}<br /><br />　　　　// 是否读取Alpha混合通道<br />　　　　if( ChannelCount &gt; 3 ) {<br />　　　　　　m_pbAlphaMask = new BYTE[ lSurfWidth * lSurfHeight ];<br /><br />　　　　for ( int x = 0; x &lt; lSurfWidth; x++ )<br />　　　　　　for ( int y = 0; y &lt; lSurfHeight; y++ ) {<br />　　　　　　　　m_pbAlphaMask[ ( y * lSurfWidth ) + x ] =<br />　　　　　　　　　　　　　　 　PSDPixels[ ( ( ( y * lSurfHeight ) + x ) * 4 ) + 3 ];<br />　　　　　　}<br />　　　　}<br />　　　　else {<br />　　　　　　m_pbAlphaMask = NULL;<br />　　　　}<br /><br />　　　　H_ARRAY_DELETE( PSDPixels );<br /><br />　　　　return DD_OK;<br />　　}<br /><br />　　// PSD文件解包<br /><br />　　void CHades2DSurface::UnPackPSD( FILE *fp,　　　　　// fp为PSD文件指针，<br />　　　　　　　　　　　　　　　　　　 DWORD dwWidth,　　 // dwWidth、dwHeight为宽高，<br />　　　　　　　　　　　　　　　　　　 DWORD dwHeight,<br />　　　　　　　　　　　　　　　　　　 BYTE* pixels,　　　// pixels为解包目标指针，<br />　　　　　　　　　　　　　　　　　　 WORD ChannelCnt,　 // ChannelCnt为通道数，<br />　　　　　　　　　　　　　　　　　　 WORD Compression ) // Compression位压缩类型。 <br />　　　　　　　　　　　　　　　　<br />　　　　　　　　　　　　　　　　 <br />　　{<br />　　　　int Default[4] = { 0, 0, 0, 255 };<br />　　　　int chn[4] = { 2, 1, 0, 3};<br />　　　　int PixelCount = dwWidth * dwHeight;<br /><br />　　　　if ( Compression ) {<br />　　　　　　fseek( fp, dwHeight * ChannelCnt * 2, SEEK_CUR );<br /><br />　　　　　　for ( int c = 0; c &lt; 4; c++ ) {<br />　　　　　　　　int pn = 0;<br />　　　　　　　　int channel = chn[c];<br /><br />　　　　　　　　if ( channel &gt;= ChannelCnt ) {<br />　　　　　　　　　　for ( pn=0; pn &lt; PixelCount ;pn++ ) {<br />　　　　　　　　　　　　pixels[ ( pn * 4 ) + channel ] = Default[ channel ];<br />　　　　　　　　　　}<br />　　　　　　　　}<br />　　　　　　　　else // 非压缩<br />　　　　　　　　{<br />　　　　　　　　　　int count = 0;<br />　　　　　　　　　　while( count &lt; PixelCount ) {<br />　　　　　　　　　　　　int len = fgetc( fp );<br />　　　　　　　　　　　　if( len == 128 ) { }<br />　　　　　　　　　　　　else if ( len &lt; 128 ) // 非RLE<br />　　　　　　　　　　　　{<br />　　　　　　　　　　　　　　len++;<br />　　　　　　　　　　　　　　count += len;<br />　　　　　　　　　　　　　　while(len) {<br />　　　　　　　　　　　　　　　　pixels[ ( pn * 4 ) + channel ] = fgetc( fp );<br />　　　　　　　　　　　　　　　　pn++;<br />　　　　　　　　　　　　　　　　len--;<br />　　　　　　　　　　　　　　}<br />　　　　　　　　　　　　}<br />　　　 　　　　　　　　 else if ( len &gt; 128 ) // RLE打包<br />　　　　　　　　　　　　{<br />　　　　　　　　　　　　　　len ^= 0x0FF;<br />　　　　　　　　　　　　　　len += 2;<br />　　　　　　　　　　　　　　unsigned char val = fgetc( fp );<br />　　　　　　　　　　　　　　count += len;<br />　　　　　　　　　　　　　　while( len ) {<br />　　　　　　　　　　　　　　　　pixels[ ( pn * 4 ) + channel ] = val;<br />　　　　　　　　　　　　　　　　pn++;<br />　　　　　　　　　　　　　　　　len--;<br />　　　　　　　　　　　　　　}<br />　　　　　　　　　　　　}<br />　　　　　　　　　　}<br />　　　　　　　　}<br />　　　　　　}<br />　　　　}<br />　　　　else<br />　　　　{<br />　　　　　　for ( int c=0; c &lt; 4; c++ ) {<br />　　　　　　　　int channel = chn[c];<br />　　　　　　　　if ( channel &gt; ChannelCnt ) {<br />　　　　　　　　　　for( int pn = 0; pn &lt; PixelCount; pn++ ) {<br />　　　　　　　　　　　　pixels[ ( pn * 4 ) + channel ] = Default[ channel ];<br />　　　　　　　　　　}<br />　　　　　　　　}<br />　　　　　　　　else {<br />　　　　　　　　　　for( int n = 0; n &lt; PixelCount; n++ ) {<br />　　　　　　　　　　　　pixels[ ( n * 4 ) + channel ] = fgetc( fp );<br />　　　　　　　　　　}<br />　　　　　　　　}<br />　　　　　　}<br />　　　　}<br />　　}  </p>
										</span>
								</td>
						</tr>
				</tbody>
		</table>
<img src ="http://www.cppblog.com/swo2006/aggbug/11279.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/swo2006/" target="_blank">swo</a> 2006-08-16 10:42 <a href="http://www.cppblog.com/swo2006/articles/11279.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用GDI+在内存中转换图片类型 [转载]</title><link>http://www.cppblog.com/swo2006/articles/11004.html</link><dc:creator>swo</dc:creator><author>swo</author><pubDate>Tue, 08 Aug 2006 09:02:00 GMT</pubDate><guid>http://www.cppblog.com/swo2006/articles/11004.html</guid><wfw:comment>http://www.cppblog.com/swo2006/comments/11004.html</wfw:comment><comments>http://www.cppblog.com/swo2006/articles/11004.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/swo2006/comments/commentRss/11004.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/swo2006/services/trackbacks/11004.html</trackback:ping><description><![CDATA[
		<p align="center">
				<b>使用GDI+在内存中转换图片类型 [转载]</b>
				<br />
		</p>
		<p>
				<br />　　首先，在StdAfx.h中静态调用diplus.lib，即由编译系统完成对DLL的加载，应用程序结束时卸载DLL的编码。如下：
</p>
		<pre>#ifndef ULONG_PTR<br />#define ULONG_PTR unsigned long*<br />#include "GdiPlus.h"<br />using namespace Gdiplus;<br />#pragma comment(lib, "gdiplus.lib")<br />#endif<br /></pre>

在类的头文件中定义，以下成员变量，用来初始化GDI+的使用和结束使用。
<pre>GdiplusStartupInput m_gdiplusStartupInput; <br />	ULONG_PTR m_gdiplusToken;<br /></pre>

然后在OnCreate()函数中加入初始化GDI+的函数：
<pre>GdiplusStartup(&amp;m_gdiplusToken, &amp;m_gdiplusStartupInput, NULL); 	<br /></pre>
在OnDestroy()函数中加入结束GDI+使用的函数：
<pre>	GdiplusShutdown(m_gdiplusToken);<br /></pre>

接着，定义转换函数：<pre>BOOL MBmpToMImage(CMemFile&amp; cbfBmp, CMemFile&amp; cbfImage, CString strType)<br /></pre>
其中：
<pre>CMemFile&amp; cbfBmp表示原位图文件;<br />CMemFile&amp; cbfImage表示转换后的图形文件;<br />CString strType表示转换的图片类型。<br /></pre>
该函数中主要的处理为以下几步：<ol><li>将原位图文件转换为IStream</li><li>定义Image类实例，并使用第1步获得的IStream初始化</li><li>获取转换的图片类型的CLSID</li><li>将Image以转换的图片类型保存到IStream中</li><li>将IStream转换为CMemFile内存文件(也可为CFile)</li></ol><p>详细代码如下： </p><pre>BOOL MBmpToMImage(CMemFile&amp; cbfBmp, CMemFile&amp; cbfImage, CString strType)<br />{<br />	int iBmpSize = cbfBmp.GetLength();<br />	HGLOBAL hMemBmp = GlobalAlloc(GMEM_FIXED, iBmpSize);<br />	if (hMemBmp == NULL) return FALSE;<br />	IStream* pStmBmp = NULL;<br />	CreateStreamOnHGlobal(hMemBmp, FALSE, &amp;pStmBmp);<br />	if (pStmBmp == NULL) <br />	{<br />		GlobalFree(hMemBmp);<br />		return FALSE;<br />	}<br />	BYTE* pbyBmp = (BYTE *)GlobalLock(hMemBmp);<br />	cbfBmp.SeekToBegin();<br />	cbfBmp.Read(pbyBmp, iBmpSize);<br /><br />	Image* imImage = NULL;<br />	imImage = Image::FromStream(pStmBmp, FALSE);<br />	if (imImage == NULL) <br />	{<br />		GlobalUnlock(hMemBmp);<br />		GlobalFree(hMemBmp);<br />		return FALSE;<br />	}<br />	USES_CONVERSION;<br />	CLSID clImageClsid;<br />	GetImageCLSID(A2W("image/"+strType.GetBuffer(0)), &amp;clImageClsid);<br /><br />	HGLOBAL hMemImage = GlobalAlloc(GMEM_MOVEABLE, 0);<br />	if (hMemImage == NULL)<br />	{<br />		pStmBmp-&gt;Release();<br />		GlobalUnlock(hMemBmp);<br />		GlobalFree(hMemBmp);<br />		if (imImage != NULL) delete imImage;<br />		return FALSE;<br />	}<br />	IStream* pStmImage = NULL;<br />	CreateStreamOnHGlobal(hMemImage, TRUE, &amp;pStmImage);<br />	if (pStmImage == NULL)<br />	{<br />		pStmBmp-&gt;Release();<br />		GlobalUnlock(hMemBmp);<br />		GlobalFree(hMemBmp);<br />		GlobalFree(hMemImage);<br />		if (imImage != NULL) delete imImage<br />		return FALSE;<br />	}	<br />	imImage-&gt;Save(pStmImage, &amp;clJpgClsid);<br />	if (pStmImage == NULL) <br />	{<br />		pStmBmp-&gt;Release();<br />		pStmImage&gt;Release();<br />		GlobalUnlock(hMemBmp);<br />		GlobalFree(hMemBmp);<br />		GlobalFree(hMemImage;<br />		if (imImage != NULL) delete imImage;<br />		return FALSE;<br />	}<br />	LARGE_INTEGER liBegin = {0};<br />	pStmImage-&gt;Seek(liBegin, STREAM_SEEK_SET, NULL);<br />	BYTE* pbyImage = (BYTE *)GlobalLock(hMemImage);<br />	cbfImage.SeekToBegin();<br />	cbfImage.Write(pbyImage, GlobalSize(hMemImage));<br /><br />	if (imImage != NULL) delete imImage;<br />	pStmBmp-&gt;Release();<br />	pStmImage-&gt;Release();<br />	GlobalUnlock(hMemBmp);<br />	GlobalUnlock(hMemImage);<br />	GlobalFree(hMemBmp);<br />	GlobalFree(hMemImage);<br />	return TRUE;<br />}</pre><img src ="http://www.cppblog.com/swo2006/aggbug/11004.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/swo2006/" target="_blank">swo</a> 2006-08-08 17:02 <a href="http://www.cppblog.com/swo2006/articles/11004.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Reading and Writing Metadata</title><link>http://www.cppblog.com/swo2006/articles/11002.html</link><dc:creator>swo</dc:creator><author>swo</author><pubDate>Tue, 08 Aug 2006 08:46:00 GMT</pubDate><guid>http://www.cppblog.com/swo2006/articles/11002.html</guid><wfw:comment>http://www.cppblog.com/swo2006/comments/11002.html</wfw:comment><comments>http://www.cppblog.com/swo2006/articles/11002.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/swo2006/comments/commentRss/11002.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/swo2006/services/trackbacks/11002.html</trackback:ping><description><![CDATA[
		<h1>
Reading and Writing Metadata [转载]<br /></h1>
		<hr size="1" />
		<p>Some image
files contain metadata that you can read to determine features of the
image. For example, a digital photograph might contain metadata that
you can read to determine the make and model of the camera used to
capture the image. With Microsoft Windows GDI+, you can read existing
metadata, and you can also write new metadata to image files.</p>
		<p>GDI+
provides a uniform way of storing and retrieving metadata from image
files in various formats. In GDI+, a piece of metadata is called a <i>property item</i>. You can store and retrieve metadata by calling the <b>SetPropertyItem</b> and 
<b>GetPropertyItem</b> methods of the <a href="http://msdn.microsoft.com/library/en-us/gdicpp/GDIPlus/GDIPlusreference/classes/image.asp">Image</a> class, and you don't have to be concerned about the details of how a particular file format stores that metadata.</p>
		<p>GDI+
currently supports metadata for the TIFF, JPEG, Exif, and PNG file
formats. The Exif format, which specifies how to store images captured
by digital still cameras, is built on top of the TIFF and JPEG formats.
Exif uses the TIFF format for uncompressed pixel data and the JPEG
format for compressed pixel data.</p>
		<p>GDI+ defines a set of property
tags that identify property items. Certain tags are general-purpose;
that is, they are supported by all of the file formats mentioned in the
preceding paragraph. Other tags are special-purpose and apply only to
certain formats. If you try to save a property item to a file that does
not support that property item, GDI+ ignores the request. More
specifically, the <a href="http://msdn.microsoft.com/library/en-us/gdicpp/GDIPlus/GDIPlusreference/classes/imageclass/imagemethods/setpropertyitem.asp">Image::SetPropertyItem</a> method returns PropertyNotSupported.</p>
		<p>You can determine the property items that are stored in an image file by calling <a href="http://msdn.microsoft.com/library/en-us/gdicpp/GDIPlus/GDIPlusreference/classes/imageclass/imagemethods/getpropertyidlist.asp">Image::GetPropertyIdList</a>. If you try to retrieve a property item that is not in the file, GDI+ ignores the request. More specifically, the 
				<a href="http://msdn.microsoft.com/library/en-us/gdicpp/GDIPlus/GDIPlusreference/classes/imageclass/imagemethods/getpropertyitem.asp">Image::GetPropertyItem</a> method returns PropertyNotFound.</p>
		<h2>
				<a name="unknown_41173">
				</a>Reading Metadata from a File</h2>
		<p>The following console application calls the 
				<b>GetPropertySize</b>  method of an 
				<b>Image</b>

 object to determine how many pieces of metadata are in the file FakePhoto.jpg.</p>
		<pre class="clsCode" autohilite="1">
				<font face="Arial" size="3">#include &lt;windows.h&gt;<br />#include &lt;gdiplus.h&gt;<br />#include &lt;stdio.h&gt;<br />using namespace Gdiplus;<br />INT main()<br />{<br />   // Initialize &lt;tla rid="tla_gdiplus"/&gt;.<br />   GdiplusStartupInput gdiplusStartupInput;<br />   ULONG_PTR gdiplusToken;<br />   GdiplusStartup(&amp;gdiplusToken, &amp;gdiplusStartupInput, NULL);<br />   UINT    size = 0;<br />   UINT    count = 0;<br />   Bitmap* bitmap = new Bitmap(L"FakePhoto.jpg");<br />   bitmap-&gt;GetPropertySize(&amp;size, &amp;count);<br />   printf("There are %d pieces of metadata in the file.\n", count);<br />   printf("The total size of the metadata is %d bytes.\n", size);<br /><br />   delete bitmap;<br />   GdiplusShutdown(gdiplusToken);<br />   return 0;<br />}</font>
		</pre>
		<p>
				<font face="Arial" size="3">The preceding code, along with a particular file, FakePhoto.jpg, produced the following output:</font>
		</p>
		<pre class="clsCode" autohilite="1">
				<font face="Arial" size="3">There are 7 pieces of metadata in the file.<br />The total size of the metadata is 436 bytes.</font>
		</pre>
		<p>
				<font face="Arial" size="3">GDI+ stores an individual piece of metadata in a 
				<a href="http://msdn.microsoft.com/library/en-us/gdicpp/GDIPlus/GDIPlusreference/classes/propertyitem.asp">PropertyItem</a> object. You can call the 
				<b>GetAllPropertyItems</b> method of the 
				<b>Image</b> class to retrieve all the metadata from a file. The <b>GetAllPropertyItems</b> method returns an array of <b>PropertyItem</b> objects. Before you call 
				<b>GetAllPropertyItems</b>, you must allocate a buffer large enough to receive that array. You can call the 
				<b>GetPropertySize</b>  method of the 
				<b>Image</b></font>
				<font size="3">

 class to get the size (in bytes) of the required buffer.</font>
		</p>
		<p>
				<font face="Arial" size="3">A 
				<b>PropertyItem</b> object has the following four public members: </font>
		</p>
		<table class="clsStd">
				<tbody>
						<tr>
								<td>
										<font face="Arial" size="3">
												<b>id</b>
										</font>
								</td>
								<td>
										<font face="Arial" size="3">A tag that identifies the metadata item. The values that can be assigned to <b>id</b> (PropertyTagImageTitle, PropertyTagEquipMake, PropertyTagExifExposureTime, and the like) are defined in Gdiplusimaging.h.</font>
								</td>
						</tr>
						<tr>
								<td>
										<font face="Arial" size="3">
												<b>length</b>
										</font>
								</td>
								<td>
										<font face="Arial" size="3">The length, in bytes, of the array of values pointed to by the <b>value</b> data member. Note that if the <b>type</b> data member is set to PropertyTagTypeASCII, then the length data member is the <b>length</b> of a null-terminated character string, including the NULL terminator.</font>
								</td>
						</tr>
						<tr>
								<td>
										<font face="Arial" size="3">
												<b>type</b>
										</font>
								</td>
								<td>
										<font face="Arial" size="3">The
data type of the values in the array pointed to by the value data
member. Constants (PropertyTagTypeByte, PropertyTagTypeASCII, and the
like) that represent various data types are described in <a href="http://msdn.microsoft.com/library/en-us/gdicpp/GDIPlus/GDIPlusreference/constants/imagepropertytagtypeconstants.asp">Image Property Tag Type Constants</a>.</font>
								</td>
						</tr>
						<tr>
								<td>
										<font face="Arial" size="3">
												<b>value</b>
										</font>
								</td>
								<td>
										<font face="Arial" size="3">A pointer to an array of values.</font>
								</td>
						</tr>
				</tbody>
		</table>
		<p>
				<font face="Arial" size="3">The
following console application reads and displays the seven pieces of
metadata in the file FakePhoto.jpg. The main function relies on the
helper function PropertyTypeFromWORD, which is shown following the main
function.</font>
		</p>
		<pre class="clsCode" autohilite="1">
				<font face="Arial" size="3">#include &lt;windows.h&gt;<br />#include &lt;gdiplus.h&gt;<br />#include &lt;strsafe.h&gt;<br />using namespace Gdiplus;<br /><br />INT main()<br />{<br />   // Initialize GDI+<br />   GdiplusStartupInput gdiplusStartupInput;<br />   ULONG_PTR gdiplusToken;<br />   GdiplusStartup(&amp;gdiplusToken, &amp;gdiplusStartupInput, NULL);<br /><br />   UINT  size = 0;<br />   UINT  count = 0;<br /><br />   #define MAX_PROPTYPE_SIZE 30<br />   WCHAR strPropertyType[MAX_PROPTYPE_SIZE] = L"";<br /><br />   Bitmap* bitmap = new <b>Bitmap</b>(L"FakePhoto.jpg");<br /><br /><b>bitmap</b>-&gt;GetPropertySize(&amp;size, &amp;count);<br />   printf("There are %d pieces of metadata in the file.\n\n", count);<br /><br />   // GetAllPropertyItems returns an array of PropertyItem objects.<br />   // Allocate a buffer large enough to receive that array.<br />   PropertyItem* <b><i>pPropBuffer </i></b>=(PropertyItem*)malloc(size);<br /><br />   // Get the array of PropertyItem objects.<br /><b>bitmap</b>-&gt;GetAllPropertyItems(size, count, pPropBuffer);<br /><br />   // For each PropertyItem in the array, display the id, type, and length.<br />   for(UINT j = 0; j &lt; count; ++j)<br />   {<br />      // Convert the property type from a WORD to a string.<br /><font color="#990000">PropertyTypeFromWORD</font>(<br /><b><i>pPropBuffer</i></b>[j].type, strPropertyType, MAX_PROPTYPE_SIZE);<br /><br />      printf("Property Item %d\n", j);<br />      printf("  id: 0x%x\n", pPropBuffer[j].id);<br />      wprintf(L"  type: %s\n", strPropertyType);<br />      printf("  length: %d bytes\n\n", pPropBuffer[j].length);<br />   }<br /><br />   free(pPropBuffer);<br />   delete bitmap;<br />   GdiplusShutdown(gdiplusToken);<br />   return 0;<br />} // main<br /><br />// Helper function<br />HRESULT <font color="#990000">PropertyTypeFromWORD(</font>WORD index, WCHAR* string, UINT maxChars)<br />{<br />   HRESULT hr = E_FAIL;<br /><br />   WCHAR* propertyTypes[] = {<br />      L"Nothing",                   // 0<br />      L"PropertyTagTypeByte",       // 1<br />      L"PropertyTagTypeASCII",      // 2<br />      L"PropertyTagTypeShort",      // 3<br />      L"PropertyTagTypeLong",       // 4<br />      L"PropertyTagTypeRational",   // 5<br />      L"Nothing",                   // 6<br />      L"PropertyTagTypeUndefined",  // 7<br />      L"Nothing",                   // 8<br />      L"PropertyTagTypeSLONG",      // 9<br />      L"PropertyTagTypeSRational"}; // 10<br /><br />   hr = StringCchCopyW(string, maxChars, propertyTypes[index]);<br />   return hr;<br />}</font>
		</pre>
		<p>
				<font face="Arial" size="3">The preceding console application produces the following output:</font>
		</p>
		<pre class="clsCode" autohilite="1">
				<font face="Arial" size="3">Property Item 0<br />  id: 0x320<br />  type: PropertyTagTypeASCII<br />  length: 16 bytes<br />Property Item 1<br />  id: 0x10f<br />  type: PropertyTagTypeASCII<br />  length: 17 bytes<br />Property Item 2<br />  id: 0x110<br />  type: PropertyTagTypeASCII<br />  length: 7 bytes<br />Property Item 3<br />  id: 0x9003<br />  type: PropertyTagTypeASCII<br />  length: 20 bytes<br />Property Item 4<br />  id: 0x829a<br />  type: PropertyTagTypeRational<br />  length: 8 bytes<br />Property Item 5<br />  id: 0x5090<br />  type: PropertyTagTypeShort<br />  length: 128 bytes<br />Property Item 6<br />  id: 0x5091<br />  type: PropertyTagTypeShort<br />  length: 128 bytes</font>
		</pre>
		<p>
				<font face="Arial" size="3">The preceding output shows a hexadecimal ID number for each property item. You can look up those ID numbers in <a href="http://msdn.microsoft.com/library/en-us/gdicpp/GDIPlus/GDIPlusreference/constants/imagepropertytagconstants.asp">Image Property Tag Constants</a> and find out that they represent the following property tags.</font>
		</p>
		<table class="clsStd">
				<tbody>
						<tr>
								<th>
										<font face="Arial" size="3">Hexadecimal value</font>
								</th>
								<th>
										<font face="Arial" size="3">Property tag</font>
								</th>
						</tr>
						<tr>
								<td>
										<font face="Arial" size="3">0x0320 </font>
										<p>
												<font face="Arial" size="3">0x010f</font>
										</p>
										<p>
												<font face="Arial" size="3">0x0110</font>
										</p>
										<p>
												<font face="Arial" size="3">0x9003</font>
										</p>
										<p>
												<font face="Arial" size="3">0x829a</font>
										</p>
										<p>
												<font face="Arial" size="3">0x5090</font>
										</p>
										<p>
												<font face="Arial" size="3">0x5091</font>
										</p>
								</td>
								<td>
										<font face="Arial" size="3">PropertyTagImageTitle </font>
										<p>
												<font face="Arial" size="3">PropertyTagEquipMake</font>
										</p>
										<p>
												<font face="Arial" size="3">PropertyTagEquipModel</font>
										</p>
										<p>
												<font face="Arial" size="3">PropertyTagExifDTOriginal</font>
										</p>
										<p>
												<font face="Arial" size="3">PropertyTagExifExposureTime</font>
										</p>
										<p>
												<font face="Arial" size="3">PropertyTagLuminanceTable</font>
										</p>
										<p>
												<font face="Arial" size="3">PropertyTagChrominanceTable</font>
										</p>
								</td>
						</tr>
				</tbody>
		</table>
		<p>
				<font face="Arial" size="3">The second (index 1) property item in the list has 
				<b>id</b> PropertyTagEquipMake and <b>type</b>
PropertyTagTypeASCII. The following example, which is a continuation of
the previous console application, displays the value of that property
item:</font>
		</p>
		<pre class="clsCode" autohilite="1">
				<font face="Arial" size="3">printf("The equipment make is %s.\n", pPropBuffer[1].value);</font>
		</pre>
		<p>
				<font face="Arial" size="3">The preceding line of code produces the following output:</font>
		</p>
		<pre class="clsCode" autohilite="1">
				<font face="Arial" size="3">The equipment make is Northwind Traders.</font>
		</pre>
		<p>
				<font face="Arial" size="3">The fifth (index 4) property item in the list has 
				<b>id</b> PropertyTagExifExposureTime and 
				<b>type</b> PropertyTagTypeRational. That data type (PropertyTagTypeRational) is a pair of 
				<b>LONG</b>s. The following example, which is a continuation of the previous console application, displays those two 
				<b>LONG</b> values as a fraction. That fraction, 1/125, is the exposure time measured in seconds.</font>
		</p>
		<pre class="clsCode" autohilite="1">
				<font face="Arial" size="3">long* ptrLong = (long*)(pPropBuffer[4].value);<br />printf("The exposure time is %d/%d.\n", ptrLong[0], ptrLong[1]);</font>
		</pre>
		<p>
				<font face="Arial" size="3">The preceding code produces the following output:</font>
		</p>
		<pre class="clsCode" autohilite="1">
				<font face="Arial" size="3">The exposure time is 1/125.</font>
		</pre>
		<h2>
				<font face="Arial" size="3">
						<a name="unknown_13673">
						</a>Writing Metadata to a File</font>
		</h2>
		<p>
				<font face="Arial" size="3">To write an item of metadata to an 
				<b>Image</b>

 object, initialize a 
				<b>PropertyItem</b> object and then pass the address of that 
				<b>PropertyItem</b> object to the 
				<b>SetPropertyItem</b>  method of the 
				<b>Image</b>

 object.</font>
		</p>
		<p>
				<font face="Arial" size="3">The following console application writes one item (the image title) of metadata to an 
				<b>Image</b>
object and then saves the image in the disk file FakePhoto2.jpg. The
main function relies on the helper function GetEncoderClsid, which is
shown in the topic <a href="http://msdn.microsoft.com/library/en-us/gdicpp/GDIPlus/usingGDIPlus/usingimageencodersanddecoders/retrievingthe.asp">Retrieving the Class Identifier for an Encoder</a>.</font>
		</p>
		<pre class="clsCode" autohilite="1">
				<font face="Arial" size="3">#include &lt;windows.h&gt;<br />#include &lt;gdiplus.h&gt;<br />#include &lt;stdio.h&gt;<br />using namespace Gdiplus;<br />INT main()<br />{<br />   // Initialize &lt;tla rid="tla_gdiplus"/&gt;.<br />   GdiplusStartupInput gdiplusStartupInput;<br />   ULONG_PTR gdiplusToken;<br />   GdiplusStartup(&amp;gdiplusToken, &amp;gdiplusStartupInput, NULL);<br />   Status stat;<br />   CLSID  clsid;<br />   char   <i><b>propertyValue</b>[] </i>= "Fake Photograph";<br />   Bitmap* <u>bitmap </u>= new Bitmap(L"FakePhoto.jpg");<br /><b>PropertyItem</b>* propertyItem = new PropertyItem;<br />   // Get the CLSID of the JPEG encoder.<br />   GetEncoderClsid(L"image/jpeg", &amp;clsid);<br /><b>propertyItem</b>-&gt;id = PropertyTagImageTitle;<br /><b>propertyItem</b>-&gt;length = 16;  // string length including NULL terminator<br /><b>propertyItem</b>-&gt;type = PropertyTagTypeASCII; <br /><b>propertyItem</b>-&gt;value = <i>propertyValue</i>;<br /><font color="#990000"></font><font color="#990000"><u>bitmap</u>-&gt;SetPropertyItem(<b>propertyItem</b>);</font><br />   stat = <u>bitmap</u>-&gt;Save(L"FakePhoto2.jpg", &amp;clsid, NULL);<br />   if(stat == Ok)<br />      printf("FakePhoto2.jpg saved successfully.\n");<br /><br />   delete propertyItem;<br />   delete bitmap;<br />   GdiplusShutdown(gdiplusToken);<br />   return 0;<br />}</font>
		</pre>
<img src ="http://www.cppblog.com/swo2006/aggbug/11002.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/swo2006/" target="_blank">swo</a> 2006-08-08 16:46 <a href="http://www.cppblog.com/swo2006/articles/11002.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在GDI+中绘制GIF</title><link>http://www.cppblog.com/swo2006/articles/11000.html</link><dc:creator>swo</dc:creator><author>swo</author><pubDate>Tue, 08 Aug 2006 08:24:00 GMT</pubDate><guid>http://www.cppblog.com/swo2006/articles/11000.html</guid><wfw:comment>http://www.cppblog.com/swo2006/comments/11000.html</wfw:comment><comments>http://www.cppblog.com/swo2006/articles/11000.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/swo2006/comments/commentRss/11000.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/swo2006/services/trackbacks/11000.html</trackback:ping><description><![CDATA[在GDI+中绘制GIF<br /><br />GDI+中绘制一个图片的代码如下: <br />      void CMyWnd::OnPaint()<br />      {<br />      CPaintDC dc(this);<br />      Graphics graphics(&amp;dc); // Create a GDI+ graphics object<br /><br />      Image image(L"Test.Gif"); // Construct an image<br />      graphics.DrawImage(&amp;image, 0, 0, image.GetWidth(), image.GetHeight());<br />      }<br /><br />Gif
分为两种，一种是静态的，对于这种格式的Gif，在GDI+中无需采用任何方法就能够直接显示(上面的代码就属于这种情况)。另一种是动态的，
这种文件能够显示简单的动画。动态的实际上由多幅静态的组成，在显示Gif时，每幅图片按照一定的时间间隔依次进行显示，从而实现了动画效果。 <br />我把GIF封装成了一个类ImageEx,这个类继承了GDI+中的Image类。我们首先要做的工作是判断GIF是动态的还是静态的。 <br />bool ImageEx::TestForAnimatedGIF()<br />{<br />       UINT count = 0;<br />       count = GetFrameDimensionsCount();<br />       GUID* pDimensionIDs = new GUID[count];<br /><br />       // 得到子帧的对象列表<br />       GetFrameDimensionsList(pDimensionIDs, count);<br /><br />    //获取总帧数<br />    m_nFrameCount = GetFrameCount(&amp;pDimensionIDs[0]);<br /><br />    // 假设图像具有属性条目 PropertyItemEquipMake.<br />    // 获取此条目的大小.<br />    int nSize = GetPropertyItemSize(PropertyTagFrameDelay);<br /><br />    // 为属性条目分配空间.<br />    m_pPropertyItem = (PropertyItem*) malloc(nSize);<br />    GetPropertyItem(PropertyTagFrameDelay, nSize, m_pPropertyItem);<br />    delete pDimensionIDs;<br />    return m_nFrameCount &gt; 1;<br /><br />}<br />m_pPropertyItem-&gt;value
是一个长整形数组, 每个长整形代表每帧的延时。由于获取的属性不同，GetPropertyItem会获得不同大小的对象，
因此要由用户来获得的对象大小，开辟与删除 GetPropertyItem相关的内存。对象的大小是通过GetPropertyItemSize
获取的，其参数是你所感兴趣的属性条目。 一旦获取了帧的数量与延时，我们就可生成一个线程来调用 DrawFrameGIF（）来显示。 <br />       bool ImageEx::DrawFrameGIF()<br />       {<br />       ::WaitForSingleObject(m_hPause, INFINITE);<br />       GUID pageGuid = FrameDimensionTime;<br />       long hmWidth = GetWidth();<br />       long hmHeight = GetHeight();<br />       HDC hDC = GetDC(m_hWnd);<br />       if (hDC)<br />       {<br />       Graphics graphics(hDC);<br />       graphics.DrawImage(this, m_rc.left, m_rc.top, hmWidth, hmHeight);<br />       ReleaseDC(m_hWnd, hDC);<br />       }<br />       SelectActiveFrame(&amp;pageGuid, m_nFramePosition++); <br />       if (m_nFramePosition == m_nFrameCount)<br />       m_nFramePosition = 0;<br /><br />       long lPause = ((long*) m_pPropertyItem-&gt;value)[m_nFramePosition] * 10;<br />       DWORD dwErr = WaitForSingleObject(m_hExitEvent, lPause);<br />       return dwErr == WAIT_OBJECT_0;<br />       }<img src ="http://www.cppblog.com/swo2006/aggbug/11000.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/swo2006/" target="_blank">swo</a> 2006-08-08 16:24 <a href="http://www.cppblog.com/swo2006/articles/11000.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在VC中如果实现GIF的播放？</title><link>http://www.cppblog.com/swo2006/articles/10996.html</link><dc:creator>swo</dc:creator><author>swo</author><pubDate>Tue, 08 Aug 2006 06:51:00 GMT</pubDate><guid>http://www.cppblog.com/swo2006/articles/10996.html</guid><wfw:comment>http://www.cppblog.com/swo2006/comments/10996.html</wfw:comment><comments>http://www.cppblog.com/swo2006/articles/10996.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/swo2006/comments/commentRss/10996.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/swo2006/services/trackbacks/10996.html</trackback:ping><description><![CDATA[
		<a>
		</a>
		<a>
				<b>
				</b>
		</a>
		<b>
				<font face="Arial" size="2">
						<a>在VC中如果实现GIF的播放？</a>
						<a>
						</a>
						<br />
						<a>void   CImageView::OnDraw(CDC*   pDC)   </a>
						<br />
						<a>   {   </a>
						<br />
						<a>               CImageDoc*   pDoc   =   GetDocument();   </a>
						<br />
						<a>               ASSERT_VALID(pDoc);   </a>
						<br />
						<a>               //   TODO:   add   draw   code   for   native   data   here   </a>
						<br />
						<a>               IPicture   *pPic;      </a>
						<br />
						<a>               IStream   *pStm;      </a>
						<br />
						<a>                  </a>
						<br />
						<a>               CFileStatus   fstatus;      </a>
						<br />
						<a>               CFile   file;      </a>
						<br />
						<a>               LONG   cb;      </a>
						<br />
						<a>                  </a>
						<br />
						<a>               if   (file.Open("c:/a.jpg",CFile::modeRead)   </a>
						<br />
						<a>                           &amp;&amp;file.GetStatus("c:/a.jpg",   fstatus)   </a>
						<br />
						<a>                           &amp;&amp;((cb   =   fstatus.m_size)   !=   -1))      </a>
						<br />
						<a>               {      </a>
						<br />
						<a>                           HGLOBAL   hGlobal   =   GlobalAlloc(GMEM_MOVEABLE,   cb);      </a>
						<br />
						<a>                           LPVOID   pvData   =   NULL;      </a>
						<br />
						<a>                           if   (hGlobal   !=   NULL)      </a>
						<br />
						<a>                           {      </a>
						<br />
						<a>                                       if   ((pvData   =   GlobalLock(hGlobal))   !=   NULL)      </a>
						<br />
						<a>                                       {      </a>
						<br />
						<a>                                                   file.ReadHuge(pvData,   cb);      </a>
						<br />
						<a>                                                   GlobalUnlock(hGlobal);      </a>
						<br />
						<a>                                                   CreateStreamOnHGlobal(hGlobal,   TRUE,   &amp;pStm);      </a>
						<br />
						<a>                                                      </a>
						<br />
						<a>
                                 
if(SUCCEEDED(::OleLoadPicture(pStm,fstatus.m_size,TRUE,IID_IPicture,(LPVOID*
  )&amp;pPic)))     </a>
						<br />
						<a>                                                   {      </a>
						<br />
						<a>                                                               OLE_XSIZE_HIMETRIC   hmWidth;      </a>
						<br />
						<a>                                                               OLE_YSIZE_HIMETRIC   hmHeight;      </a>
						<br />
						<a>                                                                  </a>
						<br />
						<a>                                                               pPic-&gt;get_Width(&amp;hmWidth);      </a>
						<br />
						<a>                                                               pPic-&gt;get_Height(&amp;hmHeight);      </a>
						<br />
						<a>                                                                  </a>
						<br />
						<a>                                                               double   fX,fY;      </a>
						<br />
						<a>
                                          fX   =  
(double)pDC-&gt;GetDeviceCaps(HORZRES)*(double)hmWidth/((double)pDC-&gt;GetDeviceCaps(HORZSIZE)*100.0);
    </a>
						<br />
						<a>                                           fY   =  
(double)pDC-&gt;GetDeviceCaps(VERTRES)*(double)hmHeight/((double)pDC-&gt;GetDeviceCaps(VERTSIZE)*100.0);
    </a>
						<br />
						<a>                                          
if(FAILED(pPic-&gt;Render(*pDC,0,0,(DWORD)fX,(DWORD)fY,0,hmHeight,hmWidth,-hmHeight,NULL)))
    </a>
						<br />
						<a>                                                  
AfxMessageBox("Failed   To   Render   The   picture!");     </a>
						<br />
						<a>                                                               pPic-&gt;Release();      </a>
						<br />
						<a>                                                   }      </a>
						<br />
						<a>                                                   else      </a>
						<br />
						<a>
                                          AfxMessageBox("Error  
Loading   Picture   From   Stream!");     </a>
						<br />
						<a>                                       }      </a>
						<br />
						<a>                           }      </a>
						<br />
						<a>               }      </a>
						<br />
						<a>               else      </a>
						<br />
						<a>                           AfxMessageBox("Can't   Open   Image   File!");      </a>
						<br />
						<a>      </a>
						<br />
						<a>   }  </a>
				</font>
				<a>
				</a>
		</b>
<img src ="http://www.cppblog.com/swo2006/aggbug/10996.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/swo2006/" target="_blank">swo</a> 2006-08-08 14:51 <a href="http://www.cppblog.com/swo2006/articles/10996.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>在VC下显示JPEG、GIF格式图像的一种简便方法</title><link>http://www.cppblog.com/swo2006/articles/10995.html</link><dc:creator>swo</dc:creator><author>swo</author><pubDate>Tue, 08 Aug 2006 06:48:00 GMT</pubDate><guid>http://www.cppblog.com/swo2006/articles/10995.html</guid><wfw:comment>http://www.cppblog.com/swo2006/comments/10995.html</wfw:comment><comments>http://www.cppblog.com/swo2006/articles/10995.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/swo2006/comments/commentRss/10995.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/swo2006/services/trackbacks/10995.html</trackback:ping><description><![CDATA[
		<h1>
				<font size="4">
						<span class="f16b">在VC下显示JPEG、GIF格式图像的一种简便方法</span>
				</font>
		</h1>
		<font face="Arial">
				<br />
		</font>
		<span class="f141">
				<font face="Arial">一、 引言 <br />
　　
JPEG图像压缩标准随然是一种有损图像压缩标准，但由于人眼视觉的不敏感，经压缩后的画质基本没有发生变化，很快便以较高的压缩率得到了广泛的认可。
GIF格式虽然仅支持256色但它对于颜色较少的图像有着很高的压缩率，甚至超过JPEG标准，也得到了广泛的认同。但作为众多程序员的一个重要的开发工
具--Microsoft Visual C++
6.0的MFC库却仅对没有经过任何压缩的BMP位图文件有着良好的支持，可以读取、显示、存储甚至在内存中创建一块内存位图。由于BMP格式的图像没有
经过任何的压缩，不论是作为程序的外部文件，还是作为程序的内部资源都要占据大量的空间，尤其是后者会大大增加可执行文件的长度。可以看出，如果能用经过
压缩、具有较好的压缩率的JPEG或GIF格式的图像来取代BMP文件在VC中的应用，无疑还是很有吸引力的。 <br />
二、 设计思路 <br />
　　 虽然有一些操作、处理JPEG、GIF等其他格式图像的Active X控件，但总的来说使用起来并不太方便，笔者经过实验摸索，总结出了一种借助于COM接口的OLE方法来实现上述功能的一种简便方法，现介绍如下以飨广大读者： <br />
下面我们要使用IPicture
的COM接口，有必要对该图像接口做些了解：该接口主要管理图像对象及其属性，图像对象为位图、图标和图元等提供一种与语言无关的抽象。和标准的字体对象
一样，系统也提供了对图像对象的标准实现。其主要的接口是IPicture和IPictureDisp，后者是由IDispatch接口派生以便通过自动
化对图像的属性进行访问。图像对象也支持外部接口IPropertyNotifySink，以便用户能在图像属性发生改变时作出决定。图像对象也支持
IPersistStream接口，所以它能从一个IStream接口的实例对象保存、装载自己，而IStream接口也支持对流对象的数据读写。 <br />
　　 我们可以用函数OleLoadPicture从包含有图像数据的流中装载图像。该函数简化了基于流的图像对象的创建过程，可以创建一个新的图像对象并且用流中的内容对它进行初始化。其函数原型为： <br />
STDAPI OleLoadPicture( IStream * pStream, //指向包含有图像数据的流的指针LONG lSize,
//从流中读取的字节数BOOL fRunmode, //图像属性对应的初值REFIID riid,
//涉及到的接口标识，描述要返回的接口指针的类型VOID ppvObj // 在rrid中用到的接口指针变量的地址); <br /><br />
三、 具体的实现 <br />
　　 在显示图像之前，首先要获取到图像文件的存放路径，这里采用标准的文件打开对话框来选取图像文件，文件名存放在CString型的变量m_sPath中： <br />
CFileDialog dlg(TRUE,"jpg","*.jpg", <br />
OFN_HIDEREADONLY|OFN_OVERWR99vEPROMPT, <br />
"JPEG文件(*.jpg)|*.jpg|GIF文件(*.gif)|*.gif||",NULL); <br />
if(dlg.DoModal()==IDOK) <br />
{ <br />
m_sPath=dlg.GetPathName(); <br />
Invalidate(); <br />
} <br />
为简单计，图形显示的代码直接在视类中的OnDraw中编写，首先打开文件并判断文件的可用性，并把文件内容放到流接口IStream的对象pStm中： <br />
IStream *pStm; <br />
CFileStatus fstatus; <br />
CFile file; <br />
LONG cb; <br />
…… <br />
if (file.Open(m_Path,CFile::modeRead)&amp;&amp;file.GetStatus(m_Path,fstatus)&amp;&amp; ((cb = fstatus.m_size) != -1)) <br />
{ <br />
HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, cb); <br />
LPVOID pvData = NULL; <br />
if (hGlobal != NULL) <br />
{ <br />
if ((pvData = GlobalLock(hGlobal)) != NULL) <br />
{ <br />
file.ReadHuge(pvData, cb); <br />
GlobalUnlock(hGlobal); <br />
CreateStreamOnHGlobal(hGlobal, TRUE, &amp;pStm); <br />
} <br />
} <br />
} <br /><br /><br />
　　 然后，就直接调用OleLoadPicture函数从流中装载图像： <br />
IPicture *pPic; <br />
…… <br />
OleLoadPicture(pStm,fstatus.m_size,TRUE,IID_IPicture,(LPVOID*)&amp;pPic)); <br /><br /><br />
　　 由于该函数有时会导致失败，所以应当用SUCCEEDED宏来做一些适当的保护工作,只有在数据装载成功的前提下才能继续下面的图像显示工作： <br />
if(SUCCEEDED(OleLoadPicture(pStm,fstatus.m_size,TRUE,IID_IPicture,(LPVOID*)&amp;pPic))) <br />
{ <br />
OLE_XSIZE_HIMETRIC hmWidth; <br />
OLE_YSIZE_HIMETRIC hmHeight; <br />
pPic-＞get_Width(&amp;hmWidth); <br />
pPic-＞get_Height(&amp;hmHeight); <br />
double fX,fY; <br />
…… <br />
fX = (double)pDC-＞GetDeviceCaps(HORZRES)*(double)hmWidth/((double)pDC-＞GetDeviceCaps(HORZSIZE)*100.0); <br />
fY = (double)pDC-＞GetDeviceCaps(VERTRES)*(double)hmHeight/((double)pDC-＞GetDeviceCaps(VERTSIZE)*100.0); <br />
if(FAILED(pPic-＞Render(*pDC,0,0,(DWORD)fX,(DWORD)fY,0,hmHeight,hmWidth,-hmHeight,NULL))) <br />
AfxMessageBox("渲染图像失败！"); <br />
pPic-＞Release(); <br />
} <br />
else <br />
AfxMessageBox("从流中装载图像失败！"); <br /><br /><br /><br />
　　 其中，显示工作主要是由IPicture接口对象的Render函数来完成的，该函数主要用来将图片的指定部分画到指定的设备环境的指定位置。原型如下： <br />
HRESULT Render( HDC hdc, //渲染图像用的设备环境句柄 <br />
long x, //在hdc上的水平坐标 <br />
long y, //在hdc上的垂直坐标 <br />
long cx, //图像宽度 <br />
long cy, //图像高度 <br />
OLE_XPOS_HIMETRIC xSrc, //在源图像上的水平偏移 <br />
OLE_YPOS_HIMETRIC ySrc, //在源图像上的垂直偏移 <br />
OLE_XSIZE_HIMETRIC cxSrc,//在源图像上水平拷贝的数量 <br />
OLE_YSIZE_HIMETRIC cySrc,//在源图像上垂直拷贝的数量 <br />
LPCRECT prcWBounds //指向目标图元设备环境句柄的指针); <br /><br /><br />
　　 小结：到此为止，通过上述代码已经能够在程序的客户区内显示JPEG、GIF等标准的图像了，但对于有多帧图片（即有动画）的GIF格式的图像，目前还只能显示第一帧，如要完整的显示GIF 动画的全过程，还需要外部Active X控件的支持。 
              
             
            
          
            </font>
				<br />
		</span>
<img src ="http://www.cppblog.com/swo2006/aggbug/10995.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/swo2006/" target="_blank">swo</a> 2006-08-08 14:48 <a href="http://www.cppblog.com/swo2006/articles/10995.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>利用Visual C++实现AVI文件的图像截取</title><link>http://www.cppblog.com/swo2006/articles/10982.html</link><dc:creator>swo</dc:creator><author>swo</author><pubDate>Tue, 08 Aug 2006 05:05:00 GMT</pubDate><guid>http://www.cppblog.com/swo2006/articles/10982.html</guid><wfw:comment>http://www.cppblog.com/swo2006/comments/10982.html</wfw:comment><comments>http://www.cppblog.com/swo2006/articles/10982.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/swo2006/comments/commentRss/10982.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/swo2006/services/trackbacks/10982.html</trackback:ping><description><![CDATA[
		<table border="0" cellpadding="0" cellspacing="2" width="550">
				<tbody>
						<tr>
								<td align="center">
										<b>
												<font class="BHEAD" color="#333399">利用Visual C++实现AVI文件的图像截取</font>
										</b>
								</td>
						</tr>
						<tr>
								<td bgcolor="#bbbbbb" height="1">
										<br />
								</td>
						</tr>
						<tr>
								<td align="center">
										<font face="Arial, Helvetica, sans-serif">
												<span class="nava">2001-10-22· 
              ·刘 涛 ··yesky<br /><br /></span>
										</font>
								</td>
						</tr>
						<tr>
								<td>
										<span class="txt">
												<br />　　AVI文件就是我们所说的多媒体文件，所谓的AVI图像就是视频图像，该文件是一个RIFF说明文件，它用于获取、编辑、演示音频、视频序列。一般的AVI文件包含音频流和视频流，有的特殊的AVI还包含一个控制路径或MIDI路径作为附加的数据流。<br /><br />　
　现在播放AVI文件的软件很多，但大多无法从AVI视频文件中读取一帧图像并生成BMP格式的文件。笔者在使用AVI文件开发项目过程中对AVI文件的
操作积累了一些经验，对于如何实现从AVI视频流中获取任意帧的图像数据并存储成BMP文件，其中最关键的是要从AVI文件中获取具体某一帧的图像数据，
为此我利用Windows提供的API函数实现了自定义的CAvi类，用于操作AVI文件。<br /><br />　　在使用API函数操作AVI文件时，一定
要注意用AVIFileInit()来初始化AVI库，程序结束时用AVIFileExit()释放AVI库，否则API函数无法使用。现以操作包含真彩
色图像的AVI文件为例，给出Cavi类的部分函数的具体实现，其中CaviCreate()函数用于读取AVI文件信息并初始化Cavi类的成员，例如
根据AVI文件信息定义每帧图像的宽、高、每帧图像的信息头结构等等；函数AviRead(int
mFrame)用于从AVI文件中读取第mFrame帧。实现代码显示如下：<br /><br /><table align="center" bgcolor="#ebe9eb" border="0" width="600"><tbody><tr><td>//Cavi类头文件定义；<br />class CAvi file://AVI类，处理AVI文件<br />{<br />　public:<br />　int cy;//图象高<br />　int cx;//图象宽<br />　file://long m_maxFrame;<br />　BYTE *pData;//寸储图象数据<br />　BITMAPINFO *m_pBMI;//位图文件信息头<br />　PAVISTREAM pavi;//AVI流<br />　PAVIFILE pfile;//AVI文件指针<br />　AVIFILEINFO * pfi; file://AVI信息<br />　BOOL AviRead(int mFrame);//读AVI文件的第mFrame帧<br />　CAvi();//标准构造函数<br />　CAviCreate(CString &amp;string);//用文件名初始化AVI类的成员<br />　virtual ~CAvi();<br />}; <br />//Cavi类文件实现部分；<br />CAvi::CAvi()<br />{ AVIFileInit();//初始化AVI库<br />　cx=0;//定义图象宽、高、等成员<br />　cy=0;<br />　m_pBMI=NULL;<br />　pData=NULL;<br />　file://m_maxFrame=0;<br />　pfi=NULL;<br />}<br />CAvi::~CAvi()//析构、释放指针<br />{<br />　// AVIFileClose(pfile);<br />　AVIFileExit();<br />　if(pData!=NULL)<br />　　delete pData;<br />　　pData=NULL;<br /><br />　if(m_pBMI!=NULL)<br />　　delete m_pBMI;<br />　　m_pBMI=NULL;<br />　　if(pfi!=NULL)<br />　　　delete pfi;<br />　　　pfi=NULL;<br />}<br />CAvi::CAviCreate(CString &amp;string)//读文件初始化该类<br />{ <br />　HRESULT hr;<br />　pfi=new AVIFILEINFO;<br />　hr = AVIFileOpen(&amp;pfile, // returned file pointer<br />　string, // file name<br />　OF_READ, // mode to open file with<br />　NULL);<br />　hr= AVIFileInfo(pfile, file://获取AVI信息，放入pfi中<br />　pfi, <br />　sizeof(AVIFILEINFO) <br />);<br />cx=pfi-&gt;dwWidth;//图象宽、高<br />cy=pfi-&gt;dwHeight;<br />hr=AVIFileGetStream(//将AVI变成视频流<br />pfile, <br />&amp;pavi, <br />streamtypeVIDEO, <br />0//LONG lParam <br />);<br />m_pBMI=new BITMAPINFO;//定义BMP信息头<br />m_pBMI-&gt;bmiHeader.biBitCount=24;<br />m_pBMI-&gt;bmiHeader.biClrImportant=0;<br />m_pBMI-&gt;bmiHeader.biClrUsed=0;<br />m_pBMI-&gt;bmiHeader.biCompression=BI_RGB;<br />m_pBMI-&gt;bmiHeader.biHeight=cy;<br />m_pBMI-&gt;bmiHeader.biWidth=cx;<br />m_pBMI-&gt;bmiHeader.biPlanes=1;<br />m_pBMI-&gt;bmiHeader.biSize=sizeof(BITMAPINFOHEADER);<br />m_pBMI-&gt;bmiHeader.biXPelsPerMeter=0;<br />m_pBMI-&gt;bmiHeader.biYPelsPerMeter=0;<br />m_pBMI-&gt;bmiHeader.biSizeImage=cx*cy*3;<br />pData=(BYTE*)new char[cx*cy*3];//根据AVI中BMP图象的信息定义缓冲区<br />}<br />BOOL CAvi::AviRead(int mFrame)//将AVI文件的M帧数据读入PData缓冲区<br />{<br />HRESULT hr;<br />hr= AVIStreamRead( pavi, <br />mFrame, <br />1, <br />pData, <br />cx*cy*3, <br />NULL, <br />NULL<br />);<br />if(hr==0)<br />return TRUE;<br />else<br />return FALSE;<br />}<br /></td></tr></tbody></table><br /><br />　
　上述Cavi类实现部分所涉及到的API函数可以参考微软提供的MSDN。Cavi类中的pData缓冲区存放AVI文件中的具体某一帧图像数据，同时
Cavi类的m_pBMI为BMP图像文件信息结构，这时可以根据图像的大小定义BMP图像文件头结构，关于BMP文件的存储，由于篇幅的原因，我不在多
讲了，有兴趣的读者可以参见笔者的拙作"Visual
C++6.0开发灰度位图处理"（天极网软件栏目2001.9.10发表），该文里面讲述了如何存取BMP文件。以上程序在Windows2000、
Visual C++6.0环境下顺利编译通过，运行正常。</span>
								</td>
						</tr>
				</tbody>
		</table>
<img src ="http://www.cppblog.com/swo2006/aggbug/10982.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/swo2006/" target="_blank">swo</a> 2006-08-08 13:05 <a href="http://www.cppblog.com/swo2006/articles/10982.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Visual C++中DDB与DIB位图编程全攻略</title><link>http://www.cppblog.com/swo2006/articles/10980.html</link><dc:creator>swo</dc:creator><author>swo</author><pubDate>Tue, 08 Aug 2006 05:00:00 GMT</pubDate><guid>http://www.cppblog.com/swo2006/articles/10980.html</guid><wfw:comment>http://www.cppblog.com/swo2006/comments/10980.html</wfw:comment><comments>http://www.cppblog.com/swo2006/articles/10980.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/swo2006/comments/commentRss/10980.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/swo2006/services/trackbacks/10980.html</trackback:ping><description><![CDATA[
		<p align="center">Visual C++中DDB与DIB位图编程全攻略<br />来源: 天极网</p>
		<p align="left">
				<strong>1. 基本概念<br /><br /></strong>先来用通俗的语句讲解位图和调色板的概念。<br />我
们知道，自然界中的所有颜色都可以由红、绿、蓝(R，G，B)三基色组合而成。针对含有红、绿、蓝色成分的多少，可以对其分别分成0～255个等级，而
红、绿、蓝的不同组合共有256×256×256种，因此约能表示1600万种颜色。对于人眼而言，这已经是"真彩色"了。<br /><br />对每个像素进行了（R，G，B）量化的图像就是位图，其在计算机中对应文件的扩展名一般为.bmp。既然用R，G，B的量化值就可以直接记录一张位图的所有像素，那我们需要调色板干什么呢？<br /><br />首先，我们可以计算完全利用（R，G，B）组合来存储一个800×600的位图所需要的空间为：<br /><br />800×600×3 = 1440000（字节）＝ 1.37M（字节）<br /><br />惊人的大！因此，调色板横空出世了，它的功能在于缓解位图文件存储空间过大的问题。<br /><br />假设一个位图为16色，其像素总数为800×600。我们只需要用4个bit就可以存储这个位图的每个像素在16种颜色中所处的等级，然后调色板提供了这16种等级对应的（R，G，B）值，这样，存储这个16色位图只需要：<br /><br />800×600×4/8 = 240000（字节）= 0.22 M（字节）<br /><br />额外的存储R，G，B表的开销（即调色板Palette，也称为颜色查找表LUT）仅仅为16×3＝48字节。<br /><br />存储空间被大为减少！<br /><br />常见的位图有单色、16色、256色、16位及24位真彩色5种，对于前三者（即不大于256色）都可以调色板方式进行存储，而对16位及24位真彩色以调色板进行存储是不划算的，它们直接按照R，G，B分量进行存储。<br /><br />在此基础上我们来分析DDB位图（Device-dependent bitmap，与设备相关的位图）与DIB位图（Device-independent bitmap，与设备无关的位图）的概念以及二者的区别。<br /><br />DDB依赖于具体设备，它只能存在于内存中（视频内存或系统内存），其颜色模式必须与特定的输出设备相一致，使用系统调色板。一般只能载入色彩较简单的DDB位图，对于颜色较丰富的位图，需使用DIB才能长期保存。<br /><br />DIB
不依赖于具体设备，可以用来永久性地保存图象。DIB一般是以*.BMP文件的形式保存在磁盘中的，有时也会保存在*.DIB文件中。
DIB位图的特点是将颜色信息储存在位图文件自身的颜色表中，应用程序要根据此颜色表为DIB创建逻辑调色板。因此，在输出一幅DIB位图之前，程序应该
将其逻辑调色板选入到相关的设备上下文并实现到系统调色板中。<br /><br /><strong>2. 例程简述<br /></strong><br />本文后续的讲解都基于这样的一个例子工程，它是一个基于对话框的MFC应用程序，包括2个父菜单：<br /><br />（1） DDB位图<br /><br />DDB位图父菜单又包括两个子菜单：<br /><br />a. ID：IDM_LOADDDBPIC caption：加载<br /><br />单击事件：加载资源中的DDB位图并显示之<br /><br />b. ID：IDM_MARK_DDBPIC caption：标记<br /><br />单击事件：在DIB位图中透明地添加天极网logo<br /><br />（2） DIB位图<br /><br />DIB位图父菜单又包括两个子菜单：<br /><br />a. ID：IDM_OPENDIBPIC caption：打开<br /><br />单击事件：弹出文件对话框，打开.bmp位图文件，并显示<br /><br />b. ID：IDM_MARK_DIBPIC caption：标记<br /><br />单击事件：在DIB位图中透明地添加天极网logo<br /><br />工程中还包含下列位图资源：<br /><br />（1）IDB_LOADED_BITMAP：要加载的位图资源<br /><br />（2）IDB_YESKY_BITMAP：天极网logo<br /><br />后续篇章将集中在对4个子菜单单击事件消息处理函数的讲解，下面的代码是整个对话框类CBitMapExampleDlg的消息映射：<br /><br /><code>BEGIN_MESSAGE_MAP(CBitMapExampleDlg, CDialog)<br />//{{AFX_MSG_MAP(CBitMapExampleDlg)<br />ON_WM_SYSCOMMAND()<br />ON_WM_PAINT()<br />ON_WM_QUERYDRAGICON()<br />ON_COMMAND(IDM_LOADDDBPIC, OnLoadddbpic)<br />ON_COMMAND(IDM_MARK_DDBPIC, OnMarkDdbpic)<br />ON_COMMAND(IDM_OPENDIBPIC, OnOpendibpic)<br />ON_COMMAND(IDM_MARK_DIBPIC,OnMarkDibpic) //}}AFX_MSG_MAP<br />END_MESSAGE_MAP()</code></p>
		<p> </p>
		<p>
				<strong>3. DDB位图编程<br /><br /></strong>先看DDB加载按钮的单击事件代码：<br /><br /><code>void CBitMapExampleDlg::OnLoadddbpic() <br />{<br />1:　CBitmap bmpDraw;<br />2: bmpDraw.LoadBitmap( IDB_LOADED_BITMAP );//装入要加载的DDB位图 <br />3: BITMAP bmpInfo;<br />4: bmpDraw.GetBitmap( &amp;bmpInfo ); //获取要加载DDB位图的尺寸 <br />5: CDC memDC;//定义一个兼容DC<br />6: CClientDC dc( this );<br />7: memDC.CreateCompatibleDC( &amp;dc );//创建兼容DC<br />8: CBitmap* pbmpOld = memDC.SelectObject( &amp;bmpDraw );//保存原有DDB，并选入新DDB入DC<br /><br />9: dc.BitBlt( 0, 0, bmpInfo.bmWidth, bmpInfo.bmHeight, &amp;memDC, 0, 0, SRCCOPY );<br /><br />10:　memDC.SelectObject( pbmpOld );//选入原DDB<br />}</code><br />上述代码将产生如图1所示的效果，位图被安置在对话框（0,0）坐标开始的位置上。</p>
		<p>
				<img src="http://cimg.163.com/catchpic/F/F8/F8F94958CE8F80443F1BDF1E43BFEA87.jpg" alt="" border="0" />
		</p>
		<p>图1 加载DDB位图资源</p>
		<p> </p>
		<p>
				<br />我们来逐行解析上述代码是怎样产生图1的效果的。<br /><br />第1、2行定义了一个CBitmap对象，并调用其成员函数
LoadBitmap加载工程中的位图资源IDB_LOADED_BITMAP。第3、4行定义了BITMAP结构体的实例并调用CBitmap的成员函
数GetBitmap获得位图信息，BITMAP结构体定义在<wingdi.h></wingdi.h>头文件中，其形式为：<br /><br /><code>/* Bitmap Header Definition */<br />typedef struct tagBITMAP<br />{<br />LONG bmType; //必需为0<br />LONG bmWidth; //位图的宽度(以像素为单位)<br />LONG bmHeight; //位图的高度(以像素为单位)<br />LONG bmWidthBytes; //每一扫描行所需的字节数，应是偶数<br />WORD bmPlanes; //色平面数<br />WORD bmBitsPixel; //色平面的颜色位数<br />LPVOID bmBits; //指向存储像素阵列的数组<br />} BITMAP, *PBITMAP, NEAR *NPBITMAP, FAR *LPBITMAP;</code><br />第5~8行的作用是：构建一个CDC对象，调用CDC::CreateCompatibleDC创建一个兼容的内存设备上下文，接着调用CDC::SelectObject将DDB选入内存设备上下文中。<br /><br />第9行调用函数CDC::BitBlt绘制位图，CDC::BitBlt的原型为：<br /><br /><code>CDC::BitBlt(int x, int y, int nWidth, int nHeight, CDC *pSrcDC, int xSrc, int ySrc, DWORD dwRop)</code><br />CDC::BitBlt执行的操作为将源DC中位图复制到目的DC中。其中前四个参数为目的区域的坐标（x,y）及长度和宽度（Width, nHeight），第五个参数是源DC指针，接下来的参数是源DC中的起始坐标，最后一个参数为光栅操作的类型。<br /><br />第10行调用CDC::SelectObject把原来的DDB选入到内存设备上下文中并使新DDB脱离出来。<br /><br />与CDC::BitBlt对应的还有另一个函数CDC::StretchBlt，它具有缩放功能，其原型为：<br /><br /><code>BOOL CDC::StretchBlt(int x, int y, int nWidth, int nHeight, CDC *pSrcDC, int<br />xSrc, int ySrc, int nSrcWidth, int nSrcHeight, DWORD dwRop);</code><br />该函数把位图从源矩形拷贝到目的矩形中，如果源和目的矩形尺寸不同，那么将缩放位图的功能以适应目的矩形的大小。函数的大部分参数与BitBlt的相同，但多了两个参数nSrcWidth和nSrcHeight用来指定源矩形的宽和高。<br /><br />如果我们将函数CBitMapExampleDlg::OnLoadddbpic() 中的第9行改为：<br /><br /><code>CRect clientRect;<br />GetClientRect(&amp;clientRect); //获得对话框窗口的大小<br />dc.StretchBlt(0, 0, clientRect.right, clientRect.bottom, &amp;memDC, 0, 0,<br />bmpInfo.bmWidth, bmpInfo.bmHeight, SRCCOPY);</code><br />则单击加载按钮后的对话框如图2所示，位图被拉伸至整个对话框的范围。<br /></p>
		<p>
				<br />
		</p>
		<p align="center">
				<img src="http://cimg.163.com/catchpic/4/4F/4F91CC4A105C69E77279A52F4FB2A9EE.jpg" alt="" border="0" />
		</p>
		<p align="center">
				<br />图2 拉伸位图<br /></p>
		<p>CDC::BitBlt和dc.StretchBlt函数中的dwRop参数较为有用，它定义光栅操作的类型。请看"DDB位图"父菜单下"标记"子菜单单击事件的消息处理函数代码：<br /><br /><code>void CBitMapExampleDlg::OnMarkDdbpic()<br />{<br />CBitmap bmpDraw;<br />bmpDraw.LoadBitmap(IDB_YESKY_BITMAP); //装入天极网logo DDB位图资源<br />BITMAP bmpInfo;<br />bmpDraw.GetBitmap(&amp;bmpInfo); //获取天极网logo位图的尺寸 <br /><br />CDC memDC; //定义一个兼容DC<br />CClientDC dc(this);<br />memDC.CreateCompatibleDC(&amp;dc); //创建DC<br /><br />CBitmap *pbmpOld = memDC.SelectObject(&amp;bmpDraw);<br />//保存原有DDB，并选入天极网logo位图入DC<br />dc.BitBlt(0, 0, bmpInfo.bmWidth, bmpInfo.bmHeight, &amp;memDC, 0, 0, SRCAND);<br />memDC.SelectObject(pbmpOld); //选入原DDB <br />}</code><br />单击该按钮后，将产生如图3的效果，天极网的logo被透明地添加到了位图中！<br /></p>
		<p>
				<br />
		</p>
		<p align="center">
				<img src="http://cimg.163.com/catchpic/A/AE/AE56DF89FB6B969070E26137BC6C5041.jpg" alt="" border="0" />
		</p>
		<p align="center">
				<br />图3 在DDB位图中加入天极网logo<br /></p>
		<p>能产生这个效果的原因在于我们在代码行：<br /><br /><code>dc.BitBlt ( 0, 0, bmpInfo.bmWidth, bmpInfo.bmHeight, &amp;memDC, 0, 0, SRCAND );</code></p>
		<p>
				<code>中使用了参数SRCAND（不同于先前代码中SRCCOPY，它仅仅意味着复制源位图到目的位图），它的含义为源和目的间进行AND操
作。我们不知道天极网的编辑同志是怎么为文章中的图片加logo的，有可能他们就使用了具有自动AND功能的图像加logo批处理软件。的确，我们可以利
用例程中的原理写一个批处理软件，一次对一堆图片自动添加logo。<br /><br />参数dwRop除了可以为SRCAND和SRCCOPY外，还可以有如下取值：<br /><br />BLACKNESS：输出区域为黑色<br /><br />DSTINVERT：反转目的位图 <br /><br />MERGECOPY：用与操作把图案(Pattern)与源位图融合起来 <br /><br />MERGEPAINT：用或操作把反转的源位图与目的位图融合起来 <br /><br />NOTSRCCOPY：把源位图反转然后拷贝到目的地 <br /><br />NOTSRCERASE：用或操作融合源和目的位图，然后再反转 <br /><br />PATCOPY：把图案拷贝到目的位图中 <br /><br />PATINVERT：用异或操作把图案与目的位图相融合 <br /><br />PATPAINT：用或操作融合图案和反转的源位图，然后用或操作把结果与目的位图融合 <br /><br />SRCERASE：先反转目的位图，再用与操作将其与源位图融合 <br /><br />SRCINVERT：用异或操作融合源位图和目的位图 <br /><br />SRCPAINT：用或操作融合源位图和目的位图 <br /><br />WHITENESS：输出区域为白色<br /><br />合理利用这些取值将帮助我们制作出特定要求的图像处理软件。<br /><br />从上述实例我们可以看出，在VC中使用CBitmap类，必须将位图放入工程的资源中，并使用类 CBitmap的成员函数LoadBitmap加载之，再通过CDC类的成员函数BitBlt进行DC拷贝等操作达到显示的目的。CBitmap有显示的不足：<br /><br />（1） 位图需要放入工程资源中，这将导致工程的可执行文件变大；<br /><br />（2） 因为位图需放入工程资源中，而资源中不能无穷无尽地包含位图，应用程序无法自适应地选取其它位图，能使用的位图十分有限的；<br /><br />（3） 类CBitmap只是DDB位图操作API的封装，不能独立于平台。<br /><br />DIB位图则可以解决上述问题，其特点是以.BMP位图文件格式存储独立于平台的图像数据，下面我们来详细分析。<br /><strong>4. DIB位图编程<br /><br /></strong>4.1位图文件格式<br /><br />先来分析DIB位图文件的格式。位图文件分为四部分： <br /><br />（1）位图文件头BITMAPFILEHEADER<br /><br />位图文件头BITMAPFILEHEADER是一个结构体，长度为14字节，定义为：<br /><br /><code>typedef struct tagBITMAPFILEHEADER<br />{<br />WORD bfType; //文件类型，必须是0x424D，即字符串"BM"<br />DWORD bfSize; //文件大小，包括BITMAPFILEHEADER的14个字节<br />WORD bfReserved1; //保留字<br />WORD bfReserved2; //保留字<br />DWORD bfOffBits; //从文件头到实际的位图数据的偏移字节数<br />} BITMAPFILEHEADER;</code><br />（2）位图信息头BITMAPINFOHEADER<br /><br />位图信息头BITMAPINFOHEADER也是一个结构体，长度为40字节，定义为：<br /><br /><code>typedef struct tagBITMAPINFOHEADER<br />{<br />DWORD biSize; //本结构的长度，为40<br />LONG biWidth; //图象的宽度，单位是象素<br />LONG biHeight; //图象的高度，单位是象素<br />WORD biPlanes; //必须是1<br />WORD biBitCount;<br />//表示颜色时要用到的位数，1(单色), 4(16色), 8(256色), 24(真彩色)<br />DWORD biCompression;<br />//指定位图是否压缩，有效的值为BI_RGB，BI_RLE8，BI_RLE4，BI_BITFIELDS等，BI_RGB表示不压缩<br />DWORD biSizeImage;<br />//实际的位图数据占用的字节数，即 biSizeImage=biWidth’ × biHeight，biWidth’是biWidth 按照4的整倍数调整后的结果 <br />LONG biXPelsPerMeter; //目标设备的水平分辨率，单位是每米的象素个数<br />LONG biYPelsPerMeter; //目标设备的垂直分辨率，单位是每米的象素个数<br />DWORD biClrUsed; //位图实际用到的颜色数，0表示颜色数为2biBitCount<br />DWORD biClrImportant; //位图中重要的颜色数，0表示所有颜色都重要<br />} BITMAPINFOHEADER;</code><br />（3）调色板Palette<br /><br />调
色板Palette针对的是需要调色板的位图，即单色、16色和256色位图。对于不以调色板方式存储的位图，则无此项信息。调色板是一个数组，共有
biClrUsed个元素(如果该值为0，则有2biBitCount个元素)。数组中每个元素是一个RGBQUAD结构体，长度为4个字节，定义为：<br /><br /><code>typedef struct tagRGBQUAD<br />{<br />BYTE rgbBlue; //蓝色分量<br />BYTE rgbGreen; //绿色分量<br />BYTE rgbRed; //红色分量<br />BYTE rgbReserved; //保留值<br />} RGBQUAD;</code></code>
		</p>
		<p>
				<code>
						<code>（4）实际的位图数据ImageDate<br /><br />对于用到调色板的位图，实际的图象数据ImageDate为该象素的颜色在调色板中的索引值；对于真彩色图，图象数据则为实际的R、G、B值：<br /><br />a.单色位图：用1bit就可以表示象素的颜色索引值；<br /><br />b.16色位图：用4bit可以表示象素的颜色索引值；<br /><br />c. 256色位图：1个字节表示1个象素的颜色索引值； <br /><br />d.真彩色：3个字节表示1个象素的颜色R，G，B值。<br /><br />此外，位图数据每一行的字节数必须为4的整倍数，如果不是，则需要补齐。奇怪的是，位图文件中的数据是从下到上（而不是从上到下）、从左到右方式存储的。<br />4.2位图的显示<br /><br />Visual C++ MFC中没有提供一个专门的类来处理DIB位图，因此，为了方便地使用位图文件，我们有必要派生一个CDib类。类的源代码如下：<br /><br />(1) CDib类的声明<br /><br /><code>// DIB.h：类CDib声明头文件<br />#ifndef __DIB_H__<br />#define __DIB_H__<br />#include <wingdi.h></wingdi.h><br />class CDib<br />{<br />public:<br />CDib();<br />~CDib();<br /><br />BOOL Load( const char * );<br />BOOL Save( const char * );<br />BOOL Draw( CDC *, int nX = 0, int nY = 0, int nWidth = -1, int nHeight = -1, int mode = SRCCOPY);<br />BOOL SetPalette( CDC * );<br /><br />private:<br />CPalette m_Palette;<br />unsigned char *m_pDib, *m_pDibBits;<br />DWORD m_dwDibSize;<br />BITMAPINFOHEADER *m_pBIH;<br />RGBQUAD *m_pPalette;<br />int m_nPaletteEntries;<br />};<br />#endif<br /></code><br />(2) CDib类的实现<br /><br /><code>// DIB.cpp：类CDib实现文件<br />#include "stdafx.h"<br />#include "DIB.h"<br /><br />CDib::CDib()<br />{<br />m_pDib = NULL;<br />}<br /><br />CDib::~CDib()<br />{<br />// 如果位图已经被加载，释放内存<br />if (m_pDib != NULL)<br />delete []m_pDib;<br />}</code><br />下面这个函数非常重要，其功能为加载位图，类似于CBitmap类的LoadBitmap函数：<br /><br /><code>BOOL CDib::Load(const char *pszFilename)<br />{<br />CFile cf;<br /><br />// 打开位图文件<br />if (!cf.Open(pszFilename, CFile::modeRead))<br />return (FALSE);<br /><br />// 获得位图文件大小，并减去BITMAPFILEHEADER的长度<br />DWORD dwDibSize;<br />dwDibSize = cf.GetLength() - sizeof(BITMAPFILEHEADER);<br /><br />// 为DIB位图分配内存<br />unsigned char *pDib;<br />pDib = new unsigned char[dwDibSize];<br />if (pDib == NULL)<br />return (FALSE);<br /><br />BITMAPFILEHEADER BFH;<br /><br />// 读取位图文件数据<br />try<br />{<br />// 文件格式是否正确有效<br />if ( cf.Read(&amp;BFH, sizeof(BITMAPFILEHEADER)) != sizeof(BITMAPFILEHEADER) ||<br />BFH.bfType != ’MB’ || cf.Read(pDib, dwDibSize) != dwDibSize)<br />{<br />delete []pDib;<br />return (FALSE);<br />}<br />}<br />catch (CFileException *e)<br />{<br />e-&gt;Delete();<br />delete []pDib;<br />return (FALSE);<br />}<br /><br />// delete先前加载的位图<br />if (m_pDib != NULL) <br />delete m_pDib;<br /><br />// 将临时Dib数据指针和Dib大小变量赋给类成员变量<br />m_pDib = pDib;<br />m_dwDibSize = dwDibSize;<br /><br />// 为相应类成员变量赋BITMAPINFOHEADER和调色板指针<br />m_pBIH = (BITMAPINFOHEADER*)m_pDib;<br />m_pPalette = (RGBQUAD*) &amp;m_pDib[sizeof(BITMAPINFOHEADER)];<br /><br />// 计算调色板中实际颜色数量<br />m_nPaletteEntries = 1 &lt;&lt; m_pBIH-&gt;biBitCount;<br />if (m_pBIH-&gt;biBitCount &gt;8)<br />m_nPaletteEntries = 0;<br />else if (m_pBIH-&gt;biClrUsed != 0)<br />m_nPaletteEntries = m_pBIH-&gt;biClrUsed;<br /><br />// 为相应类成员变量赋image data指针<br />m_pDibBits = &amp;m_pDib[sizeof(BITMAPINFOHEADER) + m_nPaletteEntries * sizeof (RGBQUAD)];<br /><br />// delete先前的调色板<br />if (m_Palette.GetSafeHandle() != NULL)<br />m_Palette.DeleteObject();<br /><br />// 如果位图中存在调色板，创建LOGPALETTE 及CPalette<br />if (m_nPaletteEntries != 0)<br />{<br />LOGPALETTE *pLogPal = (LOGPALETTE*)new char[sizeof(LOGPALETTE) + m_nPaletteEntries *sizeof(PALETTEENTRY)];<br /><br />if (pLogPal != NULL)<br />{<br />pLogPal-&gt;palVersion = 0x300;<br />pLogPal-&gt;palNumEntries = m_nPaletteEntries;<br /><br />for (int i = 0; i &lt; m_nPaletteEntries; i++)<br />{<br />pLogPal-&gt;palPalEntry[i].peRed = m_pPalette[i].rgbRed;<br />pLogPal-&gt;palPalEntry[i].peGreen = m_pPalette[i].rgbGreen;<br />pLogPal-&gt;palPalEntry[i].peBlue = m_pPalette[i].rgbBlue;<br />}<br /><br />//创建CPalette并释放LOGPALETTE的内存<br />m_Palette.CreatePalette(pLogPal);<br />delete []pLogPal;<br />}<br />}<br /><br />return (TRUE);<br />}<br /><br />//函数功能：保存位图入BMP文件<br />BOOL CDib::Save(const char *pszFilename)<br />{<br />if (m_pDib == NULL)<br />return (FALSE);<br /><br />CFile cf;<br />if (!cf.Open(pszFilename, CFile::modeCreate | CFile::modeWrite))<br />return (FALSE);<br /><br />try<br />{<br />BITMAPFILEHEADER BFH;<br />memset(&amp;BFH, 0, sizeof(BITMAPFILEHEADER));<br />BFH.bfType = ’MB’;<br />BFH.bfSize = sizeof(BITMAPFILEHEADER) + m_dwDibSize;<br />BFH.bfOffBits = sizeof(BITMAPFILEHEADER) + <br />sizeof(BITMAPINFOHEADER) + m_nPaletteEntries *sizeof(RGBQUAD);<br /><br />cf.Write(&amp;BFH, sizeof(BITMAPFILEHEADER));<br />cf.Write(m_pDib, m_dwDibSize);<br />}<br />catch (CFileException *e)<br />{<br />e-&gt;Delete();<br />return (FALSE);<br />}<br />return (TRUE);<br />}</code><br />下面这个函数也非常重要，其功能为在pDC指向的CDC中绘制位图，起点坐标为(nX,nY)，绘制宽度和高度为nWidth、nHeight，最后一个参数是光栅模式：<br /><br /><code>BOOL CDib::Draw(CDC *pDC, int nX, int nY, int nWidth, int nHeight, int mode)<br />{<br />if (m_pDib == NULL)<br />return (FALSE);<br /><br />// 获取位图宽度和高度赋值<br />if (nWidth == - 1)<br />nWidth = m_pBIH-&gt;biWidth;<br />if (nHeight == - 1)<br />nHeight = m_pBIH-&gt;biHeight;<br /><br />// 绘制位图<br />StretchDIBits(pDC-&gt;m_hDC,
nX, nY, nWidth, nHeight, 0, 0, m_pBIH-&gt;biWidth, m_pBIH-&gt;biHeight,
m_pDibBits, (BITMAPINFO*)m_pBIH, BI_RGB, mode);<br /><br />return (TRUE);<br />}<br /><br />//函数功能：设置调色板<br />BOOL CDib::SetPalette(CDC *pDC)<br />{<br />if (m_pDib == NULL)<br />return (FALSE);<br /><br />// 检查当前是否有一个调色板句柄，对于大于256色的位图，为NULL<br />if (m_Palette.GetSafeHandle() == NULL)<br />return (TRUE);<br /><br />// 选择调色板，接着实施之，最后恢复老的调色板<br />CPalette *pOldPalette;<br />pOldPalette = pDC-&gt;SelectPalette(&amp;m_Palette, FALSE);<br />pDC-&gt;RealizePalette();<br />pDC-&gt;SelectPalette(pOldPalette, FALSE);<br /><br />return (TRUE);<br />}</code><br />从整个CDib类的代码中我们可以看出，DIB位图的显示需遵循如下步骤：<br /><br />（1）读取位图，本类中使用pDib = new unsigned char[dwDibSize]为位图中的信息分配内存，另一种方法是调用API函数CreateDIBSection，譬如：<br /><br /><code>m_hBitmap = ::CreateDIBSection(pDC-&gt;GetSafeHdc(), <br />(LPBITMAPINFO) m_lpBMPHdr, DIB_RGB_COLORS,<br />(LPVOID*) &amp;m_lpDIBits, NULL, 0);</code><br />m_hBitmap定义为：<br /><br /><code>HBITMAP m_hBitmap;</code><br />（2）根据读取的位图信息，计算出调色板大小，然后创建调色板；<br /><br />（3）调用CDib::SetPalette( CDC *pDC )设置调色板，需要用到CDC::SelectPalette及CDC::RealizePalette两个函数；<br /><br />（4）
调用CDib::Draw(CDC *pDC, int nX, int nY, int nWidth, int nHeight, int
mode)函数绘制位图。在此函数中，真正发挥显示位图作用的是对StretchDIBits
API函数的调用。StretchDIBits函数具有缩放功能，其最后一个参数也是光栅操作的模式。<br /><br />下面给出DIB位图的打开及显示并在其中加入天极网logo的函数源代码。"DIB位图"父菜单下"打开"子菜单的单击事件消息处理函数为（其功能为打开位图并显示之）： <br /><br /><code>void CBitMapExampleDlg::OnOpendibpic()<br />{<br />// 弹出文件对话框，让用户选择位图文件<br />CFileDialog fileDialog(TRUE, "*.BMP", NULL, NULL,"位图文件(*.BMP)|*.bmp;*.BMP|");<br />if (IDOK == fileDialog.DoModal())<br />{<br />// 加载位图并显示之<br />CDib dib;<br />if (dib.Load(fileDialog.GetPathName()))<br />{<br />CClientDC dc(this);<br />dib.SetPalette(&amp;dc);<br />dib.Draw(&amp;dc);<br />}<br />}<br />}</code><br />"DIB位图"父菜单下"标记"子菜单的单击事件消息处理函数为（其功能为给位图加上天极网logo）：<br /><br /><code>void CBitMapExampleDlg::OnMarkDibpic()<br />{<br />// 弹出文件对话框，让用户选择标记logo<br />CFileDialog fileDialog(TRUE, "*.BMP", NULL, NULL, "标记位图文件(*.BMP)|*.bmp;*.BMP|");<br />if (IDOK == fileDialog.DoModal())<br />{<br />// 加载标记logo位图并与目标位图相与<br />CDib dib;<br />if (dib.Load(fileDialog.GetPathName()))<br />{<br />CClientDC dc(this);<br />dib.SetPalette(&amp;dc);<br />dib.Draw(&amp;dc, 0, 0, - 1, - 1, SRCAND);<br />}<br />}<br />}</code><br />图4显示了DIB位图加载天极网logo后的效果，要好于图3中加天极网logo后的DDB位图。图4显示的是真彩色位图相互与的结果，而图3中的图像颜色被减少了。<br /><br /></code>
				</code>
		</p>
		<p align="center">
				<img src="http://cimg.163.com/catchpic/E/E6/E683A3F6D12F0BFB25E9FC01B42FAC52.jpg" alt="" border="0" />
		</p>
		<p align="center">
				<br />图4 在DIB位图中加入天极网logo<br /></p>
		<strong>
		</strong>
		<p>
				<strong>5. 结束语<br /></strong>
				<br />本文介绍了位图及调色板的概念，并讲解了DDB位图与DIB位图的区别。在此基础
上，本文以实例讲解了DDB位图和DIB位图的操作方式。DDB位图的处理相对比较简单，对于DIB位图，我们需要定义一个MFC所没有的新类CDib，
它屏蔽位图信息的读取及调色板创建的技术细节，应用程序可以方便地使用之。<br /><br />本文中的所有程序在Visual C++6.0及Windows XP平台上调试通过。</p>
<img src ="http://www.cppblog.com/swo2006/aggbug/10980.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/swo2006/" target="_blank">swo</a> 2006-08-08 13:00 <a href="http://www.cppblog.com/swo2006/articles/10980.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>