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)
上一篇 2025年12月2日 下午8:01
下一篇 2025年12月2日 下午8:22


相关推荐

  • phpstorm2021.9 永久激活码(JetBrains全家桶)

    (phpstorm2021.9 永久激活码)JetBrains旗下有多款编译器工具(如:IntelliJ、WebStorm、PyCharm等)在各编程领域几乎都占据了垄断地位。建立在开源IntelliJ平台之上,过去15年以来,JetBrains一直在不断发展和完善这个平台。这个平台可以针对您的开发工作流进行微调并且能够提供…

    2022年3月27日
    200
  • 你还不知道Java异或运算符的妙用?

    你还不知道Java异或运算符的妙用?异或(XOR)运算符当两个boolean类型的变量,locked^deleted,如果locked与deleted是不同的,返回true。如果两个操作数是相同的,则返回false。因此,当我们需要同时检查两个不成立的条件时,可以使用异或运算符号。假设我们有两个条件,A和B,下面显示了A^B的可能值:A^B操作等于(A&&!B)||(!A&&B)。在Java中使用接下来让我看一下Java中的异或操作,当然我们可以.

    2026年4月16日
    7
  • 线程创建的四种方式

    线程创建的四种方式java中创建线程的四种方法以及区别Java使用Thread类代表线程,所有的线程对象都必须是Thread类或其子类的实例。Java可以用四种方式来创建线程,如下所示:1)继承Thread类创建线程2)实现Runnable接口创建线程3)使用Callable和Future创建线程4)使用线程池例如用Executor框架下面让我们分别来看看这四种创建线程的方法。–…

    2022年5月3日
    72
  • 电脑开机错误代码0xc0000428_状态为0xc0000428

    电脑开机错误代码0xc0000428_状态为0xc0000428吴川华南区技术负责人概要有用户反馈电脑启动时,屏幕突然出现错误码0xc0000428,无法进入系统。本文将针对这个问题,分析出现错误码0xc0000428的原因,并为大家提供解决方案。一、关于错误码0xc0000428当电脑启动出现错误码0xc0000428时,屏幕上一般会出现以下错误信息:“Windows无法验证此文件的数字签名:\Windows\System32\winload.ex…

    2026年4月17日
    6
  • PhantomJS简介[通俗易懂]

    PhantomJS简介[通俗易懂]PhantomJS是一个可编程的无头浏览器.无头浏览器:一个完整的浏览器内核,包括js解析引擎,渲染引擎,请求处理等,但是不包括显示和用户交互页面的浏览器。可以使用Phantomejs做一些页面渲染的工作;如获取js的页面内容、截图等;

    2022年7月26日
    11
  • Gridview漂亮的样式

    Gridview漂亮的样式  linkhref=”StyleSheet.css”rel=”stylesheet”type=”text/css”/>linkhref=”GamerGridView.css”rel=”stylesheet”type=”text/css”/> StandardGridViewdeclaration:/par??/cf0/

    2026年3月4日
    5

发表回复

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

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