怎样用下载的象棋许银川直播软件下输特级大师或好友

(Visual C++)游戏开发笔记十四:游戏画面绘图(四)华丽的CImage类
我们知道,Visual C++中的CBitmap类的功能简直太弱小了,这曾经让Visual C++在图像处理方面的功能比较尴尬。之前笔记里面,我们采用的CBitmap配合GDI进行透明图像的处理有些晦涩繁琐,而且受到图像素材的限制,可以说是有些落后,不是太实用。
为了解决这个问题,这节笔记我们将的学习MFC和ATL中新增一个图像处理的类,它就是华丽而强大的CImage类。
由于本节笔记是对CImage类的一个非常系统近乎完全的介绍,我尽量让它涵盖到了CImage类的所有的属性和类成员,所以
篇幅也许比以往的笔记内容都长,里面的不少内容是用到的时候才需要掌握或者查阅的,并不用强行记忆。
一,概念讲解部分
1.CImage类的定位和概述
首先,我们简单介绍一下CImage类的定位。
CImage是MFC和ATL共享的新类,它提供了增强的位图支持,包括加载、保存和转换JPEG,BMP,GIF,PNG图像格式的能力。可以说是微软意识到了CBitmap的不足,然后推出了一个CBitmap的增强版。使用CImage类,需在代码头部加入包含atlimage.h文件,即添加代码#include &atlimage.h&。
由于CImage拥有功能强大的类成员函数的支持,它便具有了下列四个比较出彩的特性:
1、AlphaBlend支持像素级的颜色混合,从而实现透明和半透明的效果。
2、PlgBlt能使一个矩形区域的位图映射到一个平行四边形区域中,而且还可能使用位屏蔽操作。
3、TransparentBlt在目标区域中产生透明图像
4、MaskBlt在目标区域中产生源位图与屏蔽位图合成的效果。
2.以CImage类做媒,让CBitmap类也能处理丰富的图片格式
解决的思路比较明朗,我们采用CImage类的Load函数加载图片,之后用Detch取得HBITMAP的句柄,然后再将此句柄附加给CBitmap的对象就行了。
这样就实现了让CBitmap类也可以操作JPG/JPEG/GIF/PNG格式的图片。
具体代码如下:
#include &atlimage.h&&&
CImage image;&&&&&&&&&&&&&& //定义一个CBitmap类&&
image.Load(&filename&); //filename为要加载的文件地址&&
HBITMAP hBitmap=image.Detach(); //返回被分离的图片的句柄&&
CB&&&&&&&&&&&&&&&&&&&& // 定义一个bitmap&&
bmp.Attach(hBitmap);&&&&&&& //进行句柄的附加&
#include &atlimage.h&
CImage image;&&&&&&&&&&&&&& //定义一个CBitmap类
image.Load(&filename&); //filename为要加载的文件地址
HBITMAP hBitmap=image.Detach(); //返回被分离的图片的句柄
CB&&&&&&&&&&&&&&&&&&&& // 定义一个bitmap
bmp.Attach(hBitmap);&&&&&&& //进行句柄的附加
然后就可以用CBitmap进行余下的操作了。
3.CImage额外的一些性质
CImage类对于DIB(device-independent bitmap)设备无关位图文件和非DIB都可以处理。我们可以通过Create函数或者CImage::Load来处理DIB部分,用Attach函数来将非DIB部分附加到一个CImage对象上。
对于以下函数,只支持DIB部分的位图文件,他们是:
GetBitsGetColorTable,GetMaxColorTableEntries,GetPitch,GetPixelAddress,IsIndexed,SetColorTable。
我们可以通过CImage类中的IsDIBSection()函数来帮助我们判断一个位图文件是否为DIB部分,其定义如下:
bool IsDIBSection( ) const throw( );& //如果返回值为true,则该文件为DIB;返回flase则不是DIB文件&
bool IsDIBSection( ) const throw( );& //如果返回值为true,则该文件为DIB;返回flase则不是DIB文件
我们需要注意的是,CImage不能被选到一个新的CDC( class of device-context设备描述表的类),CImage会为图像创建自己的HDC(设备描述表DC的句柄)。因为一个HBITMAP只能被选入到一个HDC中一次,也就是说这个与CImage相关的HBITMAP不能被选到一个其他的HDC中。
如果需要一个CDC,我们可以从CImage中获取HDC,然后使用CDC::FromHandle函数。
4.CImage兼容性的说明
在CImage中,有如下兼容性的要求:
只支持Windows NT4.0以上系统的成员函数:PlgBlt,MaskBlt,AlphaBlend。
只支持Windows 2000,98以上系统的成员函数:TransparentBlt,Draw
其实由于目前都是Windows XP以上的操作系统,这个知识点了解一下就行。
5.CImage类用于贴图的一般的使用方法
使用方法不唯一,最常用的方法如下,该方法大致分为三部分:
&&1& 在源文件中添加CImage类的包含文件:
&&#include &atlimage.h&
&&2& 定义一个CImage类对象,然后调用CImage::Load方法装载一个外部图像文件。Load方法有如下两种重载:
HRESULT Load(&
&& LPCTSTR pszFileName&&& //包含加载文件名的字符串指针&&
) throw( );&
HRESULT Load(&
&& IStream* pStream&& //指向包含加载文件名的流的指针&&
) throw();&
&HRESULT Load(
&&& LPCTSTR pszFileName&&& //包含加载文件名的字符串指针
&) throw( );
&HRESULT Load(
&&& IStream* pStream&& //指向包含加载文件名的流的指针
&) throw();
&&3& 调用CImage::Draw方法绘制图像。
下面重点介绍一下Draw方法。
CImage::Draw& 将一个位图文件从源设备描述表复制到当前设备描述表
该函数有如下六种重载:
BOOL Draw(&
&& HDC hDestDC,&&&&&&&& //目标设备环境DC的句柄&&
&& int xDest,&&&&&&&&&& //目的矩形的左上角X坐标(逻辑单位)&&
&& int yDest,&&&&&&&&&& //目的矩形的左上角Y坐标(逻辑单位)&&
&& int nDestWidth,&&&& //目标矩形的宽度(就是设定贴过去的图片的宽度)&&
&& int nDestHeight,&&& //目标矩形的高度(就是设定铁锅的图片的高度)&&
&& int xSrc,&&&&&&&&&&& //源矩形的左上角X坐标&&
&& int ySrc,&&&&&&&&&&& //源矩形的左上角Y坐标&&
&& int nSrcWidth,&&&&& //源矩形的宽度&&
&& int nSrcHeight&&&&& //源矩形的高度&&
) const throw( );&
BOOL Draw(&
&& HDC hDestDC,&&&&&& //目标环境DC的句柄&&
&& const RECT& rectDest,&&&&&&& //一个RECT结构的引用,用来确定目标图像。&&
&& const RECT& rectSrc&&&&&&&& //一个RECT结构体的引用,用来确定源图像&&
) const throw( );&
BOOL Draw(&
&& HDC hDestDC,&&&&&&&& //目标环境DC的句柄&&
&& int xDest,&&&&&&& //目标矩形的左上角X坐标&&
&& int yDest&&&&&&&& //目标矩形的左上角Y坐标&&
) const throw( );&&&&&&& //&&
BOOL Draw(&
&& HDC hDestDC,&&&&&&& //目标环境DC的句柄&&
&& const POINT& pointDest&&&&&&&& //一个POINT结构体,用来确定目的矩形的左上角坐标&&
) const throw( );&
BOOL Draw(&
&& HDC hDestDC,&&&&&&& //目标环境DC的句柄&&
&& int xDest,&&&&&&& //目标矩形的左上角X坐标&&
&& int yDest,&&&&&&& //目标矩形的左上角Y坐标&&
&& int nDestWidth,&&&&&&& //目标矩形的宽度&&
&& int nDestHeight&&&&&&&& //目标矩形的宽度&&
) const throw( );&
BOOL Draw(&
&& HDC hDestDC,&&&&&&& //目标环境DC的句柄&&
&& const RECT& rectDest&&&&&&&& //一个RECT结构的引用,用来确定目标图像。&&
) const throw( );&
BOOL Draw(
&& HDC hDestDC,&&&& &//目标设备环境DC的句柄
&& int xDest,&&&&&&&&&& //目的矩形的左上角X坐标(逻辑单位)
&& int yDest,&&&&&&&&&& //目的矩形的左上角Y坐标(逻辑单位)
&& int nDestWidth,&&&& //目标矩形的宽度(就是设定贴过去的图片的宽度)
&& int nDestHeight,&&& //目标矩形的高度(就是设定铁锅的图片的高度)
&& int xSrc,&&&&&&&&&&& //源矩形的左上角X坐标
&& int ySrc,&&&&&&&&&&& //源矩形的左上角Y坐标
&& int nSrcWidth,&&&&& //源矩形的宽度
&& int nSrcHeight&&&&& //源矩形的高度
) const throw( );
BOOL Draw(
&& HDC hDestDC,&&&&&& //目标环境DC的句柄
&& const RECT& rectDest,&&&&&&& //一个RECT结构的引用,用来确定目标图像。
&& const RECT& rectSrc&&&&&&&& //一个RECT结构体的引用,用来确定源图像
) const throw( );
BOOL Draw(
&& HDC hDestDC,&&&&&&&& //目标环境DC的句柄
&& int xDest,&&&&&&& //目标矩形的左上角X坐标
&& int yDest&&&&&&&& //目标矩形的左上角Y坐标
) const throw( );&&&&&&& //
BOOL Draw(
&& HDC hDestDC,&&&&&&& //目标环境DC的句柄
&& const POINT& pointDest&&&&&&&& //一个POINT结构体,用来确定目的矩形的左上角坐标
) const throw( );
BOOL Draw(
&& HDC hDestDC,&&&&&&& //目标环境DC的句柄
&& int xDest,&&&&&&& //目标矩形的左上角X坐标
&& int yDest,&&&&&&& //目标矩形的左上角Y坐标
&& int nDestWidth,&&&&&&& //目标矩形的宽度
&& int nDestHeight&&&&&&&& //目标矩形的宽度
) const throw( );
BOOL Draw(
&& HDC hDestDC,&&&&&&& //目标环境DC的句柄
&& const RECT& rectDest&&&&&&&& //一个RECT结构的引用,用来确定目标图像。
) const throw( );
在上面的Draw函数的各种重载中,对于没有指定源矩形的版本,则整个源图像就是默认的源矩形。对于没有指定目的矩形尺寸的,则源图片的尺寸就是默认的目的矩形尺寸。
需要注意的是,Draw方法综合了StretchBlt、TransparentBlt和AlphaBlend函数的功能。。通常情况下,Draw()函数作用和StretchBlt()函数一致。但是当我们的图像中存在透明的颜色和alpha通道的时候,Draw()函数作用和TransparentBlt()或者AlphaBlend()函数一致。所以,在一般情况下,我们都尽量调用Draw方法来绘制图像。
6.对CImage所有类成员的介绍
我将CImage类的所有类函数按功能分为了四大类,可以更方面的了解各函数的定位和作用,也方便大家查阅:
&1&功能为创建与连接,释放的函数
Attach&&&&&&&& 附加一个HBITMAP到CImage对象,位图类型DIB与否都可以
Create&&&&&&&& 创建一个DIB部分的位图,并将其附加到之前创建的CImage对象
CreateEX&&&&& 创建一个DIB部分的位图(拥有额外的参数),并将其附加到之前 创建的CImage对象
Destroy&&&&&& 从CImage类上分离该位图并进行删除
Detach&&&&&& 从CImage类里分离该位图
ReleaseDC&&&&&&&&&&&&&&& 释放设备描述表中的数据
ReleaseGDIPlus&&&&&&&&&&&& 释放GDI+使用的源
&2&功能为输入与输出的函数
GetExporterFilterString 返回系统支持的输入文件格式类型及其描述
GetImporterFilterString 返回系统支持的输出文件格式类型及其描述
LoadFromResource&&&&&&&&&& 从指定的源处加载一个图像资源
Load&&&&&&&&&&&&&&&&&&&&&&& 从指定文件处加载一个图像资源
IsIndexed&&&&&&&&&&& 判断一个位图颜色映射到了一个索引调色盘
IsNull&&&&&&&&&&&&&&& 判断一个源位图是否被当前载入
Save&&&&&&&&&&&&&&&&&&&&&& 以指定的类型来保存图像
&3&关于位图类型与参数的函数
GetBits&&&&&&& 返回一个指向该位图实际像素值指针
GetBPP&&&&&&& 返回该位图每个像素的位
GetColorTable& 返回颜色表中RGB值的范围条目
GetDC&&&&&&&& 返回目前被选择的设备描述表
GetExporterFilterString 返回系统支持的输入文件格式类型及其描述
GetImporterFilterString 返回系统支持的输出文件格式类型及其描述
GetHeight&&&&&&&&& 返回当前图像的像素高度
GetMaxColorTableEntries&&& 返回颜色表条目中的最大值
GetPitch&&&&&&&&&&&& 返回当前图片的间距(单位为字节),用来决定像素格式的
GetTransparentColor& 返回颜色表中透明色的位置
GetWidth&&&&&&&&&&& 返回当前图片的宽度(单位为像素)
&4&功能为图形绘制与位图块传输相关的函数
AlphaBlend&&&& 显示一个半透明或者透明像素的位图
BitBlt&&&&&&&&& 从源设备描述表复制一个位图文件到当前设备描述表
Draw&&&&&&&& 从源矩形复制一个位图到目的矩形,该函数伸缩或者拉伸位图来适应目标矩 形的尺寸,如果有必要,会处理Alpha值和透明颜色。
MaskBlt&&&&&&&&&&&&&&&&&&&& 用指定的掩码和光栅操作来结合颜色数据和目的位图
PlgBlt&&&&&&&&&&&&&&&&&&&&&& 执行一个从源设备描述表的矩形到目标设备描述表的平行 四边形的块状位图转换
SetColorTabel&&&&&&&&&&&&& 在DIB的颜色表中设定一系列条目的RGB颜色的值
SetPixelIndexed&&&&&&&&&&& 设置在指定坐标处的像素(使用索调色板的索引值)。
SetPixelRGB&&&&&&&&&&&&&&& 设置在指定坐标处的像素(使用RGB值)
SetPixel&&&&&&&&&&&&&&&&&&& 在指定坐标处设置像素的颜色
SetTransparentColor&&&&&&& 设置将被视为透明色的颜色的索引值(只能选取调色板中的 一种颜色)
StretchBlt&&&&&&&&&&&&&&&&& 从源矩形复制一个位图到目的矩形,如果有必要,该函数会 伸缩或者拉伸位图来适应目标矩形的尺寸,
TransparentBlt&&&&&&&&&&&&& 从源设备描述表中复制一个带有透明色的位图到当前设备 描述表
二,实例运用部分
运用CImage完成透明贴图的一个完整实例
介绍了这么多了,下面我们依然用一个实例来巩固本节笔记的知识。
我们知道,CImage支持透明PNG的贴图,下面我们就运用透明PNG的贴图,来代替之前的掩码操作贴图。
准备两张素材图,一张背景图,一张需要进行透明操作的人物图。
这次的选材就很广了,没有之前透明操作需要自己一定的美工功底或者美工童鞋支持的诸多限制了。
我选的两张图片素材如下:
背景图 bg.bmp& 640x444
&人物图&&onion.bmp&&130x130(呵呵,可爱的洋葱头~~)
将人物图&onion.bmp用photoshop等图像处理软件进行抠图操作,除去红黄相间的背景图,并将背景图用透明图层代替,再将图片大小调节成85x113,用png格式输出,效果如下:
处理好的人物图&&onion.png&&85x113
将bg.bmp以及onion.png放到工程目录下,并在源文件写入代码并运行。
该代码和笔记六中代码的思路基本相同,只不过,将笔记六中使用掩码操作进行透明化处理的方式换成了png透明贴图的方式,更加的直观和易懂易用。
详细注释的源代码如下
#include &stdafx.h&&&&&
#include &atlimage.h&&&
//全局变量声明&&&&
HINSTANCE hI&&&
HBITMAP&&&&&&& //声明一个位图对象,用于存储背景图&&&&
HDC&&&&&&&& //声明一个内存DC&mdc&,用来暂存位图&&
//全局函数声明&&&&
ATOM&&&& MyRegisterClass(HINSTANCE hInstance);&&&
BOOL&&&& InitInstance(HINSTANCE, int);&&&
LRESULT CALLBACK&&& WndProc(HWND, UINT, ARAM, LPARAM);&&&
void&&&& MyPaint(HDC hdc);&&&
////****Winmain函数,程序入口点函数**************************************&&&&
int APIENTRY WinMain(HINSTANCE hInstance,&&&
&&&&&&&&&&&&&&&&&&&& HINSTANCE hPrevInstance,&&&
&&&&&&&&&&&&&&&&&&&& LPSTR&&&& lpCmdLine,&&&
&&&&&&&&&&&&&&&&&&&& int&&&&&& nCmdShow)&&&
MyRegisterClass(hInstance);&&&
if (!InitInstance (hInstance, nCmdShow))&&&&
return FALSE;&&&
//消息循环&&&&
while (GetMessage(&msg, NULL, 0, 0))&&&&
TranslateMessage(&msg);&&&
DispatchMessage(&msg);&&&
return msg.wP&&&
//****设计一个窗口类,类似填空题,使用窗口结构体*************************&&&&
ATOM MyRegisterClass(HINSTANCE hInstance)&&&
WNDCLASSEX&&&
wcex.cbSize = sizeof(WNDCLASSEX);&&&&
wcex.style&& = CS_HREDRAW | CS_VREDRAW;&&&
wcex.lpfnWndProc&&& = (WNDPROC)WndP&&&
wcex.cbClsExtra& = 0;&&&
wcex.cbWndExtra& = 0;&&&
wcex.hInstance&& = hI&&&
wcex.hIcon&& = LoadIcon(NULL,IDI_APPLICATION);&&&
wcex.hCursor&&&& = NULL;&&&
wcex.hCursor&&&& = LoadCursor(NULL, IDC_ARROW);&&&
wcex.hbrBackground& = (HBRUSH)(COLOR_WINDOW+1);&&&
wcex.lpszMenuName&& = NULL;&&&
wcex.lpszClassName& = &canvas&;&&&
wcex.hIconSm&&&& = NULL;&&&
return RegisterClassEx(&wcex);&&&
//****初始化函数*************************************&&&&
// 1.建立与窗口DC兼容的内存DC&&&&
// 2.从文件加载背景图及透明的洋葱头&&&
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)&&&
HWND hW&&&
hInst = hI&&&
hWnd = CreateWindow(&canvas&, &浅墨的绘图窗口& , WS_OVERLAPPEDWINDOW,&&&
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);&&&
if (!hWnd)&&&
return FALSE;&&&
MoveWindow(hWnd,10,10,600,444,true);&&&
ShowWindow(hWnd, nCmdShow);&&&
UpdateWindow(hWnd);&&&
hdc = GetDC(hWnd);&&&&&&&&&&&&&&&&&&&& //获得窗口DC&&&&
mdc = CreateCompatibleDC(hdc);&&&&&&&&&& //创建与窗口兼容的内存DC(mdc)&&&&
bg = (HBITMAP)LoadImage(NULL,&bg.bmp&,IMAGE_BITMAP,600,444,LR_LOADFROMFILE);&&&
MyPaint(hdc);&&&
ReleaseDC(hWnd,hdc);&&&
return TRUE;&&&
//****自定义绘图函数*********************************&&&&
//透明贴图&&&&
void MyPaint(HDC hdc)&&&
SelectObject(mdc,bg);&&&
BitBlt(hdc,0,0,600,450,mdc,0,0,SRCCOPY);&&& //先将背景图贴到显示窗口中&&&&
CI&&&&& //定义一个CImage对象,用于透明贴图&&
CS&&&&& //定义一个CString对象,用于存放文件名字符串&&
str=&onion.png&;&&&&&&&&&&&&& //将字符串赋值为文件名&&
image.Load(str);&&&&&&&&&&&&&&&&&&& //在image中载入图像文件&&
image.Draw(hdc,120,180,85,113,0,0,85,113);&&& //调用Draw进行透明贴图&&
//或者为image.TransparentBlt(hdc, 120, 180, 85, 113,CLR_INVALID );//调用TransparentBlt进行透明贴图&&
image.Destroy();&
//****消息处理函数**********************************&&&&
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)&&&
PAINTSTRUCT&&&
switch (message)&&&
case WM_PAINT:&& //窗口重绘消息&&&&
hdc = BeginPaint(hWnd, &ps);&&&
MyPaint(hdc);&&&
EndPaint(hWnd, &ps);&&&
case WM_DESTROY:&&&& //窗口结束消息&&&&
DeleteDC(mdc);&&&
DeleteObject(bg);&&&
PostQuitMessage(0);&&&
default:&&&& //其他消息&&&&
return DefWindowProc(hWnd, message, wParam, lParam);&&&
&& return 0;&&&
&最后得到的效果图如下:
我们可以改变CImage::Draw函数的参数值,让&洋葱头&出现在地图不同的地方。
通过这个实例可以发现,用CImage类进行透明贴图,实在是方便多了。
本节笔记到这里就结束了,由于近期在做一个纯flash的网站,更新速度和评论的回复都不像往常那么及时,希望大家能够体谅。
本节笔记的源代码请点击这里下载:&&
【Visual C++】Code_Note_14
感谢一直支持【Visual C++】游戏开发笔记系列专栏的朋友们,也请大家继续关注我的专栏,我一有时间就会把自己的学习心得,觉得比较好的知识点写出来和大家一起分享。
精通游戏开发的路还很长很长,非常希望能和大家一起交流,共同学习,共同进步。
大家看过后觉得值得一看的话,可以顶一下这篇文章,你们的支持是我继续写下去的动力~
如果文章中有什么疏漏的地方,也请大家指正。也希望大家可以多留言来和我探讨相关的问题。
最后,谢谢你们一直的支持~~~
摘自& 枫落★流年【图像处理】CImage类的简单应用
【图像处理】CImage类的简单应用
CImage类的介绍与使用
& &CImage类是ATL和MFC共用的一个类,其头文件为atlimage.h,主要用于图片文件的打开,显示与保存。这里需要注意的是,在VS2010和VS2012的MFC编程中,不需要将头文件包含进来。MFC中要使用CImage类,必须先将头文件包含进来,可以包含在当前代码的CPP文件中,也可以包含在所属类的头文件中,不过最好还是包含在工程的stdafx.h文件中。CImage总共有39个成员函数。具体函数介绍,请查阅MSDN。
彩色图像转换成8位灰度图像
将一张普通彩色图像转换成8位灰度图像,需要调用灰度图像的调色板来处理,且需要调用CImage::IsIndexed来判断是否使用颜色表,若是则修改颜色表,否则直接对像素对颜色值进行处理。
void CImageDlg::TurnToGray(CImage *img,CImage *newimg)
int width=img-&GetWidth();
int height=img-&GetHeight();
RGBQUAD ColorTable[256];
for (int i = 0; i & 256; ++i)
ColorTable[i].rgbBlue = ColorTable[i].rgbGreen = ColorTable[i].rgbRed =
newimg-&SetColorTable(0, 256, ColorTable);
byte* pDataDst = (byte*)newimg-&GetBits();
int pitchDst = newimg-&GetPitch();
int bitCountDst = newimg-&GetBPP() / 8;
if (bitCountDst != 1)
int r,g,b,
for(int i=0;i&i++)
for(int j=0;j&j++)
pixel=img-&GetPixel(i,j);
r=GetRValue(pixel);
g=GetGValue(pixel);
b=GetBValue(pixel);
avg=(r+g+b)/3;
*(pDataDst+pitchDst*j+i*bitCountDst)=
MFC对话框显示图像
void CImageDlg::ShowImage(CImage image,int id)
//一个参数是对象srcPng或者是destPng,另一个参数是控件ID
hdc = ::GetDC(GetDlgItem(id)-&GetSafeHwnd());
GetDlgItem(id)-&GetClientRect(rect);
image.Draw(hdc , rect);
::DeleteDC(hdc);
打开一张图像并显示
void CEx_ImageView::OnFileOpen() //Cyan:添加
// TODO: 在此添加命令处理程序代码
CString strF
CSimpleArray&GUID&aguidFileT
HRESULT hR
//获取CImage支持的图像文件的过滤字符串
hResult=m_Image.GetExporterFilterString(strFilter,aguidFileTypes,_T(&All Image Files&));
if(FAILED(hResult))
MessageBox(_T(&GetExporterFilter调用失败!&));
CFileDialog dlg(TRUE,NULL,NULL,OFN_FILEMUSTEXIST,strFilter);
if(IDOK!=dlg.DoModal())
m_Image.Destroy();
//将外部图像文件装载到CImage对象中
hResult=m_Image.Load(dlg.GetFileName());
if(FAILED(hResult))
MessageBox(_T(&调用图像文件失败!&));
//设置主窗口标题栏内容
str.LoadString(AFX_IDS_APP_TITLE);
AfxGetMainWnd()-&SetWindowTextW(str+_T(&-&)+dlg.GetFileName());
Invalidate();//强制调用OnDraw函数
我的热门文章
即使是一小步也想与你分享VC++ 常用类、方法、函数、关键字(92)
VC++ CDC(51)
CImage类使用
&&&&&&&& CImage类是基于GDI+的,但是这里为什么要讲归于GDI?
&&&&&&&& 主要是基于这样的考虑: 在GDI+环境中,我们可以直接使用GDI+ ,没多少必要再使用CImage类
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& 但是,如果再GDI环境中,我们要想使用GDI+,有点麻烦,还得加入头文件,加入启动GDI+的代码和关闭GDI+的代码,显得太罗嗦了,GDI&&的CBitmap 处理功能又有局限,只能处理BMP格式的图片。 怎么办?这时,我们便可使用CImage类,因为这个类本身封装了GDI+得使用环境,所以无需我们手动设置,简化了我们的操作。& 同时,又可以利用GDI+中强大的图片处理功能,及可以简便的与CBitmap对象进行转换
,大大方便了在GDI环境下,进行各种图片处理工作 。
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& 其实,将其称作 GDI/ GDI+ 混合编程,这样才更确切些。
为什么引入CImage类?
&&& CBitmap 类只能处理BMP格式的图片,非常受限。
&&& 而CImage可以处理JPGE GIF BMP PNG多种格式图片,扩展了图片处理功能 且能与CBitmap 进行转换( 因为所载入的位图句柄都是HBITMAP,所以可相互转换),因此引入CImage类进行图像处理
&&&& CImage provides enhanced bitmap support, including the ability to load and save images in JPEG, GIF, BMP, and Portable Network Graphics (PNG) formats
CImage类介绍
&&&&&CImage是MFC和ATL共享的新类,它能从外部磁盘中调入一个JPEG、GIF、BMP和PNG格式的图像文件加以显示,而且这些文件格式可以相互转换。
&&&& CImage是VC.NET中定义的一种MFC/ATL共享类,也是ATL的一种工具类,它提供增强型的(DDB和DIB)位图支持,可以装入、显示、转换和保存多种格式的图像文件,包括BMP、GIF、JPG、PNG、TIF等。CImage是一个独立的类,没有基类。(CImage类是基于GDI+的,从VC.NET起引进,VC 6.0中没有。)
&&&&& ATL(Active Template Library,活动模板库)是一套基于模板的 C++ 类,用以简化小而快的 COM 对象的编写。
为了在MFC程序中使用CImage类,必须包含ATL的图像头文件atlimage.h:(在VS08 SP1中不用包含)
&&&& #include &atlimage.h&
1& 加载位图文件
&&&&&if(!PathFileExists(imgFilePath))&&&&&&&return&NULL;&&&&CImage&nI&&nImage.Load(imgFilePath);&&return&nImage.Detach();&&&&
&span style=&font-size:14&&
// CImage可加载的图片文件有JPG,BMP,TIF.PNG等格式
而CBitmap只能加载BMP图片文件
if(!PathFileExists(imgFilePath))
return NULL;
nImage.Load(imgFilePath);
return nImage.Detach();
//返回HBITMAP
可用CBitmap 处理 也可用CImage处理 &/span&
2 与CBitmap转换
CImage&nI&&nImage.Load(imgFilePath);&&&&HBITMAP&hBitmap=nImage.Detach();&&&&&&&&&CBitmap&&&bmp.DeleteObject();&&bmp.Attach(hBitmap);&&&&&&&&&&&&CBitmap&*pBitmap=CBitmap::FromHandle(nImage.m_hBitmap);&&
&span style=&font-size:14&& CImage nI
nImage.Load(imgFilePath);
HBITMAP hBitmap=nImage.Detach(); // 获得位图句柄 用以转换
// 转换方式一:
bmp.DeleteObject();
bmp.Attach(hBitmap); //
转换为CBitmap对象
// 转换方式二:
CBitmap *pBitmap=CBitmap::FromHandle(nImage.m_hBitmap);
3 获得CImage对象的cdc
CDC&*pDC=CDC::FromHandle(nImage.GetDC());&&&&&&&&nImage.ReleaseDC();&&
&span style=&font-size:14&& CDC *pDC=CDC::FromHandle(nImage.GetDC());
// Use pDC here
nImage.ReleaseDC();&/span&
4 显示位图
&& 思路: 将CImage对象 绘制在对应的DC中
&& 所使用的函数 BitBlt&& StretchBlt& Draw等
&& 以Draw举例:
BOOL&Draw(&&&&&HDC&hDestDC,&&&&&int&xDest,&&&&&int&yDest,&&&&&int&nDestWidth,&&&&&int&nDestHeight,&&&&&int&xSrc,&&&&&int&ySrc,&&&&&int&nSrcWidth,&&&&&int&nSrcHeight&&&)&const&throw(&);&&BOOL&Draw(&&&&&HDC&hDestDC,&&&&&const&RECT&&rectDest,&&&&&const&RECT&&rectSrc&&&)&const&throw(&);&&BOOL&Draw(&&&&&HDC&hDestDC,&&&&&int&xDest,&&&&&int&yDest&&&)&const&throw(&);&&BOOL&Draw(&&&&&HDC&hDestDC,&&&&&const&POINT&&pointDest&&&)&const&throw(&);&&BOOL&Draw(&&&&&HDC&hDestDC,&&&&&int&xDest,&&&&&int&yDest,&&&&&int&nDestWidth,&&&&&int&nDestHeight&&&)&const&throw(&);&&BOOL&Draw(&&&&&HDC&hDestDC,&&&&&const&RECT&&rectDest&&&)&const&throw(&);&&
&span style=&font-size:14&&BOOL Draw(
HDC hDestDC,
int xDest,
int yDest,
int nDestWidth,
int nDestHeight,
int nSrcWidth,
int nSrcHeight
) const throw( );
BOOL Draw(
HDC hDestDC,
const RECT& rectDest,
const RECT& rectSrc
) const throw( );
BOOL Draw(
HDC hDestDC,
int xDest,
) const throw( );
BOOL Draw(
HDC hDestDC,
const POINT& pointDest
) const throw( );
BOOL Draw(
HDC hDestDC,
int xDest,
int yDest,
int nDestWidth,
int nDestHeight
) const throw( );
BOOL Draw(
HDC hDestDC,
const RECT& rectDest
) const throw( );
Draw performs the same operation as
, unless the image contains a transparent color or alpha channel. In that case,Draw performs the same operation as either
or as required.
For versions of Draw that do not specify a source rectangle, the entire source image is the default. For the version ofDraw that does not specify a size for the destination rectangle, the size
of the source image is the default and no stretching or shrinking occurs.
EXAMPLE 1:
CImage&&&img.Load(&1.jpg&);&&&&if&(!img.IsNull())&&{&&&&&&img.Draw(pDC-&m_hDC,CRect(0,0,100,100));&&}&&
&span style=&font-size:14&& CI
img.Load(&1.jpg&);
if (!img.IsNull())
img.Draw(pDC-&m_hDC,CRect(0,0,100,100));
EXAMPLE 2: 画在另一个位图中
CImage&&&img.Load(filePath);&&&&&&HDC&hDC=img.GetDC();&&CDC&*pDC=CDC::FromHandle(hDC);&&&&CBitmap&&&bmp.CreateCompatibleBitmap(pDC,nWidth,nHeight);&&&&&&&CDC&memDC;&&memDC.CreateCompatibleDC(pDC);&&CBitmap&*pOld=memDC.SelectObject(&bmp);&&&&&&&&::SetStretchBltMode(memDC.m_hDC,HALFTONE);&&::SetBrushOrgEx(memDC.m_hDC,0,0,NULL);&&img.StretchBlt(memDC.m_hDC,CRect(0,0,nWidth,nHeight),CRect(0,0,nWidth,nHeight),SRCCOPY);&&&&HBITMAP&hBitmap=(HBITMAP)memDC.SelectObject(pOld-&m_hObject);&&&&&img.ReleaseDC();&&
&span style=&font-size:14&&
img.Load(filePath);
// 获得CImage对象的 CDC
HDC hDC=img.GetDC();
CDC *pDC=CDC::FromHandle(hDC);
CB// 只是创建了位图对象,但还没有将位图对象与位图资源联系起来
bmp.CreateCompatibleBitmap(pDC,nWidth,nHeight); // 创建新的位图资源
CDC memDC;
memDC.CreateCompatibleDC(pDC);
CBitmap *pOld=memDC.SelectObject(&bmp);
// 将img图像绘制到bmp中
::SetStretchBltMode(memDC.m_hDC,HALFTONE);
::SetBrushOrgEx(memDC.m_hDC,0,0,NULL);
img.StretchBlt(memDC.m_hDC,CRect(0,0,nWidth,nHeight)/*DestRect*/,CRect(0,0,nWidth,nHeight)/*SourceRect*/,SRCCOPY);
HBITMAP hBitmap=(HBITMAP)memDC.SelectObject(pOld-&m_hObject); // 获得新创建的位图资源句柄
img.ReleaseDC();
5 将位图资源与对象进行分离
inline&HBITMAP&CImage::Detach()&throw()&&{&&&&&&HBITMAP&hB&&&&&&&&ATLASSUME(&m_hBitmap&!=&NULL&);&&&&&&ATLASSUME(&m_hDC&==&NULL&);&&&&&&&&hBitmap&=&m_hB&&&&&&m_hBitmap&=&NULL;&&&&&&m_pBits&=&NULL;&&&&&&m_nWidth&=&0;&&&&&&m_nHeight&=&0;&&&&&&m_nBPP&=&0;&&&&&&m_nPitch&=&0;&&&&&&m_iTransparentColor&=&-1;&&&&&&m_bHasAlphaChannel&=&false;&&&&&&m_bIsDIBSection&=&false;&&&&&&&&return(&hBitmap&);&&}&&
&span style=&font-size:14&&inline HBITMAP CImage::Detach() throw()
HBITMAP hB
ATLASSUME( m_hBitmap != NULL );
ATLASSUME( m_hDC == NULL );
hBitmap = m_hB
m_hBitmap = NULL;
m_pBits = NULL;
m_nWidth = 0;
m_nHeight = 0;
m_nBPP = 0;
m_nPitch = 0;
m_iTransparentColor = -1;
m_bHasAlphaChannel =
m_bIsDIBSection =
return( hBitmap );
6&释放资源
CBitmap 使用DeleteObject()来主动释放掉位图资源
CImage&& 没有DeleteObject()函数 ,而是用Destroy()函数来主动释放位图资源
inline&void&CImage::Destroy()&throw()&&{&&&&&&HBITMAP&hB&&&&&&&&if(&m_hBitmap&!=&NULL&)&&&&&&{&&&&&&&&&&hBitmap&=&Detach();&&&&&&&&&&::DeleteObject(&hBitmap&);&&&&&&&&}&&}&&
&span style=&font-size:14&&inline void CImage::Destroy() throw()
HBITMAP hB
if( m_hBitmap != NULL )
hBitmap = Detach();
::DeleteObject( hBitmap );
//释放位图资源
CBitmap 析构时,会自动释放掉所占用的位图资源
CImage 析构时,也会自动释放掉所占用的位图资源
inline&CImage::~CImage()&throw()&&{&&&&&&Destroy();&&&&&&&s_initGDIPlus.DecreaseCImageCount();&&}&&
&span style=&font-size:14&&inline CImage::~CImage() throw()
Destroy(); //释放掉所占用的位图资源
s_initGDIPlus.DecreaseCImageCount();
7 读写图像数据
主要用到3个函数 :
1 )GetBits() 获得数据区的指针
Retrieves a pointer to the actual bit values of a given pixel in a bitmap.
void* GetBits( ) throw( );
inline&void*&CImage::GetBits()&throw()&&{&&&&&&ATLASSUME(&m_hBitmap&!=&NULL&);&&&&&&ATLASSERT(&IsDIBSection()&);&&&&&&&&return(&m_pBits&);&&}&&
&span style=&font-size:14&&inline void* CImage::GetBits() throw()
ATLASSUME( m_hBitmap != NULL );
ATLASSERT( IsDIBSection() );
return( m_pBits );
A pointer to the bitmap buffer. If the bitmap is a bottom-up DIB, the pointer points near the end of the buffer. If the bitmap is a top-down DIB, the pointer points to the first byte of the buffer.
Using this pointer, along with the value returned by
, you can locate and change individual pixels in an image.
&注意: 由GetBits()取得的指针不一定是图片数据的起始行,必须结合GetPitch()的值来确定起始行位置
2)GetPitch()
inline&int&CImage::GetPitch()&const&throw()&&{&&&&&&ATLASSUME(&m_hBitmap&!=&NULL&);&&&&&&ATLASSERT(&IsDIBSection()&);&&&&&&&&return(&m_nPitch&);&&}&&
&span style=&font-size:14&&inline int CImage::GetPitch() const throw()
ATLASSUME( m_hBitmap != NULL );
ATLASSERT( IsDIBSection() );
return( m_nPitch );
获得图像数据每一行的字节数
The pitch of the image. If the return value is negative, the bitmap is a bottom-up DIB and its origin is the lower left corner. If the return value is positive, the bitmap is a top-down DIB and its origin is the upper left corner.
GetBits 与 GetPitch 关系:
当GetPitch()&0时,GetBits()获得的指针指向最后一行
当GetPitch()&0时,GetBits()获得的指针指向第一行
图像数据首行地址:
BYTE&*pData=NULL;&&&&if(img.GetPitch()&0)&&&&&&&&pData=(BYTE*)img.GetBits()+(img.GetPitch()*(img.GetHeight()-1));&&&&else&&&&&&pData=(BYTE*)img.GetBits();&&
&span style=&font-size:14&& BYTE *pData=NULL;
if(img.GetPitch()&0)
pData=(BYTE*)img.GetBits()+(img.GetPitch()*(img.GetHeight()-1));
pData=(BYTE*)img.GetBits();
BYTE&*pData=NULL;&&if(img.GetPitch()&0)&&&&&&&&pData=(BYTE&*)img.GetPixelAddress(img.GetHeight()-1,0);&&&&else&&&&&&&&pData=(BYTE&*)img.GetPixelAddress(0,0);&&
&span style=&font-size:14&& BYTE *pData=NULL;
if(img.GetPitch()&0)
pData=(BYTE *)img.GetPixelAddress(img.GetHeight()-1,0);
pData=(BYTE *)img.GetPixelAddress(0,0);&/span&
3)GetBPP() 返回每个像素所占的bit数
inline&int&CImage::GetBPP()&const&throw()&&{&&&&&&ATLASSUME(&m_hBitmap&!=&NULL&);&&&&&&&&return(&m_nBPP&);&&}&&
&span style=&font-size:14&&inline int CImage::GetBPP() const throw()
ATLASSUME( m_hBitmap != NULL );
return( m_nBPP );
The number of bits per pixel.
This value determines the number of bits that define each pixel and the maximum number of colors in the bitmap
一个综合例子:
void&CMyImage::Negatives(void)&&{&&&&&&int&i,&j;&&&&&&&&&&&&&&int&nRowBytes&=&GetPitch();&&&&&&int&nWidth&=&GetWidth();&&&&&&int&nHeight&=&GetHeight();&&&&&&&&&&&&&&&&int&nClrCount&=&GetBPP()&/&8;&&&&&&LPBYTE&p;&&&&&&for(int&index&=&0;&index&&&nClrC&index++)&&&&&&{&&&&&&&&&&p&=&(LPBYTE)GetBits();&&&&&&&&&&for(i&=&0;&i&&&nH&i++)&&&&&&&&&&{&&&&&&&&&&&&&&for(j&=&0;&j&&&nW&j++)&&&&&&&&&&&&&&{&&&&&&&&&&&&&&&&&&p[j*nClrCount&+&index]&=&255&-&p[j*nClrCount&+&index];&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&p&+=&nRowB&&&&&&&&&&&}&&&&&&}&&}&&
&span style=&font-size:14&&void CMyImage::Negatives(void)
//图像每一行的字节数
int nRowBytes = GetPitch();
int nWidth = GetWidth();
int nHeight = GetHeight();
//每个像素所占的字节数
int nClrCount = GetBPP() / 8;
for(int index = 0; index & nClrC index++)
p = (LPBYTE)GetBits();
for(i = 0; i & nH i++)
for(j = 0; j & nW j++)
p[j*nClrCount + index] = 255 - p[j*nClrCount + index];
//如果nRowBytes&0
则从开始到结尾
//如果nRowBytes&0, 则从结尾到开始
p += nRowB
8 保存到图像文件中
Saves an image as the specified file name and type.
HRESULT Save(
IStream* pStream,
REFGUID guidFileType
) const throw();
HRESULT Save(
LPCTSTR pszFileName,
REFGUID guidFileType= GUID_NULL
inline&HRESULT&CImage::Save(&LPCTSTR&pszFileName,&REFGUID&guidFileType&)&const&throw()&&{&&&&&&if(&!InitGDIPlus()&)&&&&&&{&&&&&&&&&&return(&E_FAIL&);&&&&&&}&&&&&&&&UINT&nE&&&&&&UINT&nB&&&&&&Gdiplus::Status&&&&&&&&&status&=&Gdiplus::GetImageEncodersSize(&&nEncoders,&&nBytes&);&&&&&&if(&status&!=&Gdiplus::Ok&)&&&&&&{&&&&&&&&&&return(&E_FAIL&);&&&&&&}&&&&&&&&USES_CONVERSION_EX;&&&&&&Gdiplus::ImageCodecInfo*&pEncoders&=&static_cast&&Gdiplus::ImageCodecInfo*&&(&_ATL_SAFE_ALLOCA(nBytes,&_ATL_SAFE_ALLOCA_DEF_THRESHOLD)&);&&&&&&&&if(&pEncoders&==&NULL&)&&&&&&&&&&return&E_OUTOFMEMORY;&&&&&&&&status&=&Gdiplus::GetImageEncoders(&nEncoders,&nBytes,&pEncoders&);&&&&&&if(&status&!=&Gdiplus::Ok&)&&&&&&{&&&&&&&&&&return(&E_FAIL&);&&&&&&}&&&&&&&&CLSID&clsidEncoder&=&CLSID_NULL;&&&&&&if(&guidFileType&==&GUID_NULL&)&&&&&&{&&&&&&&&&&&&&&&&&&&&clsidEncoder&=&FindCodecForExtension(&::PathFindExtension(&pszFileName&),&pEncoders,&nEncoders&);&&&&&&}&&&&&&else&&&&&&{&&&&&&&&&&&&&&&&&&&&clsidEncoder&=&FindCodecForFileType(&guidFileType,&pEncoders,&nEncoders&);&&&&&&}&&&&&&if(&clsidEncoder&==&CLSID_NULL&)&&&&&&{&&&&&&&&&&return(&E_FAIL&);&&&&&&}&&&&&&&&LPCWSTR&pwszFileName&=&T2CW_EX(&pszFileName,&_ATL_SAFE_ALLOCA_DEF_THRESHOLD&);&&#ifndef&_UNICODE&&&&&&if(&pwszFileName&==&NULL&)&&&&&&&&&&return&E_OUTOFMEMORY;&&#endif&//&_UNICODE&&&&&&if(&m_bHasAlphaChannel&)&&&&&&{&&&&&&&&&&ATLASSUME(&m_nBPP&==&32&);&&&&&&&&&&Gdiplus::Bitmap&bm(&m_nWidth,&m_nHeight,&m_nPitch,&PixelFormat32bppARGB,&static_cast&&BYTE*&&(&m_pBits&)&);&&&&&&&&&&status&=&bm.Save(&pwszFileName,&&clsidEncoder,&NULL&);&&&&&&&&&&if(&status&!=&Gdiplus::Ok&)&&&&&&&&&&{&&&&&&&&&&&&&&return(&E_FAIL&);&&&&&&&&&&}&&&&&&}&&&&&&else&&&&&&{&&&&&&&&&&Gdiplus::Bitmap&bm(&m_hBitmap,&NULL&);&&&&&&&&&&status&=&bm.Save(&pwszFileName,&&clsidEncoder,&NULL&);&&&&&&&&&&if(&status&!=&Gdiplus::Ok&)&&&&&&&&&&{&&&&&&&&&&&&&&return(&E_FAIL&);&&&&&&&&&&}&&&&&&}&&&&&&&&return(&S_OK&);&&}&&
&span style=&font-size:14&&inline HRESULT CImage::Save( LPCTSTR pszFileName, REFGUID guidFileType ) const throw()
if( !InitGDIPlus() )
return( E_FAIL );
Gdiplus::S
status = Gdiplus::GetImageEncodersSize( &nEncoders, &nBytes );
if( status != Gdiplus::Ok )
return( E_FAIL );
USES_CONVERSION_EX;
Gdiplus::ImageCodecInfo* pEncoders = static_cast& Gdiplus::ImageCodecInfo* &( _ATL_SAFE_ALLOCA(nBytes, _ATL_SAFE_ALLOCA_DEF_THRESHOLD) );
if( pEncoders == NULL )
return E_OUTOFMEMORY;
status = Gdiplus::GetImageEncoders( nEncoders, nBytes, pEncoders );
if( status != Gdiplus::Ok )
return( E_FAIL );
CLSID clsidEncoder = CLSID_NULL;
if( guidFileType == GUID_NULL )
// Determine clsid from extension
clsidEncoder = FindCodecForExtension( ::PathFindExtension( pszFileName ), pEncoders, nEncoders );
// Determine clsid from file type
clsidEncoder = FindCodecForFileType( guidFileType, pEncoders, nEncoders );
if( clsidEncoder == CLSID_NULL )
return( E_FAIL );
LPCWSTR pwszFileName = T2CW_EX( pszFileName, _ATL_SAFE_ALLOCA_DEF_THRESHOLD );
#ifndef _UNICODE
if( pwszFileName == NULL )
return E_OUTOFMEMORY;
#endif // _UNICODE
if( m_bHasAlphaChannel )
ATLASSUME( m_nBPP == 32 );
Gdiplus::Bitmap bm( m_nWidth, m_nHeight, m_nPitch, PixelFormat32bppARGB, static_cast& BYTE* &( m_pBits ) );
status = bm.Save( pwszFileName, &clsidEncoder, NULL );
if( status != Gdiplus::Ok )
return( E_FAIL );
Gdiplus::Bitmap bm( m_hBitmap, NULL );
status = bm.Save( pwszFileName, &clsidEncoder, NULL );
if( status != Gdiplus::Ok )
return( E_FAIL );
return( S_OK );
A pointer to a stream containing the file name for the image.
pszFileName
A pointer to the file name for the image.
guidFileType
The file type to save the image as. Can be one of the following:
ImageFormatBMP&&&An uncompressed bitmap image.
ImageFormatPNG&&&A Portable Network Graphic (PNG) compressed image.
ImageFormatJPEG&&&A JPEG compressed image.
ImageFormatGIF&&&A GIF compressed image.
Call this function to save the image using a specified name and type. If the
guidFileType parameter is not included, the file name's file extension will be used to determine the image format. If no extension is provided, the image will be saved in BMP format.
MSDN例子:
&&Copy&Code&&&&&int&_tmain(int&argc,&_TCHAR*&argv[])&&{&&&&&CImage&&&&&&&&&&&myimage.Load(&image.bmp&);&&&&&&&&&&&&&&myimage.Save(&c:\image1.bmp&);&&&&&&&&&&myimage.Save(&c:\image2&,ImageFormatBMP);&&&&&&&&&&myimage.Save(&c:\image3.jpg&);&&&&&&&&&&myimage.Save(&c:\image4.jpg&,ImageFormatBMP);&&&&&return&0;&&}&&&&&
&span style=&font-size:14&&
// Demonstrating saving various file formats
int _tmain(int argc, _TCHAR* argv[])
// load existing image
myimage.Load(&image.bmp&);
// save an image in BMP format
myimage.Save(&c:\image1.bmp&);
// save an image in BMP format
myimage.Save(&c:\image2&,ImageFormatBMP);
// save an image in JPEG format
myimage.Save(&c:\image3.jpg&);
// save an image in BMP format, even though jpg file extension is used
myimage.Save(&c:\image4.jpg&,ImageFormatBMP);
&9 应用实例: 将两个图像合并为一个新的图像
&&CString&img1P&&CString&img2P&&CString&img3P&&&&img1Path=_T(&1.bmp&);&&img2Path=_T(&2.bmp&);&&img3Path=_T(&3.bmp&);&&&&&&&&CImage&img1,img2,img3;&&&&img1.Load(img1Path);&&img2.Load(img2Path);&&&&&&CBitmap&&&CDC&memDC;&&HDC&hDC=NULL;&&CDC&*pDC=NULL;&&CBitmap&*pOld=NULL;&&HBITMAP&hBitmap=NULL;&&&&&&&&hDC=img1.GetDC();&&pDC=CDC::FromHandle(hDC);&&bmp.DeleteObject();&&bmp.CreateCompatibleBitmap(pDC,img1.GetWidth()/2,img1.GetHeight());&&memDC.DeleteDC();&&memDC.CreateCompatibleDC(pDC);&&pOld=memDC.SelectObject(&bmp);&&&&&&::SetStretchBltMode(memDC.m_hDC,HALFTONE);&&::SetBrushOrgEx(memDC.m_hDC,0,0,NULL);&&&&&&CRgn&rectR&&rectRgn.CreateRectRgn(0,0,img1.GetWidth()/2,img1.GetHeight());&&CBrush&&&brush.CreateSolidBrush(RGB(255,255,255));&&memDC.FillRgn(&rectRgn,&brush);&&&&&&&&img1.StretchBlt(memDC.m_hDC,CRect(0,0,img1.GetWidth()/2,img1.GetHeight()/2),CRect(0,0,img1.GetWidth(),img1.GetHeight()),SRCCOPY);&&img2.StretchBlt(memDC.m_hDC,CRect(0,img1.GetHeight()/2,img1.GetWidth()/2,img1.GetHeight()),CRect(0,0,img2.GetWidth(),img2.GetHeight()),SRCCOPY);&&&&hBitmap=(HBITMAP)memDC.SelectObject(pOld-&m_hObject);&&img3.Attach(hBitmap);&&img3.Save(img3Path);&&&&&img1.ReleaseDC();&&img1.Destroy();&&img2.Destroy();&&img3.Destroy();&&
&span style=&font-size:14&& //图像路径
CString img1P
CString img2P
CString img3P
img1Path=_T(&1.bmp&);
img2Path=_T(&2.bmp&);
img3Path=_T(&3.bmp&);
// 将 图片1、2 合并成图片3
CImage img1,img2,img3;
img1.Load(img1Path);
img2.Load(img2Path);
CDC memDC;
HDC hDC=NULL;
CDC *pDC=NULL;
CBitmap *pOld=NULL;
HBITMAP hBitmap=NULL;
//创建位图
hDC=img1.GetDC();
pDC=CDC::FromHandle(hDC);
bmp.DeleteObject();
bmp.CreateCompatibleBitmap(pDC,img1.GetWidth()/2,img1.GetHeight());
memDC.DeleteDC();
memDC.CreateCompatibleDC(pDC);
pOld=memDC.SelectObject(&bmp);
::SetStretchBltMode(memDC.m_hDC,HALFTONE);
::SetBrushOrgEx(memDC.m_hDC,0,0,NULL);
// 背景置白色
CRgn rectR
rectRgn.CreateRectRgn(0,0,img1.GetWidth()/2,img1.GetHeight());
brush.CreateSolidBrush(RGB(255,255,255));
memDC.FillRgn(&rectRgn,&brush);
img1.StretchBlt(memDC.m_hDC,CRect(0,0,img1.GetWidth()/2,img1.GetHeight()/2),CRect(0,0,img1.GetWidth(),img1.GetHeight()),SRCCOPY);
img2.StretchBlt(memDC.m_hDC,CRect(0,img1.GetHeight()/2,img1.GetWidth()/2,img1.GetHeight()),CRect(0,0,img2.GetWidth(),img2.GetHeight()),SRCCOPY);
hBitmap=(HBITMAP)memDC.SelectObject(pOld-&m_hObject);
img3.Attach(hBitmap);// 载入位图资源
img3.Save(img3Path); // 保存新的位图
img1.ReleaseDC();
img1.Destroy();
img2.Destroy();
img3.Destroy();
&&相关文章推荐
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:848905次
积分:11436
积分:11436
排名:第1194名
原创:225篇
转载:644篇
评论:64条

我要回帖

更多关于 象棋许银川直播 的文章

 

随机推荐