【VS开发】GDI+ 用CImage类来显示PNG、JPG等图片
系统环境:Windows 7
软件环境:Visual Studio 2008 SP1
本次目的:实现VC单文档、对话框程序显示图片效果
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>
这是一个强大的图像处理类,下面分别详细介绍在文档、对话框下的显示图片。
对于单文档程序:
步骤一:添加头文件(由于我使用的是VS2008SP1,所以我未添加上面的头文件。)
步骤二:在Doc头文件里面声明对象,如:CImage img ;
步骤三:在Doc实现函数里面的序列化Serialize函数
void CImagePNGDoc::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
// TODO: 在此添加存储代码
}
else
{
// TODO: 在此添加加载代码
if(!img.IsNull()) img.Destroy();
img.Load(ar.GetFile()->GetFilePath());
}
}
步骤四:在视图View的实现文件OnDraw()里面
void CImagePNGView::OnDraw(CDC* pDC )
{
CImagePNGDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
// TODO: 在此处为本机数据添加绘制代码
if(!pDoc->img.IsNull()) pDoc->img.Draw(pDC->m_hDC, 0, 0);
}
完成,以上可以显示大多数的图片格式。
对于对话框程序:
步骤一:在对话框的头文件声明一个对象,如:CImage img ;
步骤二:在对话框的实现函数OnPaint()函数里面
void CTestDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 用于绘制的设备上下文
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// 使图标在工作区矩形中居中
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// 绘制图标
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CPaintDC dc(this);
if(!img.IsNull()) img.Destroy();
img.Load(_T("图片3.png"));
if(!img.IsNull()) img.Draw(dc.m_hDC, 0, 0);
CDialog::OnPaint();
}
}
完成。上述可实现对话框显示大多数图片。
特别注意,只有用Load()方式才能打开其他的图片格式,若是用资源加载的方式,则显示不出。下面介绍一种让PNG透明显示的方法:
if(!img.IsNull())img.TransparentBlt (dc.m_hDC,0,0,img.GetWidth(),img.GetHeight(),RGB(255,255,255));
一般透明色为白色,即只需要把关键色设置为白色即可。网上有很多相关的资料,可以参考一下:
使用CImage显示透明的PNG图片 http://blog.csdn.net/wormsun/archive/2008/11/13/3293741.aspx PNG透明背景显示之路 http://m9551.blog.sohu.com/29092953.html
CImage http://hi.baidu.com/cauciee/blog/item/3053490994877438e8248822.html
前言
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 加载位图文件
- // CImage可加载的图片文件有JPG,BMP,TIF.PNG等格式 而CBitmap只能加载BMP图片文件
- if(!PathFileExists(imgFilePath))
- return NULL;
- CImage nImage;
- nImage.Load(imgFilePath);
- return nImage.Detach(); //返回HBITMAP 可用CBitmap 处理 也可用CImage处理
2 与CBitmap转换
- CImage nImage;
- nImage.Load(imgFilePath);
- HBITMAP hBitmap=nImage.Detach(); // 获得位图句柄 用以转换
- // 转换方式一:
- CBitmap bmp;
- bmp.DeleteObject();
- bmp.Attach(hBitmap); // 转换为CBitmap对象
- // 转换方式二:
- CBitmap *pBitmap=CBitmap::FromHandle(nImage.m_hBitmap);
3 获得CImage对象的cdc
- CDC *pDC=CDC::FromHandle(nImage.GetDC());
- // Use pDC here
- nImage.ReleaseDC();
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( );
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:
- CImage img;
- img.Load("1.jpg");
- if (!img.IsNull())
- {
- img.Draw(pDC->m_hDC,CRect(0,0,100,100));
- }
EXAMPLE 2: 画在另一个位图中
- CImage img;
- img.Load(filePath);
- // 获得CImage对象的 CDC
- HDC hDC=img.GetDC();
- CDC *pDC=CDC::FromHandle(hDC);
- CBitmap bmp;// 只是创建了位图对象,但还没有将位图对象与位图资源联系起来
- 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 hBitmap;
- ATLASSUME( m_hBitmap != NULL );
- ATLASSUME( m_hDC == NULL );
- hBitmap = m_hBitmap;
- 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 );
- }
6 释放资源
CBitmap 使用DeleteObject()来主动释放掉位图资源
CImage 没有DeleteObject()函数 ,而是用Destroy()函数来主动释放位图资源
- inline void CImage::Destroy() throw()
- {
- HBITMAP hBitmap;
- if( m_hBitmap != NULL )
- {
- hBitmap = Detach();
- ::DeleteObject( hBitmap ); //释放位图资源
- }
- }
CBitmap 析构时,会自动释放掉所占用的位图资源
CImage 析构时,也会自动释放掉所占用的位图资源
- 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 );
- }
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()
- 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();
或
- BYTE *pData=NULL;
- if(img.GetPitch()<0)
- pData=(BYTE *)img.GetPixelAddress(img.GetHeight()-1,0);
- else
- pData=(BYTE *)img.GetPixelAddress(0,0);
3)GetBPP() 返回每个像素所占的bit数
- 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 < nClrCount; index++)
- {
- p = (LPBYTE)GetBits();
- for(i = 0; i < nHeight; i++)
- {
- for(j = 0; j < nWidth; j++)
- {
- p[j*nClrCount + index] = 255 - p[j*nClrCount + index];
- }
- //如果nRowBytes>0 则从开始到结尾
- //如果nRowBytes<0, 则从结尾到开始
- p += nRowBytes;
- }
- }
- }
8 保存到图像文件中
Saves an image as the specified file name and type.
HRESULT Save( |
- inline HRESULT CImage::Save( LPCTSTR pszFileName, REFGUID guidFileType ) const throw()
- {
- if( !InitGDIPlus() )
- {
- return( E_FAIL );
- }
- UINT nEncoders;
- UINT nBytes;
- Gdiplus::Status 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 )
- {
- // Determine clsid from extension
- clsidEncoder = FindCodecForExtension( ::PathFindExtension( pszFileName ), pEncoders, nEncoders );
- }
- else
- {
- // 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 );
- }
- }
- else
- {
- Gdiplus::Bitmap bm( m_hBitmap, NULL );
- status = bm.Save( pwszFileName, &clsidEncoder, NULL );
- if( status != Gdiplus::Ok )
- {
- return( E_FAIL );
- }
- }
- return( S_OK );
- }
- pStream
-
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
- // Demonstrating saving various file formats
- int _tmain(int argc, _TCHAR* argv[])
- {
- CImage myimage;
- // 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);
- return 0;
- }
9 应用实例: 将两个图像合并为一个新的图像
- //图像路径
- CString img1Path;
- CString img2Path;
- CString img3Path;
- 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);
- CBitmap bmp;
- 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 rectRgn;
- rectRgn.CreateRectRgn(0,0,img1.GetWidth()/2,img1.GetHeight());
- CBrush brush;
- 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();
【VS开发】GDI+ 用CImage类来显示PNG、JPG等图片的更多相关文章
- 用CImage类来显示PNG、JPG等图片
系统环境:Windows 7软件环境:Visual Studio 2008 SP1本次目的:实现VC单文档.对话框程序显示图片效果 CImage 是VC.NET中定义的一种MFC/ATL共享类,也是A ...
- 强大的CImage类
这下有了CImage类,处理其他类型的图片不再寻找第三方类库了.加载到对话框背景的代码如下: //从资源里载入背景JPEG图片 HRSRC hRsrc=::FindResource(AfxGetRe ...
- GDI 总结三: CImage类使用
前言 CImage类是基于GDI+的.可是这里为什么要讲归于GDI? 主要是基于这种考虑: 在GDI+环境中,我们能够直接使用GDI+ ,没多少必要再使用CImage类 可是,假设再 ...
- GDI+ 两个汇总 : 为什么CImage类别是根据GDI+的?
在很多资料上都说CImage类是基于GDI+的,可是为什么是基于GDI+的呢? 由于使用这个类时,并没有增加#include <gdiplus.h> .也没有在程序開始和结束时分别写GDI ...
- 供CImage类显示的半透明PNG文件处理方法
原文链接: http://blog.sina.com.cn/s/blog_4070692f010003gy.html 前补:没想到这个帖子好像挺多人看哪……看来大家都被这个png郁闷的够呛.显示p ...
- CImage类
CImage封装了DIB(设备无关位图)的功能,因而可以让我们能够处理每个位图像素.这里介绍GDI+和CImage的一般使用方法和技巧. TAG: GDI CImage 后处理 我们知道,Vi ...
- 使用MFC CImage类绘制PNG图片时遇到的问题
为了测试CImage绘制PNG图片的效果,我们用截图软件截得一张360的界面,然后使用PhotoShop等工具在图片的周边加上了透明的区域,然后保存成PNG图片文件.CImage首先从文件中加载,即 ...
- vc++加载透明png图片方法-GDI+和CImage两种
转载自:http://blog.csdn.net/zhongbin104/article/details/8730935 先看看GDI+的方法方法1: 1.GDI+画透明图层(alpha)的png ...
- c++ MFC图像处理CImage类常用操作代码
原文作者:aircraft 原文地址:https://www.cnblogs.com/DOMLX/p/9598974.html MFC图像处理CImage类常用操作 CImage类头文件为#inclu ...
随机推荐
- Java8-Lambda-No.05
import java.util.HashMap; import java.util.function.BiConsumer; public class Lambda5 { //Pre-Defined ...
- python自动华 (五)
Python自动化 [第五篇]:Python基础-常用模块 目录 模块介绍 time和datetime模块 random os sys shutil json和pickle shelve xml处理 ...
- P3648 [APIO2014]序列分割 斜率优化
题解:斜率优化\(DP\) 提交:\(2\)次(特意没开\(long\ long\),然后就死了) 题解: 好的先把自己的式子推了出来: 朴素: 定义\(f[i][j]\)表示前\(i\)个数进行\( ...
- luoguP4778 Counting swaps
题目链接 题解 首先,对于每个\(i\)向\(a[i]\)连边. 这样会连出许多独立的环. 可以证明,交换操作不会跨越环. 每个环内的点到最终状态最少交换步数是 \(环的大小-1\) 那么设\(f[i ...
- 经过测试,feign只能通过@RequestBody传对象参数
通过feign调用,使用ModelAttribute 注解,参数没法传到对应的server
- Applications (ZOJ 3705)
题解:就是题目有点小长而已,可能会不想读题,但是题意蛮好理解的,就是根据条件模拟,计算pts.(送给队友zm. qsh,你们不适合训练了.) #include <iostream> #in ...
- 如何在vue中使用svg
1.安装依赖 npm install svg-sprite-loader --save-dev 2.在config文件中配置 const path = require('path'); func ...
- Python 函数lambda(), filter(), map(), reduce()
1 filter filter(function, sequence):对sequence中的item依次执行function(item),将执行结果为True的item组成一个List/String ...
- Oracle JDBC 连接池
1.简介 数据库连接池负责分配.管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个:释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据 ...
- jQuery 的on()方法
jQuery 的on()方法 一.总结 一句话总结: 1.普通添加事件:$("a").on("click", function () {执行的代码}) 2.未创 ...