Visual C++的CBitmap类的功能是比较弱的,它只能显示出在资源中的图标、位图、光标以及图元文件的内容,而不像VB中的Image控件可以显示出绝大多数的外部图像文件(BMP、GIF、JPEG等)。如果想要在对话框或其他窗口中显示外部图像文件则只能借助于第三方提供的控件或代码,未免过于繁琐.
现在,.net引入了一个功能非常强大的新类 ----- CImage.有了CImage类,Visual C++在图像方面的缺憾将一去不复返。CImage是MFC和ATL共享的新类,它能从外部磁盘中调入一个JPEG、GIF、BMP和PNG格式的图像文件加以显示,而且这些文件格式可以相互转换。例如通过简单的几句,就可以实现CImage类和CBitmap类实例的:
HBITMAP hBitmap=image.Detach();
CBitmap bmp;
bmp.Attach(hBitmap);
这样一来,就又回归到以前操纵CBitmap的方式了.CImage本身封装了DIB(设备无关位图)的功能,因而能够处理每个位图像素。
它具有下列最酷特性:
1、AlphaBlend支持像素级的颜色混合,从而实现透明和半透明的效果。
2、PlgBlt能使一个矩形区域的位图映射到一个平行四边形区域中,而且还可能使用位屏蔽操作。
3、TransparentBlt在目标区域中产生透明图像,SetTransparentColor用来设置某种颜色是透明色。
4、MaskBlt在目标区域中产生源位图与屏蔽位图合成的效果。
由于CImage在不同的Windows操作系统中其某些性能是不一样的,因此在使用时要特别注意。例如,CImage::PlgBlt和 CImage::MaskBlt只能在 Windows NT 4.0 或更高版本中使用,但不能运行在Windows 95/98 应用程序中。CImage::AlphaBlend和CImage::TransparentBlt也只能在 Windows 2000/98或其更高版本中使用。即使在Windows 2000运行程序还必须将stdafx.h文件中的WINVER和_WIN32_WINNT的预定义修改成0x0500才能正常使用。
使用CImage的一般方法
使用CImage的一般方法是这样的过程:
(1) 打开应用程序的stdafx.h文件添加CImage类的包含文件:
#include <atlimage.h>
(2) 定义一个CImage类对象,然后调用CImage::Load方法装载一个外部图像文件。
(3) 调用CImage::Draw方法绘制图像。Draw方法具有如下定义:
BOOL Draw( HDC hDestDC, int xDest, int yDest,
int nDestWidth, int nDestHeight, int xSrc, int ySrc,
int nSrcWidth, int nSrcHeight );
BOOL Draw( HDC hDestDC, const RECT& rectDest, const RECT& rectSrc );
BOOL Draw( HDC hDestDC, int xDest, int yDest );
BOOL Draw( HDC hDestDC, const POINT& pointDest );
BOOL Draw( HDC hDestDC, int xDest, int yDest,
int nDestWidth, int nDestHeight );
BOOL Draw( HDC hDestDC, const RECT& rectDest );
其中,hDestDC用来指定绘制的目标设备环境句柄,(xDest, yDest)和pointDest用来指定图像显示的位置,这个位置和源图像的左上角点相对应。nDestWidth和nDestHeight分别指定图像要显示的高度和宽度,xSrc、ySrc、nSrcWidth和nSrcHeight用来指定要显示的源图像的某个部分所在的位置和大小。 rectDest和rectSrc分别用来指定目标设备环境上和源图像所要显示的某个部分的位置和大小。
需要说明的是,Draw方法综合了StretchBlt、TransparentBlt和AlphaBlend函数的功能。默认时,Draw的功能和 StretchBlt相同。但当图像含有透明色或Alpha通道时,它的功能又和TransparentBlt、AlphaBlend相同。因此,在一般情况下,我们都应该尽量调用CImage::Draw方法来绘制图像。
例如,下面的示例Ex_Image是实现这样的功能:当选择"文件"ò"打开"菜单命令后,弹出一个文件打开对话框。当选定一个图像文件后,就会在窗口客户区中显示该图像文件内容。这个示例的具体步骤如下:
(1) 创建一个默认的单文档程序项目Ex_Image。
(2) 打开stdafx.h文件中添加CImage类的包含文件atlimage.h。
(3) 在CEx_ImageView类添加ID_FILE_OPEN的COMMAND事件映射程序,并添加下列代码:
void CEx_ImageView::OnFileOpen()
{
CString strFilter;
CSimpleArray<GUID> aguidFileTypes;
HRESULT hResult;
// 获取CImage支持的图像文件的过滤字符串
hResult = m_Image.GetExporterFilterString(strFilter,aguidFileTypes,
_T( "All Image Files") );
if (FAILED(hResult)) {
MessageBox("GetExporterFilter调用失败!");
return;
}
CFileDialog dlg(TRUE, NULL, NULL, OFN_FILEMUSTEXIST, strFilter);
if(IDOK != dlg.DoModal())
return;
m_Image.Destroy();
// 将外部图像文件装载到CImage对象中
hResult = m_Image.Load(dlg.GetFileName());
if (FAILED(hResult)) {
MessageBox("调用图像文件失败!");
return;
}
// 设置主窗口标题栏内容
CString str;
str.LoadString(AFX_IDS_APP_TITLE);
AfxGetMainWnd()->SetWindowText(str + " - " +dlg.GetFileName());
Invalidate(); // 强制调用OnDraw
}
(4) 定位到CEx_ImageView::OnDraw函数处,添加下列代码:
void CEx_ImageView::OnDraw(CDC* pDC)
{
CEx_ImageDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!m_Image.IsNull()) {
m_Image.Draw(pDC->m_hDC,0,0);
}
}
(5) 打开Ex_ImageView.h文件,添加一个公共的成员数据m_Image:
public:
CImage m_Image;
(6) 编译并运行。单击"打开"工具按钮,在弹出的对话框中指定一个图像文件后,单击"打开"按钮,其结果如图7.21所示。
将图片用其它格式保存
CImage::Save方法能将一个图像文件按另一种格式来保存,它的原型如下:
HRESULT Save( LPCTSTR pszFileName, REFGUID guidFileType= GUID_NULL);
其中,pszFileName用来指定一个文件名,guidFileType用来指定要保存的图像文件格式,当为GUID_NULL时,其文件格式由文件的扩展名来决定,这也是该函数的默认值。它还可以是GUID_BMPFile(BMP文件格式)、GUID_PNGFile(PNG文件格式)、 GUID_JPEGFile(JPEG文件格式)和GUID_GIFFile(GIF文件格式)。
例如,下面的过程是在Ex_Image示例基础上进行的,我们在CEx_ImageView类添加ID_FILE_SAVE_AS的COMMAND事件映射程序,并添加下列代码:
void CEx_ImageView::OnFileSaveAs()
{
if (m_Image.IsNull()) {
MessageBox("你还没有打开一个要保存的图像文件!");
return;
}
CString strFilter;
strFilter = "位图文件|*.bmp|JPEG 图像文件|*.jpg| \
GIF 图像文件|*.gif|PNG 图像文件|*.png||";
CFileDialog dlg(FALSE,NULL,NULL,NULL,strFilter);
if ( IDOK != dlg.DoModal())
return;
// 如果用户没有指定文件扩展名,则为其添加一个
CString strFileName;
CString strExtension;
strFileName = dlg.m_ofn.lpstrFile;
if (dlg.m_ofn.nFileExtension == 0)
{
switch (dlg.m_ofn.nFilterIndex)
{
case 1:
strExtension = "bmp"; break;
case 2:
strExtension = "jpg"; break;
case 3:
strExtension = "gif"; break;
case 4:
strExtension = "png"; break;
default:
break;
}
strFileName = strFileName + '.' + strExtension;
}
// 图像保存
HRESULT hResult = m_Image.Save(strFileName);
if (FAILED(hResult))
MessageBox("保存图像文件失败!");
将图片用其它格式保存
CImage::Save方法能将一个图像文件按另一种格式来保存,它的原型如下:
HRESULT Save( LPCTSTR pszFileName, REFGUID guidFileType= GUID_NULL);
其中,pszFileName用来指定一个文件名,guidFileType用来指定要保存的图像文件格式,当为GUID_NULL时,其文件格式由文件的扩展名来决定,这也是该函数的默认值。它还可以是GUID_BMPFile(BMP文件格式)、GUID_PNGFile(PNG文件格式)、 GUID_JPEGFile(JPEG文件格式)和GUID_GIFFile(GIF文件格式)。
例如,下面的过程是在Ex_Image示例基础上进行的,我们在CEx_ImageView类添加ID_FILE_SAVE_AS的COMMAND事件映射程序,并添加下列代码:
void CEx_ImageView::OnFileSaveAs()
{
if (m_Image.IsNull()) {
MessageBox("你还没有打开一个要保存的图像文件!");
return;
}
CString strFilter;
strFilter = "位图文件|*.bmp|JPEG 图像文件|*.jpg| \
GIF 图像文件|*.gif|PNG 图像文件|*.png||";
CFileDialog dlg(FALSE,NULL,NULL,NULL,strFilter);
if ( IDOK != dlg.DoModal())
return;
// 如果用户没有指定文件扩展名,则为其添加一个
CString strFileName;
CString strExtension;
strFileName = dlg.m_ofn.lpstrFile;
if (dlg.m_ofn.nFileExtension == 0)
{
switch (dlg.m_ofn.nFilterIndex)
{
case 1:
strExtension = "bmp"; break;
case 2:
strExtension = "jpg"; break;
case 3:
strExtension = "gif"; break;
case 4:
strExtension = "png"; break;
default:
break;
}
strFileName = strFileName + '.' + strExtension;
}
// 图像保存
HRESULT hResult = m_Image.Save(strFileName);
if (FAILED(hResult))
MessageBox("保存图像文件失败!");
变成黑白图片
由于许多图像文件使用颜色表来发挥显示设备的色彩显示能力,因而将一张彩色图片变成黑色图片时需要调用CImage::IsIndexed来判断是否使用颜色表,若是则修改颜色表,否则直接将像素进行颜色设置。例如下面的代码:
void CEx_ImageView::MakeBlackAndwhite(CImage* image)
{
if (image->IsNull()) return;
if (!image->IsIndexed()) {
// 直接修改像素颜色
COLORREF pixel;
int maxY = image->GetHeight(), maxX = image->GetWidth();
byte r,g,b,avg;
for (int x=0; x<maxX; x++) {
for (int y=0; y<maxY; y++) {
pixel = image->GetPixel(x,y);
r = GetRValue(pixel);
g = GetGValue(pixel);
b = GetBValue(pixel);
avg = (int)((r + g + b)/3);
image->SetPixelRGB(x,y,avg,avg,avg);
}
}
} else {
// 获取并修改颜色表
int MaxColors = image->GetMaxColorTableEntries();
RGBQUAD* ColorTable;
ColorTable = new RGBQUAD[MaxColors];
image->GetColorTable(0,MaxColors,ColorTable);
for (int i=0; i<MaxColors; i++)
{
int avg = (ColorTable[i].rgbBlue + ColorTable[i].rgbGreen + ColorTable[i].rgbRed)/3;
ColorTable[i].rgbBlue = avg;
ColorTable[i].rgbGreen = avg;
ColorTable[i].rgbRed = avg;
}
image->SetColorTable(0,MaxColors,ColorTable);
delete(ColorTable);
}
}
转自:http://hi.baidu.com/cauciee/blog/item/3053490994877438e8248822.html
分类: 图形图像处理2011-12-21 09:16 427人阅读 评论(1) 收藏 举报
前言
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 加载位图文件
[cpp] view plaincopyprint?
2 与CBitmap转换
[cpp] view plaincopyprint?
3 获得CImage对象的cdc
[cpp] view plaincopyprint?
4 显示位图
思路: 将CImage对象 绘制在对应的DC中
所使用的函数 BitBlt StretchBlt Draw等
以Draw举例:
[cpp] view plaincopyprint?
Draw performs the same operation as StretchBlt, unless the image contains a transparent color or alpha channel. In that case,Draw performs the same operation as eitherTransparentBlt orAlphaBlend 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:
[cpp] view plaincopyprint?
EXAMPLE 2: 画在另一个位图中
[cpp] view plaincopyprint?
5 将位图资源与对象进行分离
[cpp] view plaincopyprint?
6 释放资源
CBitmap 使用DeleteObject()来主动释放掉位图资源
CImage 没有DeleteObject()函数 ,而是用Destroy()函数来主动释放位图资源
[cpp] view plaincopyprint?
CBitmap 析构时,会自动释放掉所占用的位图资源
CImage 析构时,也会自动释放掉所占用的位图资源
[cpp] view plaincopyprint?
7 读写图像数据
主要用到3个函数 :
1 )GetBits() 获得数据区的指针
Retrieves a pointer to the actual bit values of a given pixel in a bitmap.
void* GetBits( ) throw( );
[cpp] view plaincopyprint?
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 GetPitch, you can locate and change individual pixels in an image.
注意: 由GetBits()取得的指针不一定是图片数据的起始行,必须结合GetPitch()的值来确定起始行位置
2)GetPitch()
[cpp] view plaincopyprint?
获得图像数据每一行的字节数
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()获得的指针指向第一行
图像数据首行地址:
[cpp] view plaincopyprint?
或
[cpp] view plaincopyprint?
3)GetBPP() 返回每个像素所占的bit数
[cpp] view plaincopyprint?
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
一个综合例子:
[cpp] view plaincopyprint?
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 )
[cpp] view plaincopyprint?
A pointer to a stream containing the file name for the image.
A pointer to the file name for the image.
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例子:
[cpp] view plaincopyprint?
9 应用实例: 将两个图像合并为一个新的图像
[cpp] view plaincopyprint?