<?xml version="1.0" encoding="utf-8" ?>















<feed version="0.3" xmlns="http://purl.org/atom/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xml:lang="zh_CN">
<title><![CDATA[wqj1212'职业博客]]></title>
<link rel="alternate" type="text/html" href="http://wqj1212.blog.bokee.net"/>
<modified>2008-01-25T10-48-39 CST</modified>
<tagline type="text/html" mode="escaped"><![CDATA[图像处理、机器视觉、机器人、运动控制学习交流！——寻找伯乐，为实现理想而奋斗！]]></tagline>
<generator url="http://www.bokee.net/" version="2.0">bokee.net</generator>
<copyright>Copyright (c) 2005,  wqj1212</copyright>


<entry>
<title>directshow与OPENCV</title>
<link rel="alternate" type="text/html" href="http://www.bokee.net/blogmodule/weblogcomment_viewEntry/1387675.html"/>
<issued>2008-01-25T10-48-39 CST</issued> 
<created>2008-01-25T10-48-39 CST</created>
<modified>2008-01-25T10-48-39Z</modified>
<id>tag:wqj1212.blogchina.com,2005://1387675</id>
<author>
<name>wqj1212</name>
<url>http://www.bokee.net/blogmodule/weblogcomment_index/wqj1212.html</url>
</author>
<dc:subject>OPENCV</dc:subject>
<content type="text/html" mode="escaped" xml:lang="zh_CN" xml:base="http://www.bokee.net"> 
<![CDATA[<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>]]>
</content>
</entry>

<entry>
<title>Visual C++中DDB与DIB位图编程全攻略</title>
<link rel="alternate" type="text/html" href="http://www.bokee.net/blogmodule/weblogcomment_viewEntry/1374409.html"/>
<issued>2008-01-21T10-16-26 CST</issued> 
<created>2008-01-21T10-16-26 CST</created>
<modified>2008-01-21T10-16-26Z</modified>
<id>tag:wqj1212.blogchina.com,2005://1374409</id>
<author>
<name>wqj1212</name>
<url>http://www.bokee.net/blogmodule/weblogcomment_index/wqj1212.html</url>
</author>
<dc:subject>VC++学习</dc:subject>
<content type="text/html" mode="escaped" xml:lang="zh_CN" xml:base="http://www.bokee.net"> 
<![CDATA[.2位图的显示<br />　 <br />　　Visual C++ MFC中没有提供一个专门的类来处理DIB位图，因此，为了方便地使用位图文件，我们有必要派生一个CDib类。类的源代码如下：<br /><br />　　(1) CDib类的声明<br /><br />
<table bordercolor="#cccccc" width="90%" align="center" bgcolor="#e3e3e3" border="1">
    <tbody>
        <tr>
            <td>// DIB.h：类CDib声明头文件<br />#ifndef __DIB_H__<br />#define __DIB_H__<br />#include &lt;wingdi.h&gt;<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 /></td>
        </tr>
    </tbody>
</table>
<br />　　(2) CDib类的实现<br /><br />
<table bordercolor="#cccccc" width="90%" align="center" bgcolor="#e3e3e3" border="1">
    <tbody>
        <tr>
            <td>// DIB.cpp：类CDib实现文件<br />#include &quot;stdafx.h&quot;<br />#include &quot;DIB.h&quot;<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 />}</td>
        </tr>
    </tbody>
</table>
<br />　　下面这个函数非常重要，其功能为加载位图，类似于CBitmap类的LoadBitmap函数：<br /><br />
<table bordercolor="#cccccc" width="90%" align="center" bgcolor="#e3e3e3" border="1">
    <tbody>
        <tr>
            <td>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 != &rsquo;MB&rsquo; || 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 = 0<a class="bluekey" href="http://product.yesky.com/product/157/157071/" target="_blank">x3</a>00;<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 = &rsquo;MB&rsquo;;<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 />}</td>
        </tr>
    </tbody>
</table>
<br />　　下面这个函数也非常重要，其功能为在pDC指向的CDC中绘制位图，起点坐标为(nX,nY)，绘制宽度和高度为nWidth、nHeight，最后一个参数是光栅模式：<br /><br />
<table bordercolor="#cccccc" width="90%" align="center" bgcolor="#e3e3e3" border="1">
    <tbody>
        <tr>
            <td>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 />}</td>
        </tr>
    </tbody>
</table>
<br />　　从整个CDib类的代码中我们可以看出，DIB位图的显示需遵循如下步骤：<br /><br />　　（1）读取位图，本类中使用pDib = new unsigned char[dwDibSize]为位图中的信息分配内存，另一种方法是调用API函数CreateDIBSection，譬如：<br /><br />
<table bordercolor="#cccccc" width="90%" align="center" bgcolor="#e3e3e3" border="1">
    <tbody>
        <tr>
            <td>m_hBitmap = ::CreateDIBSection(pDC-&gt;GetSafeHdc(), <br />(LPBITMAPINFO) m_lpBMPHdr, DIB_RGB_COLORS,<br />(LPVOID*) &amp;m_lpDIBits, NULL, 0);</td>
        </tr>
    </tbody>
</table>
<br />　　m_hBitmap定义为：<br /><br />
<table bordercolor="#cccccc" width="90%" align="center" bgcolor="#e3e3e3" border="1">
    <tbody>
        <tr>
            <td>HBITMAP m_hBitmap;</td>
        </tr>
    </tbody>
</table>
<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的函数源代码。&quot;DIB位图&quot;父菜单下&quot;打开&quot;子菜单的单击事件消息处理函数为（其功能为打开位图并显示之）： <br /><br />
<table bordercolor="#cccccc" width="90%" align="center" bgcolor="#e3e3e3" border="1">
    <tbody>
        <tr>
            <td>void CBitMapExampleDlg::OnOpendibpic()<br />{<br />　// 弹出文件对话框，让用户选择位图文件<br />　CFileDialog fileDialog(TRUE, &quot;*.BMP&quot;, NULL, NULL,&quot;位图文件(*.BMP)|*.bmp;*.BMP|&quot;);<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 />}</td>
        </tr>
    </tbody>
</table>
<br />　　&quot;DIB位图&quot;父菜单下&quot;标记&quot;子菜单的单击事件消息处理函数为（其功能为给位图加上天极网logo）：<br /><br />
<table bordercolor="#cccccc" width="90%" align="center" bgcolor="#e3e3e3" border="1">
    <tbody>
        <tr>
            <td>void CBitMapExampleDlg::OnMarkDibpic()<br />{<br />　// 弹出文件对话框，让用户选择标记logo<br />　CFileDialog fileDialog(TRUE, &quot;*.BMP&quot;, NULL, NULL, &quot;标记位图文件(*.BMP)|*.bmp;*.BMP|&quot;);<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 />}</td>
        </tr>
    </tbody>
</table>
<br />　　图4显示了DIB位图加载天极网logo后的效果，要好于图3中加天极网logo后的DDB位图。图4显示的是真彩色位图相互与的结果，而图3中的图像颜色被减少了。<br /><br />
<table width="90%" align="center" border="0">
    <tbody>
        <tr>
            <td>
            <div align="center"><img src="http://dev.yesky.com/imagelist/05/10/3109a09py627.jpg" border="0" alt="" /><br />图4 在DIB位图中加入天极网logo</div>
            </td>
        </tr>
    </tbody>
</table>
<br />　　<strong>5. 结束语<br /></strong><br />　　本文介绍了位图及调色板的概念，并讲解了DDB位图与DIB位图的区别。在此基础上，本文以实例讲解了DDB位图和DIB位图的操作方式。DDB位图的处理相对比较简单，对于DIB位图，我们需要定义一个MFC所没有的新类CDib，它屏蔽位图信息的读取及调色板创建的技术细节，应用程序可以方便地使用之。<br /><br />　　本文中的所有程序在Visual C++6.0及Windows XP平台上调试通过。
<div id="numpage"><a href="http://dev.yesky.com/72/2150572_3.shtml" target="_self"><span></span></a></div>]]>
</content>
</entry>

<entry>
<title>获取位图尺寸</title>
<link rel="alternate" type="text/html" href="http://www.bokee.net/blogmodule/weblogcomment_viewEntry/1367558.html"/>
<issued>2008-01-18T17-13-03 CST</issued> 
<created>2008-01-18T17-13-03 CST</created>
<modified>2008-01-18T17-13-03Z</modified>
<id>tag:wqj1212.blogchina.com,2005://1367558</id>
<author>
<name>wqj1212</name>
<url>http://www.bokee.net/blogmodule/weblogcomment_index/wqj1212.html</url>
</author>
<dc:subject>VC++学习</dc:subject>
<content type="text/html" mode="escaped" xml:lang="zh_CN" xml:base="http://www.bokee.net"> 
<![CDATA[<br />从 CBitmap类对象中获取位图尺寸我们可用GetBitmap()函数 。&nbsp;
<div style="BORDER-RIGHT: windowtext 0.5pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 0.5pt solid; PADDING-LEFT: 5.4pt; BACKGROUND: #e6e6e6; PADDING-BOTTOM: 4px; BORDER-LEFT: windowtext 0.5pt solid; WIDTH: 95%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: windowtext 0.5pt solid">
<div><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" /><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;变量bitmap是一个CBitmap类对象</span><span style="COLOR: #008000"><br /><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #000000">BITMAP&nbsp;bm;<br /><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" />bitmap.GetBitmap(&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">bm&nbsp;);<br /><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" />bmWidth&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;bm.bmWidth;<br /><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" />bmHeight&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;bm.bmHeight;</span></div>
</div>
<br />如果你有一个 HBITMAP句柄，你可以将它附加到一个CBitmap类对象上，再用上述方法<br />获取尺寸<br />
<div style="BORDER-RIGHT: windowtext 0.5pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 0.5pt solid; PADDING-LEFT: 5.4pt; BACKGROUND: #e6e6e6; PADDING-BOTTOM: 4px; BORDER-LEFT: windowtext 0.5pt solid; WIDTH: 95%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: windowtext 0.5pt solid">
<div><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" /><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;变量hBmp是一个HBITMAP句柄</span><span style="COLOR: #008000"><br /><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #000000">BITMAP&nbsp;bm;<br /><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" />::GetObject(&nbsp;hBmp,&nbsp;</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(&nbsp;bm&nbsp;),&nbsp;</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">bm&nbsp;);<br /><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" />bmWidth&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;bm.bmWidth;<br /><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" />bmHeight&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;bm.bmHeight;</span></div>
</div>
<br />从BMP位图文件中获取位图尺寸可用下述方法。<br />
<div style="BORDER-RIGHT: windowtext 0.5pt solid; PADDING-RIGHT: 5.4pt; BORDER-TOP: windowtext 0.5pt solid; PADDING-LEFT: 5.4pt; BACKGROUND: #e6e6e6; PADDING-BOTTOM: 4px; BORDER-LEFT: windowtext 0.5pt solid; WIDTH: 95%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: windowtext 0.5pt solid">
<div><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" /><span style="COLOR: #000000">CFile&nbsp;file;<br /><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;sBMPFileName是BMP位图文件名</span><span style="COLOR: #008000"><br /><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">(&nbsp;</span><span style="COLOR: #000000">!</span><span style="COLOR: #000000">file.Open(&nbsp;sBMPFileName,&nbsp;CFile::modeRead)&nbsp;)<br /><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;;<br /><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" /><br /><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" />BITMAPFILEHEADER&nbsp;bmfHeader;<br /><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" /><br /><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;读文件头</span><span style="COLOR: #008000"><br /><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(file.Read((LPSTR)</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">bmfHeader,&nbsp;</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(bmfHeader))<br /><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(bmfHeader))<br /><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;;<br /><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" /><br /><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;确定文件类型标记&rsquo;BM&rsquo;</span><span style="COLOR: #008000"><br /><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(bmfHeader.bfType&nbsp;</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">&nbsp;((WORD)&nbsp;(&rsquo;M&rsquo;&nbsp;</span><span style="COLOR: #000000">&lt;&lt;</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #000000">8</span><span style="COLOR: #000000">)&nbsp;</span><span style="COLOR: #000000">|</span><span style="COLOR: #000000">&nbsp;&rsquo;B&rsquo;))<br /><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;;<br /><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" /><br /><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" />BITMAPINFOHEADER&nbsp;bmiHeader;<br /><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000">&nbsp;(file.Read((LPSTR)</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">bmiHeader,&nbsp;</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(bmiHeader))<br /><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #000000">!=</span><span style="COLOR: #000000">&nbsp;</span><span style="COLOR: #0000ff">sizeof</span><span style="COLOR: #000000">(bmiHeader))<br /><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="COLOR: #0000ff">return</span><span style="COLOR: #000000">&nbsp;;<br /><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" /><br /><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;bmWidth&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;bmiHeader.biWidth;<br /><img alt="" src="http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif" align="top" /></span><span style="COLOR: #0000ff">int</span><span style="COLOR: #000000">&nbsp;bmHeight&nbsp;</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000">&nbsp;bmiHeader.biHeight;</span></div>
</div>
<br /><br />]]>
</content>
</entry>

<entry>
<title>利用VC＋＋开发ASP图像处理组件</title>
<link rel="alternate" type="text/html" href="http://www.bokee.net/blogmodule/weblogcomment_viewEntry/1367446.html"/>
<issued>2008-01-18T16-38-27 CST</issued> 
<created>2008-01-18T16-38-27 CST</created>
<modified>2008-01-18T16-38-25Z</modified>
<id>tag:wqj1212.blogchina.com,2005://1367446</id>
<author>
<name>wqj1212</name>
<url>http://www.bokee.net/blogmodule/weblogcomment_index/wqj1212.html</url>
</author>
<dc:subject>VC++学习</dc:subject>
<content type="text/html" mode="escaped" xml:lang="zh_CN" xml:base="http://www.bokee.net"> 
<![CDATA[<p align="center"><strong>利用VC＋＋开发ASP图像处理组件（一）<br /></strong><br /></p>
<p><a href="http://www.vckbase.com/code/downcode.asp?id=2362" target="_blank">下载源代码</a><br /><br />一、VC++中的DC环境及GUI有关的各种对象<br />　　在Windows中有各种图形用户界面GUI(Graphics User Interface)对象，当我们在进行绘图时就需要利用这些对象。而各种对象都拥有各种属性，下面首先介绍几种GUI对象和拥有的属性。<br /><br />(一)、GUI有关的各种对象<br />　　在Windows中有各种图形用户界面GUI(Graphics User Interface)对象，当我们在进行绘图时就需要利用这些对象。而各种对象都拥有各种属性，下面首先介绍几种GUI对象和拥有的属性。</p>
<ul>
    <li>字体对象CFont<br />字体对象CFont用于输出文字时选用不同风格和大小的字体。可选择的风格包括：是否为斜体，是否为粗体，字体名称，是否有下划线等。 </li>
    <li>刷子CBrush对象<br />刷子CBrush对象决定填充区域时所采用的颜色或模板。对于一个固定色的刷子来讲它的属性为颜色，是否采用网格和网格的类型如水平的，垂直的，交叉的等。也可以利用8*8的位图来创建一个自定义模板的刷子，在使用这种刷子填充时系统会利用位图逐步填充区域。 </li>
    <li>画笔CPen<br />画笔CPen对象在画点和画线时有用。它的属性包括颜色，宽度，线的风格，如虚线，实线，点划线等。 </li>
    <li>位图CBitmap对象<br />位图CBitmap对象可以包含一幅图像，可以保存在资源中。 </li>
    <li>CPalette调色板<br />CPalette调色板是一种颜色映射接口，它允许应用程序在不影响其他应用程序的前提下，可以充分利用输出设备的颜色描绘能力。 </li>
</ul>
<p>　　此外系统中还拥有一些库存GUI对象，你可以利用CDC::SelectStockObject(SelectStockObject( int nIndex )选入这些对象，它们包括一些固定颜色的刷子，画笔和一些基本字体。 如：</p>
<ul>
    <li>BLACK_BRUSH 黑色刷子 </li>
    <li>NULL_BRUSH 空刷子 </li>
    <li>WHITE_PEN 白色画笔 </li>
    <li>DEVICE_DEFAULT_FONT 默认字体 </li>
</ul>
<p>　　在Windows中使用GUI对象必须遵守一定的规则。首先需要创建一个合法的对象，不同的对象创建方法不同。然后需要将该GUI对象选入DC中，同时保存DC中原来的GUI对象。如果选入一个非法的对象将会引起异常。在使用完后应该恢复原来的对象，这一点特别重要，如果保存一个临时对象在DC中，而在临时对象被销毁后可能引起异常。有一点必须注意，每一个对象在重新创建前必须销毁，下面的代码演示了这一种安全的使用方法： </p>
<pre>OnDraw(CDC* pDC)
{
	a) CPen pen1,pen2;
	b) pen1.CreatePen(PS_SOLID,2,RGB(128,128,128));//创建画笔对象一
	c) pen2.CreatePen(PS_SOLID,2,RGB(128,128,0));//创建画笔对象二
	d) CPen* pOldPen=(CPen*)pDC-&gt;SelectObject(&amp;pen1);//选择对象进DC
	e) drawWithPen1...
	f)	(CPen*)pDC-&gt;SelectObject(&amp;pen2);//选择对象进DC
	g) drawWithPen2...
	h)	pen1.DeleteObject();//再次创建前先销毁
	i) pen1.CreatePen(PS_SOLID,2,RGB(0,0,0));//再次创建对象
	j) (CPen*)pDC-&gt;SelectObject(&amp;pen1);//选择对象进DC
	k) drawWithPen1...
	l)	pDC-&gt;SelectObject(pOldPen);//恢复
}      </pre>
　　OnDraw(CDC* pDC) 函数是VC中最常见的图形输出刷新函数，参数pDC 为CDC类的一个指针，我们通过它进行画图操作。<br />　　代码a行定义CPen 类的两个画笔对象pen1,pen2；分别在行b,c 调用CPen 类成员函数CreatePen 创建两个实心画笔, 其颜色RGB值分别为RGB(128,128,128), RGB(128,128,0)。行d 将新创建的画笔pen1选入当前设备上下文DC环境并将旧画笔保存在pOldPen里，这样在e行输出的图形或文本线条将以pen1的属性填充。f, g 行选入画笔二并输出。i,j 行销毁画笔一并且创建RGB(0,0,0)色的画笔，k行输出。最后一行l行将旧画笔选入当前DC环境，输出完毕。字体对象，刷子对象及位图对象的使用方法同上，具体使用将在下面的实例中描述。<br />　　在绘图时都需要一个DC对象，DC（Device Context设备环境）对象是一个抽象的作图环境，可能是对应屏幕，也可能是对应打印机或其它。这个环境是设备无关的，所以在对不同的设备输出时只需要使用不同的设备环境就行了，而作图方式可以完全不变。<br /><br />(二)、DC环境下输出文本<br />　　在MFC里有一个设备环境类CDC封装了有关对物理设备的输出。CDC是设备环境类的基类直接由CObject派生。是图形设备接口的关键元素，它代表了物理设备。每一个C++设备环境对象都有相对应Windows设备环境，并通过一个32位类型的HDC句柄来标识。CDC类的虚拟性使我们可以很容易的做到编写同时适用于多种设备的代码。例如OnDraw函数的pDC-&gt;TextOut(0,0,&quot;Hello&quot;);既可以适用于显示器、还可以适用于打印预览和打印，只需要在CView::OnDraw函数的pDC参数指向不同的对象类。<br />　　CClientDC和CWindowDC是显示设备环境类，都是由CDC派生而来，区别在于CClientDC是窗口的客户区不包括边框、标题栏和菜单栏，（0，0）指客户区域的左上角。CWindowDC的（0，0）指整个屏幕的左上角，这意味着我们可以在显示器的任意地方绘图，包括窗口边框、标题栏和菜单栏等等。CWindowDC一般应用在框架窗口，而不是视图窗口。<br />　　CDC对象被创建后一定要在合适的时候将它删除掉，如果忘记了删除设备环境对象则会造成内存丢失。下面程序段实现在DC环境下输出文本。<br />
<pre>long CImg::OutImgFromText(LPCTSTR vFileName, 
LPCTSTR lpText, 
LPCTSTR lpBgImg, 
long lCSet,
LPCTSTR lpFont,
long lWidth, 
long lHeight,
long lLeft, 
long lTop, 
long llfHeight, 
long lWeight,
long l3D)
{
i. m_nWidth = lWidth;
ii. m_nHeight = lHeight;

iii. if((m_nWidth % 8) != 0)
1. m_nWidth = ((int)(m_nWidth/8) + 1) * 8;

iv. if(m_nWidth &lt; 3 * lLeft)
1. m_nWidth = 3 * lLeft;

v. if(m_nHeight &lt; 3 * lTop)
1. m_nHeight = 3 * lTop;

vi. int nFHeight = llfHeight;
vii. if(0 == nFHeight)
1. nFHeight = 1;

viii. int nRealClientWidth = (m_nWidth - 2 * lLeft);

ix. HDC hDC;
x. hDC = CreateCompatibleDC(NULL);

xi. LOGFONT lf;
xii. memset(&amp;lf,0,sizeof(lf));
xiii. lf.lfCharSet = GB2312_CHARSET;
xiv. lf.lfHeight = nFHeight;
xv. lstrcpy(lf.lfFaceName, lpFont); 
xvi. lf.lfPitchAndFamily = 8;
xvii. lf.lfWeight = lWeight;

xviii. HFONT hFont = CreateFontIndirect(&amp;lf);
1. HFONT hOldFont = (HFONT)SelectObject(hDC, hFont); //选入字体


xix. CComBSTR bstrText(lpText);

xx. RECT rectClient = {lLeft, lTop, m_nWidth - lLeft, m_nHeight - lTop};

xxi. ::DrawText(
1. hDC,
2. bstrText.m_str, 
3. bstrText.Length(),
4. &amp;rectClient, 
5. DT_WORDBREAK|DT_LEFT|DT_CALCRECT
6. ); //计算输出距形

xxii. int nRealHeight = rectClient.bottom + lTop;
xxiii. if(m_nHeight &lt; nRealHeight)
1. m_nHeight = nRealHeight;
xxiv. else
1. rectClient.bottom = m_nHeight - lTop;

xxv. HBITMAP hBitmap;
xxvi. hBitmap = CreateDiscardableBitmap(hDC, m_nWidth, m_nHeight);

xxvii. SelectObject(hDC, hBitmap);

xxviii. //---------------------------------
xxix. HBRUSH hBBg = CreateSolidBrush(RGB(255,255,255));
xxx. RECT rectFull = {0, 0, m_nWidth, m_nHeight};
xxxi. FillRect(hDC, &amp;rectFull, hBBg); 

xxxii. if(l3D &gt; 0)
xxxiii. {
1. //SetBkColor(hDC, RGB(200,193,193));
2. SetTextColor(hDC, ::GetSysColor(COLOR_3DDKSHADOW)); 
3. SetBkMode(hDC, OPAQUE);
xxxiv. }
xxxv. else
xxxvi. {
1. SetBkColor(hDC, RGB(255,255,255));
2. SetTextColor(hDC, RGB(0,0,0));
3. SetBkMode(hDC, TRANSPARENT);
xxxvii. }

xxxviii. ::DrawText(
1. hDC,
2. bstrText.m_str, 
3. bstrText.Length(),
4. &amp;rectClient, 
5. DT_WORDBREAK
6. ); //输出

xxxix. if(l3D &gt; 0)
xl. {
1. SetTextColor(hDC, ::GetSysColor(COLOR_3DHILIGHT)); 
2. SetBkMode(hDC, TRANSPARENT);

3. rectClient.left = rectClient.left + l3D;
4. rectClient.top = rectClient.top - 1;
5. rectClient.right = rectClient.right + l3D;
6. rectClient.bottom = rectClient.bottom - 1;

7. ::DrawText(
a) hDC,
b) lpText, 
c) wcslen(lpText),
d) &amp;rectClient, 
e) DT_WORDBREAK);
xli. }

