知识大全 基于VC.NET的GDI+编程之CImage

Posted

篇首语:蹉跎莫遣韶光老,人生唯有读书好。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 基于VC.NET的GDI+编程之CImage相关的知识,希望对你有一定的参考价值。

基于VC.NET的GDI+编程之CImage  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

  我们知道 Visual C++的CBitmap类和静态图片控件的功能是比较弱的 它只能显示出在资源中的图标 位图 光标以及图元文件的内容 而不像VB中的Image控件可以显示出绝大多数的外部图像文件(BMP GIF JPEG等) 因此 想要在对话框或其他窗口中显示外部图像文件则只能借助于第三方提供的控件或代码 现在 MFC和ATL共享的新类CImage为图像处理提供了许多相应的方法 这使得Visual C++在图像方面的缺憾一去不复返了   CImage类概述  CImage是MFC和ATL共享的新类 它能从外部磁盘中调入一个JPEG GIF BMP和PNG格式的图像文件加以显示 而且这些文件格式可以相互转换 由于CImage在不同的Windows操作系统中其某些性能是不一样的 因此在使用时要特别注意 例如 CImage::PlgBlt和CImage::MaskBlt只能在 Windows NT 或更高版本中使用 但不能运行在Windows / 应用程序中 CImage::AlphaBlend和CImage::TransparentBlt也只能在 Windows / 或其更高版本中使用 即使在Windows 运行程序还必须将stdafx h文件中的WINVER和_WIN _WINNT的预定义修改成 x 才能正常使用   CImage封装了DIB(设备无关位图)的功能 因而可以让我们能够处理每个位图像素 它具有下列最酷特性    AlphaBlend支持像素级的颜色混合 从而实现透明和半透明的效果    PlgBlt能使一个矩形区域的位图映射到一个平行四边形区域中 而且还可能使用位屏蔽操作    TransparentBlt在目标区域中产生透明图像 SetTransparentColor用来设置某种颜色是透明色    MaskBlt在目标区域中产生源位图与屏蔽位图合成的效果

  使用CImage的一般方法  使用CImage的一般方法是这样的过程   ( ) 打开应用程序的stdafx h文件添加CImage类的包含文件 #include <atlimage h>  ( ) 定义一个CImage类对象 然后调用CImage::Load方法装载一个外部图像文件   ( ) 调用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是实现这样的功能 当选择 文件 ò 打开 菜单命令后 弹出一个文件打开对话框 当选定一个图像文件后 就会在窗口客户区中显示该图像文件内容 这个示例的具体步骤如下   ( ) 创建一个默认的单文档程序项目Ex_Image   ( ) 打开stdafx h文件中添加CImage类的包含文件atlimage h   ( ) 在CEx_ImageView类添加ID_FILE_OPEN的MAND事件映射程序 并添加下列代码

   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

  ( ) 定位到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 ); 

  ( ) 打开Ex_ImageView h文件 添加一个公共的成员数据m_Image

   public:CImage m_Image;

  ( ) 编译并运行 单击 打开 工具按钮 在弹出的对话框中指定一个图像文件后 单击 打开 按钮 其结果如图 所示

  

  将图片用其它格式保存  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的MAND事件映射程序 并添加下列代码

   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 == )    switch (dlg m_ofn nFilterIndex)     case :    strExtension = bmp ; break;   case :    strExtension = jpg ; break;   case :    strExtension = gif ; break;   case :    strExtension = png ; break;   default:    break;    strFileName = strFileName + + strExtension;  // 图像保存 HRESULT hResult = m_Image Save(strFileName); if (FAILED(hResult))   MessageBox( 保存图像文件失败! );

  柔化和锐化处理  在图像处理中 我们通常用一些数学手段 对图像进行除去噪声 强调或抽取轮廓特征等图像空间的变换 所谓 图像空间的变换 是借助于一个称之为模板的局部像素域来完成的 不同的模板具有不同的图像效果    . 柔化  图像的柔化是除去图像中点状噪声的一个有效方法 所谓柔化 是指使图像上任何一个像素与其相邻像素的颜色值的大小不会出现陡突的一种处理方法 设在一个 x 的模板中其系数为

  中间有底纹的表示中心元素 即用那个元素作为处理后的元素 很明显 上述模板(称之为Box模板)是将图像上每个像素用它近旁(包括它本身)的 个像素的平均值取代 这样处理的结果在除噪的同时 也降低图像的对比度 使图像的轮廓模糊 为了避免这一缺陷 我们对各点引入加权系数 将原来的模板改为   新的模板可一方面除去点状噪声 同时能较好地保留原图像的对比度 因此该模板得到了广泛的应用 由于这个模板是通过二维高斯(Gauss)函数得到的 故称为高斯模板    . 锐化  锐化和柔化恰恰相反 它通过增强高频分量减少图像中的模糊 因此又称为高通滤波 锐化处理在增强图像边缘效果的同时增加了图像的噪声 常用的锐化模板是拉普拉斯模板   用此模板处理后的图像 轮廓线条将明显得到增强 轮廓线以外的部分将变得较暗 而轮廓线部分将变得比较明亮   使用程序对模板进行运算时 要考虑到溢出点的处理 所谓溢出点 指的是大于 或小于 的点 处理时 可令大于 的点取 而小于 的点取其正值    . 实现代码  实现柔化和锐化时 我们先调用CImage::GetPixel来依次读取相应的像素 然后用柔化和锐化模板进行处理 最后调用CImage::SetPixel函数将处理后的像素写回到CImage对象中 具体的代码如下 void FilterImage(CImage* image int nType) if (image >IsNull())  return; int smoothGauss[ ] = ; // 高斯模板 int sharpLaplacian[ ] = ; // 拉普拉斯模板 int opTemp[ ]; float aver; // 系数 if ( nType > ) nType = ; switch( nType )  case : // 高斯模板   aver = (float)( / );   memcpy( opTemp smoothGauss *sizeof(int));   break;  case : // 拉普拉斯模板   aver = ;   memcpy( opTemp sharpLaplacian *sizeof(int));   break;  int i j; int nWidth = image >GetWidth(); int nHeight = image >GetHeight(); for (i = ; i < nWidth ; i++)  for (j = ; j < nHeight ; j++)   int rr = gg = bb = ;   int index = ;   for (int col = ; col <= ; col++)    for (int row = ; row <= ; row++)     COLORREF clr = image >GetPixel( i+row j+col);     rr += GetRValue(clr) * opTemp[index];     gg += GetGValue(clr) * opTemp[index];     bb += GetBValue(clr) * opTemp[index];     index++;            rr = (int)(rr*aver);   gg = (int)(gg*aver);   bb = (int)(bb*aver);   // 处理溢出点  if ( rr > ) rr = ;  else if ( rr < ) rr = rr;  if ( gg > ) gg = ;  else if ( gg < ) gg = gg;  if ( bb > ) bb = ;  else if ( bb < ) bb = bb;  // 错位重写以避免前一个像素被新的像素覆蓋  image >SetPixel( i j RGB(rr gg bb));    图 是使用上述代码将某个图像处理后的结果  

  变成黑白图片  由于许多图像文件使用颜色表来发挥显示设备的色彩显示能力 因而将一张彩色图片变成黑色图片时需要调用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= ; x<maxX; x++)    for (int y= ; y<maxY; y++)     pixel = image >GetPixel(x y);    r = GetRValue(pixel);    g = GetGValue(pixel);    b = GetBValue(pixel);    avg = (int)((r + g + b)/ );    image >SetPixelRGB(x y avg avg avg);       else   // 获取并修改颜色表  int MaxColors = image >GetMaxColorTableEntries();  RGBQUAD* ColorTable;  ColorTable = new RGBQUAD[MaxColors];  image >GetColorTable( MaxColors ColorTable);  for (int i= ; i<MaxColors; i++)     int avg = (ColorTable[i] rgbBlue + ColorTable[i] rgbGreen + ColorTable[i] rgbRed)/ ;   ColorTable[i] rgbBlue = avg;   ColorTable[i] rgbGreen = avg;   ColorTable[i] rgbRed = avg;    image >SetColorTable( MaxColors ColorTable);  delete(ColorTable); 

cha138/Article/program/net/201311/13155

相关参考

知识大全 C# GDI+编程之基础篇

C#GDI+编程之基础篇  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  一关于GDI+  从本质

知识大全 C# GDI+绘图高级编程

C#GDI+绘图高级编程  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  一般来说Windows的

知识大全 GDI+编程的10个基本技巧

GDI+编程的10个基本技巧  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  创建绘图表面创建绘图

知识大全 VC++.NET开发环境整合技巧

VC++.NET开发环境整合技巧  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  主窗口内的每一个

知识大全 用VC.NET制作启动屏幕的新方法

用VC.NET制作启动屏幕的新方法  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  在利用VC+编

知识大全 VC#.Net中浏览Crystal Report

VC#.Net中浏览CrystalReport  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!&nb

知识大全 VC# .Net中使用Crystal Report(一)

VC#.Net中使用CrystalReport(一)  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

知识大全 VC# .Net中使用Crystal Report(二)

VC#.Net中使用CrystalReport(二)  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

知识大全 VC.NET索引对查询条件顺序的影响

VC.NET索引对查询条件顺序的影响  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  环境SqlS

知识大全 使用 VC.net 轻松实现按钮控件自绘

使用VC.net轻松实现按钮控件自绘  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  使用&nbs