CImage的学习

CImage的学习程序代码下载处 http download csdn net source 2098910 下载处 http hi baidu com wangleitongx blog item 9063b03e5e20 html 备注 这个程序是在 xp 系统 vs2008 下做的 当初测试没出什么问题 昨天 2014 11 11 我下了程序在 win7 下面测试 出现了评

程序代码下载处:http://download.csdn.net/source/

下载处:http://hi.baidu.com/wangleitongxing/blog/item/9063b03e5e20f3c97c1e71c8.html

备注:这个程序是在xp系统,vs2008下做的,当初测试没出什么问题。

昨天(2014-11-11)我下了程序在win7下面测试,出现了评论里说的问题,解决方法我已经写在评论里面了。主要是因为路径的问题。大家参照着修改测下应该就没问题了。

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 4.0或更高版本中使用,但不能运行在Windows 95/98应用程序中。CImage::AlphaBlend和CImage::TransparentBlt也只能在 Windows 2000/98或其更高版本中使用。即使在Windows 2000运行程序还必须将stdafx.h文件中的WINVER和_WIN32_WINNT的预定义修改成0x0500才能正常使用。

 

CImage封装了DIB(设备无关位图)的功能,因而可以让我们能够处理每个位图像素。它具有下列最酷特性:

1、AlphaBlend支持像素级的颜色混合,从而实现透明和半透明的效果。

2、PlgBlt能使一个矩形区域的位图映射到一个平行四边形区域中,而且还可能使用位屏蔽操作。

3、TransparentBlt在目标区域中产生透明图像,SetTransparentColor用来设置某种颜色是透明色。

4、MaskBlt在目标区域中产生源位图与屏蔽位图合成的效果。

使用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)在view类中添加成员变量CImage m_Image;

CEx_ImageView类添加ID_FILE_OPEN的COMMAND事件映射程序,并添加下列代码:

程序代码:

voidCEx_ImageView::OnFileOpen()//Cyan:添加

{

    // TODO: 在此添加命令处理程序代码

    CString strFilter;

    CSimpleArray<GUID>aguidFileTypes;

    HRESULT hResult;  //获取CImage支持的图像文件的过滤字符串

    hResult=m_Image.GetExporterFilterString(strFilter,aguidFileTypes,_T(“All Image Files”));

    if(FAILED(hResult))

    {

        MessageBox(_T(“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(_T(调用图像文件失败!”));

        return;

    }

    //设置主窗口标题栏内容

    CString str;

    str.LoadString(AFX_IDS_APP_TITLE);

    AfxGetMainWnd()->SetWindowTextW(str+_T(“-“)+dlg.GetFileName());

    Invalidate();//强制调用OnDraw函数

}

(4)定位到CEx_ImageView::OnDraw函数处,添加下列代码:

程序代码:

voidCEx_ImageView::OnDraw(CDC*pDC)

{

    CEx_ImageDoc* pDoc = GetDocument();

    ASSERT_VALID(pDoc);

    //if (!pDoc)

        //return;

    // TODO: 在此处为本机数据添加绘制代码

    // Cyan:添加

    if(!m_Image.IsNull())

    {

        m_Image.Draw(pDC->m_hDC,0,0);

    }

}

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

程序代码:

public:   CImage m_Image;(Cyan:我觉得设置成私有成员比较好)

 (6)编译并运行。单击”打开”工具按钮,在弹出的对话框中指定一个图像文件后,单击”打开”按钮。

将图片用其它格式保存

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事件映射程序,并添加下列代码:

程序代码:

voidCEx_ImageView::OnFileSaveAs()  //Cyan:添加

{

    // TODO: 在此添加命令处理程序代码

    if(m_Image.IsNull())

    {

        MessageBox(_T(请打开要另存的图像!”));

        return;

    }

    CString strFilter;

    strFilter=“bmp位图文件|*.bmp|JPEG图像文件|*.jpg|GIF图像文件|*.gif|PNG图像文件|*.png||”;

    CFileDialog dlg(FALSE,NULL,NULL,NULL,strFilter);

    if(IDOK!=dlg.DoModal())

        return;

    //如果没有指定文件扩展名,则为其添加一个

    CString strFileName,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+_T(“.”)+strExtension;

    }

    //图像保存

    HRESULT hResult=m_Image.Save(strFileName);

    if(FAILED(hResult))

    {

        MessageBox(_T(保存图像文件失败!”));

    }

}

彩色图像转换成灰度图像

由于许多图像文件使用颜色表来发挥显示设备的色彩显示能力,因而将一张彩色图片变成黑色图片时需要调用CImage::IsIndexed来判断是否使用颜色表,若是则修改颜色表,否则直接将像素进行颜色设置。例如下面的代码:

程序代码:

voidCEx_ImageView::OnToGray()//Cyan:添加

{

    // TODO: 在此添加命令处理程序代码

    if(m_Image.IsNull())

        return;

    if(!m_Image.IsIndexed())

    {

        //直接修改像素颜色

        COLORREF pixel;

        int maxY=m_Image.GetHeight();

        int maxX=m_Image.GetWidth();

        byte r,g,b,avg;

        for(int x=0;x<maxX;x++)

        {

             for(int y=0;y<maxY;y++)

             {

                  pixel=m_Image.GetPixel(x,y);

                  r=GetRValue(pixel);

                  g=GetGValue(pixel);

                  b=GetBValue(pixel);

                  avg=(int)(((int)r+g+b)/3);

                  m_Image.SetPixelRGB(x,y,avg,avg,avg);

             }       

        }

    }

    else

    {

        //获取并修改颜色表

        int maxColors=m_Image.GetMaxColorTableEntries();

        RGBQUAD* lpColorTable;

        lpColorTable=newRGBQUAD[maxColors];

        m_Image.GetColorTable(0,maxColors,lpColorTable);

        for(int i=0;i<maxColors;i++)

        {

             int avg=(lpColorTable[i].rgbRed+lpColorTable[i].rgbGreen+lpColorTable[i].rgbBlue)/3;

             lpColorTable[i].rgbRed=avg;

             lpColorTable[i].rgbGreen=avg;

             lpColorTable[i].rgbBlue=avg;

        }

        m_Image.SetColorTable(0,maxColors,lpColorTable);

        delete(lpColorTable);

    }

    Invalidate();//强制调用OnDraw

} 

程序代码下载处:http://download.csdn.net/source/

下载处:http://hi.baidu.com/wangleitongxing/blog/item/9063b03e5e20f3c97c1e71c8.html

备注:这个程序是在xp系统,vs2008下做的,当初测试没出什么问题。

昨天(2014-11-11)我下了程序在win7下面测试,出现了评论里说的问题,解决方法我已经写在评论里面了。主要是因为路径的问题。大家参照着修改测下应该就没问题了。

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 4.0或更高版本中使用,但不能运行在Windows 95/98应用程序中。CImage::AlphaBlend和CImage::TransparentBlt也只能在 Windows 2000/98或其更高版本中使用。即使在Windows 2000运行程序还必须将stdafx.h文件中的WINVER和_WIN32_WINNT的预定义修改成0x0500才能正常使用。

 

CImage封装了DIB(设备无关位图)的功能,因而可以让我们能够处理每个位图像素。它具有下列最酷特性:

1、AlphaBlend支持像素级的颜色混合,从而实现透明和半透明的效果。

2、PlgBlt能使一个矩形区域的位图映射到一个平行四边形区域中,而且还可能使用位屏蔽操作。

3、TransparentBlt在目标区域中产生透明图像,SetTransparentColor用来设置某种颜色是透明色。

4、MaskBlt在目标区域中产生源位图与屏蔽位图合成的效果。

使用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)在view类中添加成员变量CImage m_Image;