xlii. SelectObject(hDC, hOldFont);

xliii. DeleteObject(hFont);
xliv. DeleteObject(hBBg);

xlv. SaveDCBmp(hDC, hBitmap, vFileName); 
xlvi. //SaveDCJPG(hDC, hBitmap, vFileName); 

xlvii. DeleteObject(hBitmap);
xlviii. ::ReleaseDC(NULL, hDC); 

xlix. return 0;
}		</pre>
此函数功能：通过输入特定长度的文本，输出图像到指定文件<br />参数说明：<br />vFileName: 图像保存文件路径<br />lpText: 图像输出文本<br />lpBgImg: 图像背景路径<br />lCSet: 字符集<br />lpFont: 字体名称<br />lWidth: 图像输出宽度<br />lHeight: 图像输出高度<br />lLeft: 图像输出左边距，与右边距相同<br />lTop: 图像输出上边距，与下边距相同<br />llfHeight: 文本输出字体高度，字体宽度随高度等比例变化<br />lWeight: 文本重量<br />l3D: 三D效果,值为0时无三D效果，大于0时其值为字体偏移量<br /><br />程序i. 至 viii. 行对输入参数合法性进行检查及究正。<br />行ix. ，x. 定义及创建与指定设备兼容的设备上下文句柄hDC。<br />行xi. 至 xviii.1 行定义LOGFONT 逻辑字体结构并填充。通过CreateFontIndirect(&amp;lf) 创建字体并调用SelectObject(hDC, hFont)将创建字体选入设备上下文，原字体句柄保存在hOldFont里。<br />xix. 至 xxiv. 行取得输入文本长度，在当前字体环境下调用DrawText函数计算输出矩形，并将其矩形保存在rectClient里，以便调整DC输出矩形大小。<br />行xxvi. 利用上面计算出的长宽创建位图句柄，行xxvii.将其选入设备上下文，准备工作完毕，绘图工作正式开始。<br />在此函数中，画笔及刷子我们使用系统默认设置，不再重复申请。<br />行xxxii.判断三D偏移量是否大于零，如果不为零，输出三D效果。<br />行xxxviii.在新矩形下输入文本。如果有三D输出请求，将矩形偏移l3D个像素，再次输出文本，以显示三D效果。<br />xlii. 行选入旧字体。<br />xliii. 行以后删除对象保存位图及恢复现场。保存位图功能SaveDCBmp将在下节讨论。<br /><br />二、位图文件<br /><br />(一)、位图文件结构<br />　　位图文件由三部分组成：文件头 + 位图信息 + 位图像素数据<br /><br />1、位图文件头<br />　　位图文件头主要用于识别位图文件。以下是位图文件头结构的定义：
<pre>typedef struct tagBITMAPFILEHEADER { 
WORD bfType; 
DWORD bfSize; 
WORD bfReserved1; 
WORD bfReserved2; 
DWORD bfOffBits; 
} BITMAPFILEHEADER;</pre>
<p>　　其中的bfType值应该是&ldquo;BM&rdquo;（0x4d42），标志该文件是位图文件。bfSize的值是位图文件的大小。bfReserved1, bfReserved2 为保留字，值为0。bfOffBits为位图文件大小与DIB（设备无关的位图 Device-indepentent bitmap）位图数据的大小之差。如：</p>
<pre>BITMAPFILEHEADER bmfHdr;
bmfHdr.bfType = 0x4D42; // &quot;BM&quot; 
dwDIBSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + dwPaletteSize + dwBmBitsSize; 
bmfHdr.bfSize = dwDIBSize; 
bmfHdr.bfReserved1 = 0; 
bmfHdr.bfReserved2 = 0; 
bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER) + dwPaletteSize;</pre>
<p>2、位图信息<br />　　位图信息中所记录的值用于分配内存，设置调色板信息，读取像素值等。以下是位图信息结构的定义：</p>
<pre>typedef struct tagBITMAPINFO {
BITMAPINFOHEADER bmiHeader;
RGBQUAD bmiColors[1];
} BITMAPINFO;</pre>
<p>可见位图信息也是由两部分组成的：位图信息头 + 颜色表 <br /><br />2.1、位图信息头<br />　　位图信息头包含了单个像素所用字节数以及描述颜色的格式，此外还包括位图的宽度、高度、目标设备的位平面数、图像的压缩格式。以下是位图信息头结构的定义： </p>
<pre>typedef struct tagBITMAPINFOHEADER{ 
DWORD biSize; 
LONG biWidth; 
LONG biHeight; 
WORD biPlanes; 
WORD biBitCount 
DWORD biCompression; 
DWORD biSizeImage; 
LONG biXPelsPerMeter; 
LONG biYPelsPerMeter; 
DWORD biClrUsed; 
DWORD biClrImportant; 
} BITMAPINFOHEADER; </pre>
<p>biSize 结构BITMAPINFOHEADER的字节数，即sizeof(BITMAPINFOHEADER)<br />biWidth 以像素为单位的图像宽度<br />biHeight 以像素为单位的图像长度<br />biplanes 目标设备的位平面数 <br />biBitCount 每个像素的位数 <br />对于每个像素的位数，分别有一下意义：<br />0，用在JPEG格式中<br />1，单色图，调色板中含有两种颜色，也就是我们通常说的黑白图片<br />4，16色图<br />8，256色图，通常说的灰度图<br />16，64K图，一般没有调色板，图像数据中每两个字节表示一个像素，5个或6个位表示一个RGB分量<br />24，16M真彩色图，一般没有调色板，图像数据中每3个字节表示一个像素，每个字节表示一个RGB分量<br />32，4G真彩色，一般没有调色板，每4个字节表示一个像素，相对24位真彩图而言，加入了一个透明度，即RGBA模式<br />biCompression 图像的压缩格式（这个值几乎总是为0） <br />biSizeImage 以字节为单位的图像数据的大小（对BI_RGB压缩方式而言） <br />biXPelsPermeter 水平方向上的每米的像素个数 <br />biYpelsPerMeter 垂直方向上的每米的像素个数 <br />biClrused 调色板中实际使用的颜色数,这个值通常为0<br />biClrImportant 现实位图时必须的颜色数, 这个值通常为0，表示所有的颜色都是必需的<br /><br />2.2、颜色表<br />　　颜色表一般是针对16位以下的图像而设置的，对于16位和16位以上的图像，由于其位图像素数据中直接对对应像素的RGB(A)颜色进行描述，因而省却了调色板。而对于16位以下的图像，由于其位图像素数据中记录的只是调色板索引值，因而需要根据这个索引到调色板去取得相应的RGB(A)颜色。颜色表的作用就是创建调色板。颜色表是由颜色表项组成的，颜色表项结构的定义如下：</p>
<pre>typedef struct tagRGBQUAD { // rgbq 
BYTE rgbBlue; 
BYTE rgbGreen; 
BYTE rgbRed; 
BYTE rgbReserved; 
} RGBQUAD;</pre>
<p>rgbBlue 蓝色的强度<br />rgbGreen 绿色的强度<br />rgbRed 红色的强度<br />rgbReserved 保留字，为0<br /><br />其中需要注意的问题是，RGBQUAD结构中的颜色顺序是BGR，而不是平常的RGB。<br /><br />3、位图数据<br />　　最后，在位图文件头、位图信息头、位图颜色表之后，便是位图的主体部分：位图数据。根据不同的位图，位图数据所占据的字节数也是不同的，比如，对于8位位图，每个字节代表了一个像素，对于16位位图，每两个字节代表了一个像素，对于24位位图，每三个字节代表了一个像素，对于32位位图，每四个字节代表了一个像素。 <br /><br />(二)、存储区域DC到位图文件<br />　　认识了位图文件的结构以后，对特定位图文件进行操作就显得简单了。我们通过创建特定的画笔，刷子及位图对象，在DC 环境下进行绘图后，就要将保存在DC 里的图像存储到位图文件中，以便使用及输出到其他媒体。下面代码实现将设图上下文图形保存为位图文件。<br /></p>
<pre>BOOL CImg::SaveDCBmp(HDC hDC, HBITMAP hBitmap, LPCTSTR lpFileName)
{
	//当前分辨率下每象素所占字节数
	int iBits;
	//位图中每象素所占字节数
	WORD wBitCount;
	//定义调色板大小， 位图中像素字节大小 ，位图文件大小 ， 写入文件字节数 
	DWORD dwPaletteSize=0, dwBmBitsSize=0, dwDIBSize=0, dwWritten=0; 
	//位图属性结构 
	BITMAP Bitmap; 
	//位图文件头结构
	BITMAPFILEHEADER bmfHdr; 
	//位图信息头结构 
	BITMAPINFOHEADER bi; 
	//指向位图信息头结构 
	LPBITMAPINFOHEADER lpbi; 
	//定义文件，分配内存句柄，调色板句柄 
	HANDLE fh, hDib, hPal,hOldPal=NULL; 
	
	//计算位图文件每个像素所占字节数 
	iBits = GetDeviceCaps(hDC, BITSPIXEL) * GetDeviceCaps(hDC, PLANES); 
	
	if (iBits &lt;= 1) wBitCount = 1; 
	else if (iBits &lt;= 4) wBitCount = 4; 
	else if (iBits &lt;= 8) wBitCount = 8; 
	else wBitCount = 24; 
	
	//wBitCount = 4;
	
	GetObject(hBitmap, sizeof(Bitmap), (LPSTR)&amp;Bitmap);
	bi.biSize = sizeof(BITMAPINFOHEADER);
	bi.biWidth = Bitmap.bmWidth;
	bi.biHeight = Bitmap.bmHeight;
	bi.biPlanes = 1;
	bi.biBitCount = wBitCount;
	bi.biCompression = BI_RGB;
	bi.biSizeImage = 0;
	bi.biXPelsPerMeter = 0;
	bi.biYPelsPerMeter = 0;
	bi.biClrImportant = 0;
	bi.biClrUsed = 0;
	
	dwBmBitsSize = ((Bitmap.bmWidth * wBitCount + 31) / 32) * 4 * Bitmap.bmHeight;
	
	//为位图内容分配内存 
	hDib = GlobalAlloc(GHND,dwBmBitsSize + dwPaletteSize + sizeof(BITMAPINFOHEADER)); 
	lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDib); 
	*lpbi = bi; 
	
	// 处理调色板 
	hPal = GetStockObject(DEFAULT_PALETTE); 
	if (hPal) 
	{ 
		hOldPal = ::SelectPalette(hDC, (HPALETTE)hPal, FALSE); 
	}
	
	// 获取该调色板下新的像素值 
	GetDIBits(hDC, hBitmap, 0, (UINT) Bitmap.bmHeight, (LPSTR)lpbi + sizeof(BITMAPINFOHEADER) 
		+dwPaletteSize, (BITMAPINFO *)lpbi, DIB_RGB_COLORS); 
	
	//恢复调色板 
	if (hOldPal) 
	{ 
		::SelectPalette(hDC, (HPALETTE)hOldPal, TRUE); 
		RealizePalette(hDC); 
	} 
	
	//创建位图文件 
	fh = CreateFile(lpFileName, GENERIC_WRITE,0, NULL, CREATE_ALWAYS, 
		FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); 
	
	if (fh == INVALID_HANDLE_VALUE) return FALSE; 
	
	// 设置位图文件头 
	bmfHdr.bfType = 0x4D42; // &quot;BM&quot; 
	dwDIBSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + dwPaletteSize + dwBmBitsSize; 
	bmfHdr.bfSize = dwDIBSize; 
	bmfHdr.bfReserved1 = 0; 
	bmfHdr.bfReserved2 = 0; 
	bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER) + dwPaletteSize; 
	// 写入位图文件头 
	WriteFile(fh, (LPSTR)&amp;bmfHdr, sizeof(BITMAPFILEHEADER), &amp;dwWritten, NULL); 
	// 写入位图文件其余内容 
	WriteFile(fh, (LPSTR)lpbi, dwDIBSize, &amp;dwWritten, NULL); 
	//清除 
	GlobalUnlock(hDib); 
	GlobalFree(hDib); 
	CloseHandle(fh); 
	
	return TRUE;
}		</pre>
保存位图文件前通过GetObject函数取得位图长度， 通过GetDIBits取得位图图像扫描数据，填充BITMAPFILEHEADER(位图文件头结构); BITMAPINFOHEADER (位图信息头结构); 然后写入位图文件头：
<p>&nbsp;</p>
<pre>WriteFile(fh, (LPSTR)&amp;bmfHdr, sizeof(BITMAPFILEHEADER), &amp;dwWritten, NULL); </pre>
<p>写入位图文件其余内容：</p>
<pre>WriteFile(fh, (LPSTR)lpbi, dwDIBSize, &amp;dwWritten, NULL); </pre>
<p>以 文件头 + 位图信息 + 位图像素数据 的顺序进行存储。<br /><br /></p>]]>
</content>
</entry>