CEx_ImageView类添加ID_FILE_OPEN的COMMAND事件映射程序,并添加下列代码:

程序代码:

voidCEx_ImageView::OnFileOpen()//Cyan:添加

{

    // TODO: 在此添加命令处理程序代码

    CString strFilter;

    CSimpleArray<GUID>aguidFileTypes;

    HRESULT hResult;  //获取CImage支持的图像文件的过滤字符串

    hResult=m_Image.GetExporterFilterString(strFilter,aguidFileTypes,_T(“All Image Files”));

    if(FAILED(hResult))

    {

        MessageBox(_T(“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(_T(调用图像文件失败!”));

        return;

    }

    //设置主窗口标题栏内容

    CString str;

    str.LoadString(AFX_IDS_APP_TITLE);

    AfxGetMainWnd()->SetWindowTextW(str+_T(“-“)+dlg.GetFileName());

    Invalidate();//强制调用OnDraw函数

}

(4)定位到CEx_ImageView::OnDraw函数处,添加下列代码:

程序代码:

voidCEx_ImageView::OnDraw(CDC*pDC)

{

    CEx_ImageDoc* pDoc = GetDocument();

    ASSERT_VALID(pDoc);

    //if (!pDoc)

        //return;

    // TODO: 在此处为本机数据添加绘制代码

    // Cyan:添加

    if(!m_Image.IsNull())

    {

        m_Image.Draw(pDC->m_hDC,0,0);

    }

}

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

程序代码:

public:   CImage m_Image;(Cyan:我觉得设置成私有成员比较好)

 (6)编译并运行。单击”打开”工具按钮,在弹出的对话框中指定一个图像文件后,单击”打开”按钮。

将图片用其它格式保存

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事件映射程序,并添加下列代码:

程序代码:

voidCEx_ImageView::OnFileSaveAs()  //Cyan:添加

{

    // TODO: 在此添加命令处理程序代码

    if(m_Image.IsNull())

    {

        MessageBox(_T(请打开要另存的图像!”));

        return;

    }

    CString strFilter;

    strFilter=“bmp位图文件|*.bmp|JPEG图像文件|*.jpg|GIF图像文件|*.gif|PNG图像文件|*.png||”;

    CFileDialog dlg(FALSE,NULL,NULL,NULL,strFilter);

    if(IDOK!=dlg.DoModal())

        return;

    //如果没有指定文件扩展名,则为其添加一个

    CString strFileName,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+_T(“.”)+strExtension;

    }

    //图像保存

    HRESULT hResult=m_Image.Save(strFileName);

    if(FAILED(hResult))

    {

        MessageBox(_T(保存图像文件失败!”));

    }

}

彩色图像转换成灰度图像

由于许多图像文件使用颜色表来发挥显示设备的色彩显示能力,因而将一张彩色图片变成黑色图片时需要调用CImage::IsIndexed来判断是否使用颜色表,若是则修改颜色表,否则直接将像素进行颜色设置。例如下面的代码:

程序代码:

voidCEx_ImageView::OnToGray()//Cyan:添加

{

    // TODO: 在此添加命令处理程序代码

    if(m_Image.IsNull())

        return;

    if(!m_Image.IsIndexed())

    {

        //直接修改像素颜色

        COLORREF pixel;

        int maxY=m_Image.GetHeight();

        int maxX=m_Image.GetWidth();

        byte r,g,b,avg;

        for(int x=0;x<maxX;x++)

        {

             for(int y=0;y<maxY;y++)

             {

                  pixel=m_Image.GetPixel(x,y);

                  r=GetRValue(pixel);

                  g=GetGValue(pixel);

                  b=GetBValue(pixel);

                  avg=(int)(((int)r+g+b)/3);

                  m_Image.SetPixelRGB(x,y,avg,avg,avg);

             }       

        }

    }

    else

    {

        //获取并修改颜色表

        int maxColors=m_Image.GetMaxColorTableEntries();

        RGBQUAD* lpColorTable;

        lpColorTable=newRGBQUAD[maxColors];

        m_Image.GetColorTable(0,maxColors,lpColorTable);

        for(int i=0;i<maxColors;i++)

        {

             int avg=(lpColorTable[i].rgbRed+lpColorTable[i].rgbGreen+lpColorTable[i].rgbBlue)/3;

             lpColorTable[i].rgbRed=avg;

             lpColorTable[i].rgbGreen=avg;

             lpColorTable[i].rgbBlue=avg;

        }

        m_Image.SetColorTable(0,maxColors,lpColorTable);

        delete(lpColorTable);

    }

    Invalidate();//强制调用OnDraw

}

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/231596.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • python爬虫库_python爬虫实战百度云盘

    python爬虫库_python爬虫实战百度云盘如何使用爬虫与JieBa库制作词云所需库的安装所需第三方库为如下:importrequestsfrombs4importBeautifulSoupfromwordcloudimportWordCloudimportmatplotlib.pyplotaspltimportjiebaimportnumpyasnpfromPILimportImage此网址内含大量python第三方库下载安装即可:链接:https://www.lfd.uci.edu/~g

    2025年11月18日
    5
  • Symantec 卸载密码方法

    Symantec 卸载密码方法Symantec卸载密码方法最的有很多朋友问…方法一:当时就是输入在服务器端设置的密码(诺顿的默认密码是symantec)方法二:修改注册表HKEY_LOCAL_MACHINE\SOFTWARE\INTEL\LANDesk\VirusProtect6CurrentVersion\AdministratorOnly\Security修改UseV…

    2022年6月3日
    209
  • rs232接口与rs485接口区别_rs485和rj45区别

    rs232接口与rs485接口区别_rs485和rj45区别原文地址:https://www.sohu.com/a/244903033_649673通讯端口都是串口,在以下几个方面有区别:1、通讯距离RS232口最大通讯距离是15米,而RS422/485最大通讯距离是1200米。2、所连接设备个RS232只能连接一个设备,而RS485可以连接多个设备。3、端口的定义RS232是标准接口,为D形9针头,所连接设备的接口的信号定义是一样的,其信号定义如下:而RS422/RS485为非标准接口,一般为15针串行接口(也有使用9针接口的),每

    2025年12月12日
    4
  • 递归和迭代有什么区别?

    递归和迭代有什么区别?“递归”和“迭代”的区别如下:1、递归的基本概念:程序调用自身的编程技巧称为递归,是函数自己调用自己.一个函数在其定义中直接或间接调用自身的一种方法,它通常把一个大型的复杂的问题转化为一个与原问题相似的规模较小的问题来解决,可以极大的减少代码量.递归的能力在于用有限的语句来定义对象的无限集合。2、迭代:利用变量的原值推算出变量的一个新值.如果递归是自己调用自己的话,迭代就是A不停的调用…

    2022年6月6日
    38
  • Java JSON解析_javaxml解析

    Java JSON解析_javaxml解析JavaJSON解析教程

    2025年9月2日
    7
  • WPF TextBox模仿PasswordBox的密码显示功能

    WPF TextBox模仿PasswordBox的密码显示功能WPFTextBox显示密码,模仿PasswordBox的功能

    2022年7月24日
    16

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号