<entry>
<title>在外面改变动态链接库里的变量</title>
<link rel="alternate" type="text/html" href="http://www.bokee.net/blogmodule/weblogcomment_viewEntry/1366239.html"/>
<issued>2008-01-18T11-10-58 CST</issued> 
<created>2008-01-18T11-10-58 CST</created>
<modified>2008-01-18T11-10-56Z</modified>
<id>tag:wqj1212.blogchina.com,2005://1366239</id>
<author>
<name>wqj1212</name>
<url>http://www.bokee.net/blogmodule/weblogcomment_index/wqj1212.html</url>
</author>
<dc:subject>VC++学习</dc:subject>
<content type="text/html" mode="escaped" xml:lang="zh_CN" xml:base="http://www.bokee.net"> 
<![CDATA[<p>动态链接库如下，想改变L6的值</p>
<p>#include &quot;math.h&quot;<br />#include &quot;iostream.h&quot;<br />double L6=310;<br />_declspec(dllexport) bool InvertZhi(double zhi)<br />{<br />&nbsp;L6=310+zhi;<br />&nbsp;return true;</p>
<p>}<br />_declspec(dllexport) bool Forward(double *q)<br />{<br />&nbsp;q[0]=L6;<br />&nbsp;return true;</p>
<p>}</p>
<p>&nbsp;</p>
<p>测试</p>
<p>void CDyCeshiDlg::OnButton1() <br />{<br />&nbsp;// TODO: Add your control notification handler code here<br />&nbsp;UpdateData(true);<br />&nbsp;double zhi=m_Edit2;<br />&nbsp;InvertZhi(zhi);<br />&nbsp;double q[1]={0.0};<br />&nbsp;Forward(q);<br />&nbsp;m_Edit=q[0];<br />&nbsp;UpdateData(false);<br />}</p>]]>
</content>
</entry>

<entry>
<title>VC++ MFC DLL动态链接库编写详解 </title>
<link rel="alternate" type="text/html" href="http://www.bokee.net/blogmodule/weblogcomment_viewEntry/1365923.html"/>
<issued>2008-01-18T10-23-24 CST</issued> 
<created>2008-01-18T10-23-24 CST</created>
<modified>2008-01-18T10-23-23Z</modified>
<id>tag:wqj1212.blogchina.com,2005://1365923</id>
<author>
<name>wqj1212</name>
<url>http://www.bokee.net/blogmodule/weblogcomment_index/wqj1212.html</url>
</author>
<dc:subject>VC++学习</dc:subject>
<content type="text/html" mode="escaped" xml:lang="zh_CN" xml:base="http://www.bokee.net"> 
<![CDATA[<br />虽然能用DLL实现的功能都可以用COM来替代，但DLL的优点确实不少，它更容易创建。本文将讨论如何利用VC MFC来创建不同类型的DLL，以及如何使用他们。<br /><br />一、DLL的不同类型<br />使用VC++可以生成两种类型的DLL：MFC扩展DLL和常规DLL。常规DLL有可以分为动态连接和静态连接。Visual C++还可以生成WIN32 DLL，但不是这里讨论的主要对象。<br />1、MFC扩展DLL<br />每个DLL都有某种类型的接口：变量、指针、函数、客户程序访问的类。它们的作用是让客户程序使用DLL，MFC扩展DLL可以有C++的接口。也就是它可以导出C++类给客户端。导出的函数可以使用C++/MFC数据类型做参数或返回值，导出一个类时客户端能创建类对象或者派生这个类。同时，在DLL中也可以使用DLL和MFC。<br />Visual C++使用的MFC类库也是保存在一个DLL中，MFC扩展DLL动态连接到MFC代码库的DLL，客户程序也必须要动态连接到MFC代码库的DLL。（这里谈到的两个DLL，一个是我们自己编写的DLL，一个装MFC类库的DLL）现在MFC代码库的DLL也存在多个版本，客户程序和扩展DLL都必须使用相同版本的MFC代码DLL。所以为了让MFC扩展DLL能很好的工作，扩展DLL和客户程序都必须动态连接到MFC代码库DLL。而这个DLL必须在客户程序运行的计算机上。<br />2、常规DLL<br />使用MFC扩展DLL的一个问题就是DLL仅能和MFC客户程序一起工作，如果需要一个使用更广泛的DLL，最好采用常规DLL，因为它不受MFC的某些限制。常规DLL也有缺点：它不能和客户程序发送指针或MFC派生类和对象的引用。一句话就是常规DLL和客户程序的接口不能使用MFC，但在DLL和客户程序的内部还是可以使用MFC。<br />当在常规DLL的内部使用MFC代码库的DLL时，可以是动态连接/静态连接。如果是动态连接，也就是常规DLL需要的MFC代码没有构建到DLL中，这种情况有点和扩展DLL类似，在DLL运行的计算机上必须要MFC代码库的DLL。如果是静态连接，常规DLL里面已经包含了需要的MFC代码，这样DLL的体积将比较大，但它可以在没有MFC代码库DLL的计算机上正常运行。<br /><br />二、建立DLL<br />利用Visual C++提供的向导功能可以很容易建立一个不完成任何实质任务的DLL，这里就不多讲了，主要的任务是如何给DLL添加功能，以及在客户程序中利用这个DLL<br />1、导出类<br />用向导建立好框架后，就可以添加需要导出类的.cpp .h文件到DLL中来，或者用向导创建C++ Herder File/C++ Source File。为了能导出这个类，在类声明的时候要加&ldquo;_declspec(dllexport)&rdquo;,如： <br />class _declspec(dllexport) CMyClass<br />{<br />...//声明 <br />}<br />如果创建的MFC扩展DLL，可以使用宏：AFX_EXT_CLASS:<br />class AFX_EXT_CLASS CMyClass<br />{<br />...//声明 <br />}<br />这样导出类的方法是最简单的，也可以采用.def文件导出，这里暂不详谈。<br />2、导出变量、常量、对象<br />很多时候不需要导出一个类，可以让DLL导出一个变量、常量、对象，导出它们只需要进行简单的声明：_declspec(dllexport) int MyInt; <br />_declspec(dllexport) extern const COLORREF MyColor=RGB(0,0,0); <br />_declspec(dllexport) CRect rect(10,10,20,20); <br />要导出一个常量时必须使用关键字extern，否则会发生连接错误。<br />注意：如果客户程序识别这个类而且有自己的头文件，则只能导出一个类对象。如果在DLL中创建一个类，客户程序不使用头文件就无法识别这个类。<br />当导出一个对象或者变量时，载入DLL的每个客户程序都有一个自己的拷贝。也就是如果两个程序使用的是同一个DLL，一个应用程序所做的修改不会影响另一个应用程序。 <br />我们在导出的时候只能导出DLL中的全局变量或对象，而不能导出局部的变量和对象，因为它们过了作用域也就不存在了，那样DLL就不能正常工作。如： <br />MyFunction()<br />{<br />_declspec(dllexport) int MyInt; <br />_declspec(dllexport) CMyClass object; <br />}<br />3、导出函数<br />导出函数和导出变量/对象类似，只要把_declspec(dllexport)加到函数原型开始的位置：<br />_declspec(dllexport) int MyFunction(int);<br />如果是常规DLL，它将和C写的程序使用，声明方式如下：<br />extern &quot;c&quot; _declspec(dllexport) int MyFunction(int);<br />实现：<br />extern &quot;c&quot; _declspec(dllexport) int MyFunction(int x)<br />{<br />...//操作 <br />}<br />如果创建的是动态连接到MFC代码库DLL的常规DLL，则必须插入AFX_MANAGE_STATE作为导出函数的首行，因此定义如下：<br />extern &quot;c&quot; _declspec(dllexport) int MyFunction(int x)<br />{<br />AFX_MANAGE_STATE(AfxGetStaticModuleState()); <br />...//操作 <br />}<br />有时候为了安全起见，在每个常规DLL里都加上，也不会有任何问题，只是在静态连接的时候这个宏无效而已。这是导出函数的方法，记住只有MFC扩展DLL才能让参数和返回值使用MFC的数据类型。<br />4、导出指针<br />导出指针的方式如下：<br />_declspec(dllexport) int *pint;<br />_declspec(dllexport) CMyClass object = new CMyClass;<br />如果声明的时候同时初始化了指针，就需要找到合适的地方类释放指针。在扩展DLL中有个函数DllMain()。（注意函数名中的两个l要是小写字母），可以在这个函数中处理指针：<br /># include &quot;MyClass.h&quot;<br />_declspec(dllexport) CMyClass *pobject = new CMyClass;<br />DllMain(HINSTANCE hInstance,DWORD dwReason,LPVOID lpReserved)<br />{<br />if(dwReason == DLL_PROCESS_ATTACH) <br />{ <br />.....// <br />} <br />else if(dwReason == DLL_PROCESS_DETACH) <br />{ <br />delete pobject; <br />} <br />}<br />常规DLL有一个从CWinApp派生的类对象处理DLL的开和关，可以使用类向导添加InitInstance/ExitInstance函数。<br />int CMyDllApp::ExitInstance()<br />{<br />delete pobject; <br />return CWinApp::ExitInstance(); <br />}<br /><br />三、在客户程序中使用DLL<br />编译一个DLL时将创建两个文件.dll文件和.lib文件。首先将这两个文件复制到客户程序项目的文件夹里，这里需要注意DLL和客户程序的版本问题，尽量使用相同的版本，都使用RELEASE或者都是DEBUG版本。 <br />接着就需要在客户程序中设置LIB文件，打开Project Settings--- &gt;Link---&gt;Object/library Modules中输入LIB的文件名和路径。如：Debug/SampleDll.lib。除了DLL和LIB文件外，客户程序需要针对导出类、函数、对象和变量的头文件，现在进行导入添加的关键字就是：_declspec(dllimport)，如：<br />_declspec(dllimport) int MyFunction(int);<br />_declspec(dllimport) int MyInt;<br />_declspec(dllimport) CMyClass object;<br />extern &quot;C&quot; _declspec(dllimport) int MyFunction(int);<br />在有的时候为了导入类，要把相应类的头文件添加到客户程序中，不同的是要修改类声明的标志：<br />class _declspec(dllimport) CMyClass，如果创建的是扩展DLL，两个位置都是:<br />class AFX_EXT_CLASS CMyClass。<br /><br /><br />使用DLL的一个比较严重的问题就是编译器之间的兼容性问题。不同的编译器对c++函数在二进制级别的实现方式是不同的。所以对基于C++的DLL，如果编译器不同就有很麻烦的。如果创建的是MFC扩展DLL，就不会存在问题，因为它只能被动态连接到MFC的客户应用程序。这里不是本文讨论的重点。<br /><br />一、重新编译问题<br />我们先来看一个在实际中可能遇到的问题：<br />比如现在建立好了一个DLL导出了CMyClass类，客户也能正常使用这个DLL，假设CMyClass对象的大小为30字节。如果我们需要修改DLL中的CMyClass类，让它有相同的函数和成员变量，但是给增加了一个私有的成员变量int类型，现在CMyClass对象的大小就是34字节了。当直接把这个新的DLL给客户使用替换掉原来30字节大小的DLL，客户应用程序期望的是30字节大小的对象，而现在却变成了一个34字节大小的对象，糟糕，客户程序出错了。<br />类似的问题，如果不是导出CMyClass类，而在导出的函数中使用了CMyClass，改变对象的大小仍然会有问题的。这个时候修改这个问题的唯一办法就是替换客户程序中的CMyClass的头文件，全部重新编译整个应用程序，让客户程序使用大小为34字节的对象。<br />这就是一个严重的问题，有的时候如果没有客户程序的源代码，那么我们就不能使用这个新的DLL了。<br /><br />二、解决方法 <br />为了能避免重新编译客户程序，这里介绍两个方法：（1）使用接口类。（2）使用创建和销毁类的静态函数。<br />1、使用接口类<br />接口类的也就是创建第二个类，它作为要导出类的接口，所以在导出类改变时，也不需要重新编译客户程序，因为接口类没有发生变化。<br />假设导出的CMyClass类有两个函数FunctionA FunctionB。现在创建一个接口类CMyInterface，下面就是在DLL中的CMyInterface类的头文件的代码：<br /># include &quot;MyClass.h&quot;<br />class _declspec(dllexport) CMyInterface<br />{<br />CMyClass *pmyclass;<br />CMyInterface();<br />~CMyInterface();<br />public:<br />int FunctionA(int);<br />int FunctionB(int);<br />};<br />而在客户程序中的头文件稍不同，不需要INCLUDE语句，因为客户程序没有它的拷贝。相反，使用一个CMyClass的向前声明，即使没有头文件也能编译：<br />class _declspec(dllexport) CMyInterface<br />{<br />class CMyClass;//向前声明<br />CMyClass *pmyclass;<br />CMyInterface();<br />~CMyInterface();<br />public:<br />int FunctionA(int);<br />int FunctionB(int);<br />};<br />在DLL中的CMyInterface的实现如下：<br />CMyInterface::CMyInterface()<br />{<br />pmyclass = new CMyClass();<br />}<br />CMyInterface::~CMyInterface()<br />{<br />delete pmyclass;<br />}<br />int CMyInterface::FunctionA()<br />{<br />return pmyclass-&gt;FunctionA();<br />}<br />int CMyInterface::FunctionB()<br />{<br />return pmyclass-&gt;FunctionB(); <br />}<br />.....<br />对导出类CMyClass的每个成员函数，CMyInterface类都提供自己的对应的函数。客户程序与CMyClass没有联系，这样任意改CMyClass也不会有问题，因为CMyInterface类的大小没有发生变化。即使为了能访问CMyClass中的新增变量而给CMyInterface类加了函数也不会有问题的。<br />但是这种方法也存在明显的问题，对导出类的每个函数和成员变量都要对应实现，有的时候这个接口类会很庞大。同时增加了客户程序调用所需要的时间。增加了程序的开销。<br /><br />2、使用静态函数<br />还可以使用静态函数来创建和销毁类对象。创建一个导出类的时候，增加两个静态的公有函数CreateMe()/DestroyMe()，头文件如下：<br />class _declspec(dllexport) CMyClass<br />{<br />CMyClass(); <br />~CMyClass(); <br />public: <br />static CMyClass *CreateMe(); <br />static void DestroyMe(CMyClass *ptr); <br />};<br />实现函数就是：<br />CMyClass * CMyClass::CMyClass()<br />{<br />return new CMyClass; <br />}<br />void CMyClass::DestroyMe(CMyClass *ptr)<br />{<br />delete ptr; <br />}<br />然后象其他类一样导出CMyClass类，这个时候在客户程序中使用这个类的方法稍有不同了。如若想创建一个CMyClass对象，就应该是：<br />CMyClass x;<br />CMyClass *ptr = CMyClass::CreateMe();<br />在使用完后删除：<br />CMyClass::DestroyMe(ptr);<br />]]>
</content>
</entry>

<entry>
<title>(拍客)世界最神奇的医生,看后疯狂爆笑</title>
<link rel="alternate" type="text/html" href="http://www.bokee.net/blogmodule/weblogcomment_viewEntry/1364942.html"/>
<issued>2008-01-17T22-01-28 CST</issued> 
<created>2008-01-17T22-01-28 CST</created>
<modified>2008-01-17T22-01-28Z</modified>
<id>tag:wqj1212.blogchina.com,2005://1364942</id>
<author>
<name>wqj1212</name>
<url>http://www.bokee.net/blogmodule/weblogcomment_index/wqj1212.html</url>
</author>
<dc:subject>搞笑视频</dc:subject>
<content type="text/html" mode="escaped" xml:lang="zh_CN" xml:base="http://www.bokee.net"> 
<![CDATA[<embed align="9" src="http://player.youku.com/player.php/sid/XNTc1NTk4MA==/v.swf" width="450" height="372" type="application/x-shockwave-flash" scale="" play="" loop="" menu=""></embed>]]>
</content>
</entry>

<entry>
<title>笑死人的王小丫接观众电话</title>
<link rel="alternate" type="text/html" href="http://www.bokee.net/blogmodule/weblogcomment_viewEntry/1364936.html"/>
<issued>2008-01-17T21-54-41 CST</issued> 
<created>2008-01-17T21-54-41 CST</created>
<modified>2008-01-17T21-54-41Z</modified>
<id>tag:wqj1212.blogchina.com,2005://1364936</id>
<author>
<name>wqj1212</name>
<url>http://www.bokee.net/blogmodule/weblogcomment_index/wqj1212.html</url>
</author>
<dc:subject>搞笑视频</dc:subject>
<content type="text/html" mode="escaped" xml:lang="zh_CN" xml:base="http://www.bokee.net"> 
<![CDATA[<embed align="9" src="http://player.youku.com/player.php/sid/XODU3NDI3Ng==/v.swf" width="450" height="372" type="application/x-shockwave-flash" scale="" play="" loop="" menu=""></embed>]]>
</content>
</entry>

<entry>
<title>办公室里有这样的女人你能安心工作吗</title>
<link rel="alternate" type="text/html" href="http://www.bokee.net/blogmodule/weblogcomment_viewEntry/1364919.html"/>
<issued>2008-01-17T21-34-13 CST</issued> 
<created>2008-01-17T21-34-13 CST</created>
<modified>2008-01-17T21-34-13Z</modified>
<id>tag:wqj1212.blogchina.com,2005://1364919</id>
<author>
<name>wqj1212</name>
<url>http://www.bokee.net/blogmodule/weblogcomment_index/wqj1212.html</url>
</author>
<dc:subject>搞笑视频</dc:subject>
<content type="text/html" mode="escaped" xml:lang="zh_CN" xml:base="http://www.bokee.net"> 
<![CDATA[<embed align="9" src="http://player.youku.com/player.php/sid/XNzEyNTgwOA==/v.swf" width="450" height="372" type="application/x-shockwave-flash" scale="" play="" loop="" menu=""></embed>]]>
</content>
</entry>

<entry>
<title>色戒（东北版）</title>
<link rel="alternate" type="text/html" href="http://www.bokee.net/blogmodule/weblogcomment_viewEntry/1364790.html"/>
<issued>2008-01-17T20-30-31 CST</issued> 
<created>2008-01-17T20-30-31 CST</created>
<modified>2008-01-17T20-30-31Z</modified>
<id>tag:wqj1212.blogchina.com,2005://1364790</id>
<author>
<name>wqj1212</name>
<url>http://www.bokee.net/blogmodule/weblogcomment_index/wqj1212.html</url>
</author>
<dc:subject>搞笑视频</dc:subject>
<content type="text/html" mode="escaped" xml:lang="zh_CN" xml:base="http://www.bokee.net"> 
<![CDATA[<embed align="9" src="http://player.youku.com/player.php/sid/XMTU5ODg2NjQ=/v.swf" width="450" height="372" type="application/x-shockwave-flash" scale="" play="" loop="" menu=""></embed>]]>
</content>
</entry>

</feed>
