1、1,图像的存取、显示与生成,2,4.1.3 CImage类(1),CImage是Visual C+中MFC的一个类 CImage类使图形、图像软件的开发跨越了DDB与DIB概念,使处理更为简洁、方便 CImage类提供了读入和保存BMP、JPEG、GIF、TIF与PNG等格式图像的能力 CImage可以直接使用Windows提供的图形功能,3,4.1.3 CImage类(2),使用CImage时,必须包含atlimage.h文件。可在stdafx.h文件的末尾添加#include .,4,CImage类成员函数创建与删除,Create 创建一个DIB位图与已有CImage对象相连接 Destr
2、oy 位图与CImage对象相分离并予删除,5,CImage类成员函数输入与输出,Load 读入指定图像文件中的图像 Save 按指定类型保存图像,文件名中不能省略后缀,6,CImage类成员函数位图参数,GetWidth 返回当前图像的宽度(以像素为单位) GetHeight 返回当前图像的高度 GetBPP 返回当前图像的每像素位数(颜色的深度) GetPixelAddress 返回指定像素数据存放位置的存储地址 GetMaxColorTableEntries 返回调色板单元数 IsIndexed 判别位图中是否有调色板,7,CImage类成员函数图形绘制,GetDC 返回当前位图的设备描
3、述表 ReleaseDC 释放设备描述表 GetPixel 返回指定位置像素的颜色 SetPixel 设置指定位置像素的颜色 SetPixelRGB 设置指定位置像素的红绿蓝分量 GetColorTable 获取调色板颜色分量 (红、绿、蓝) 值 SetColorTable 设置调色板颜色分量 (红、绿、蓝) 值,8,CImage类成员函数位图块传送,BitBlt 位图的一个矩形区域复制到另一位图上的指定区域 StretchBlt 从源矩形拷贝到目标矩形,支持伸缩,9,4.1.5 图像文件的输入与输出,CImage类读入图象数据的成员函数: HRESULT Load( LPCTSTR pszF
4、ileName ) throw( ); 例如:WorkCanvus.Load(m_FileName);CImage类保存图象数据的成员函数: HRESULT Save( IStream* pStream, REFGUID guidFileType ) const throw();,10,读入图象文件并显示图象的步骤,(1)建立CImage对象,例如WorkCanvus (2)在“打开文件”菜单处理程序OnFileOpen()函数中用WorkCanvus的Load()成员函数将图像文件里的图象数据读入到WorkCanvus中 (3)在菜单“显示工作画布”处理程序OnDisplayWorkcanv
5、us()中用WorkCanvus的Bitblt()函数将WorkCanvus中的图象数据传送到画布(例如CClientDC或pDC)上,WorkCanvus,图像文件,Load(),Bitblt(),画布,11,打开图像文件-OnFileOpen(),菜单: “文件/打开” 源文件:CImageDoc.cpp 函数:OnFileOpen() 步骤: (1)添加CImage类的全局对象WorkCanvus,并在stdafx.h中将WorkCanvus说明为外部对象 extern CImage WorkCanvus; (2)添加CImageDoc类的事件ID_FILE_OPEN的处理函数void
6、CImageDoc:OnFileOpen() (3)在CImageDoc:OnFileOpen()函数中编写程序 由对话框输入图像文件名 根据文件名从图像文件中读入图像数据到CImage类的对象WorkCanvus中 并设置最近打开的文件名,12,Program CImageDoc.cpp OnFileOpen(),void CImageDoc:OnFileOpen() 。CFileDialog dlg(TRUE, NULL, NULL, OFN_FILEMUSTEXIST, strFilter);hResult = (int)dlg.DoModal();/由对话框输入图像文件名m_FileN
7、ame = dlg.GetFileName();/保存当前文件名hResult = WorkCanvus.Load(m_FileName);/根据文件名从图像文件中读入图像数据到CImage类的对象WorkCanvus中SetPathName(m_FileName,1);/设置最近打开的文件名UpdateAllViews(NULL); /调用OnDraw显示图象 ,13,保存图像文件(1),菜单: “文件/另存为” 源文件:CImageDoc.cpp 函数:OnFileSaveAs() 步骤: (1)添加CImageDoc类的事件ID_FILE_SAVE_AS的处理函数void CImageD
8、oc:OnFileSaveAs() (3)在CImageDoc: OnFileSaveAs()函数中编写程序: 由对话框输入图像文件名 根据文件名将CImage类的对象WorkCanvus中的图像数据保存到图像文件中去,14,保存图像文件(2),void CImageDoc:OnFileSaveAs() CFileDialog dlg(FALSE,NULL,NULL,OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_EXPLORER,strFilter);hResult = (int)dlg.DoModal();/ 由对话框输入文件名hResult =
9、WorkCanvus.Save(strFileName); ,15,显示CImage类对象中的图象,菜单: “画布操作/显示工作画布” 源文件:CImageView.cpp 函数:OnDisplayWorkcanvus() void DrawWorkCanvus(CDC *pDC) CClientDC dc(this);int nXDest,nYDest,nWidth,nHeight,nXSrc,nYSrc;nXSrc=0;nYSrc=0;nXDest=0;nYDest=0;nWidth=WorkCanvus.GetWidth();nHeight=WorkCanvus.GetHeight();
10、WorkCanvus.BitBlt(dc,nXDest,nYDest,nWidth,nHeight,nXSrc,nYSrc,SRCCOPY); ,16,4.2 画布,画布是一个将图像作为二维像素数组存储的数据结构 屏幕画布 屏幕上Windows窗口中的客户区 可通过新建CClientDC的对象来创建屏幕画布 利用OnDraw()函数中的参数pDC来创建屏幕画布 内存画布 建立一个或多个CImage对象来创建内存画布 画布可用作双缓存技术 克服屏幕画面的闪烁,17,4.2.1-2 CImage对象的创建,BOOL Create(int nWidth, int nHeight,int nBPP,D
11、WORD dwFlags=0)throw(); nWidth The width of the CImage bitmap, in pixels. nHeight The height of the CImage bitmap, in pixels. If nHeight is positive, the bitmap is a bottom-up DIB and its origin is the lower left corner. If nHeight is negative, the bitmap is a top-down DIB and its origin is the uppe
12、r left corner. nBPP The numbers of bits per pixel in the bitmap. Usually 4, 8, 16, 24, or 32. Can be 1 for monochrome bitmaps or masks. dwFlags Specifies if the bitmap object has an alpha channel. Can be a combination of zero or more of the following values:,18,4.2.1-3 CImage对象转换成CDC对象,CDC中有大量绘图函数,那
13、么如何用CDC类的成员函数在CImage对象上绘图? 从CImage对象取得HDC设备描述表,再转换成CDC对象, 例如 CImage WorkCanvus; CDC *pDC;pDC=CDC:FromHandle(WorkCanvus.GetDC();/获取CDC指针pDC-SetPixel(x,y,(COLORREF) n); /CDC上的各种绘图操作WorkCanvus.ReleaseDC(); / 释放HDC,19,4.2.2 窗口刷新,Windows通过调用OnDraw()函数刷新窗口 何时需要刷新窗口? 系统需要,例如系统改变窗口的尺寸 程序需要,例如程序要重画,可调用Invali
14、date()使窗口失效Invalidate()可以使整个窗口失效进行重绘,也可定义一个矩形区域只使一个区域内部某些地方失效 刷新时全部清除失效区域后,再重新开始绘制新的画面,故在执行过程中会看到屏幕有一次闪动 刷新窗口的方法 重新绘制,即将形成当前图像画面的过程再重复一遍 备份复贴,即将当前的屏幕画面存储起来作为备份,刷新时将备份粘贴到屏幕上,20,4.2.3 演示程序中一些画布的设置,工作画布-用于存放需要进行处理的图像 CImage对象,名为WorkCanvus 副本画布-保存图像,必要时把副本画布恢复到工作画布中去 CImage对象,名为SaveCanvus 屏幕画布-即屏幕窗口 CCl
15、ientDC的对象,例如dc CDC类的指针,例如pDC,WorkCanvus,SaveCanvus,屏幕画布,21,4.3.1-4 位图的复制,CImage类对象之间的复制功能不可以用赋值来实现。因此,编写了CopyImage()函数来实现两个CImage对象间数据的复制 菜单: “画布操作/工作画布复制到副本画布” 源文件:第四章图象显示.cpp 函数:CopyImage(),22,void CopyImage(CImage *pNewImg,CImage *pImage) RGBQUAD ColorTabs256;BYTE *pPixels, *pNewPixels;CDC *pDC,*
16、pNewDC; nWidth=pImage-GetWidth(); nHeight=pImage-GetHeight();nBitsPerPixel=pImage-GetBPP();nColorTableEntries=pImage-GetMaxColorTableEntries();if(!pNewImage-IsNull() pNewImage-Destroy();pNewImage-Create(nWidth,nHeight,nBitsPerPixel,0); if (nColorTableEntries0)pImage-GetColorTable(0,nColorTableEntrie
17、s,ColorTabs);pNewImage-SetColorTable(0,nColorTableEntries,ColorTabs); pDC= CDC:FromHandle(pImage-GetDC();pNewDC = CDC:FromHandle(pNewImage-GetDC();pNewDC-BitBlt(0,0,nWidth,nHeight,pDC,0,0,SRCCOPY);pImage-ReleaseDC();pNewImage-ReleaseDC(); ,23,像素的整行复制,为了能快速复制这些像素数据,可使用内存拷贝函数memcpy来复制像素 void *memcpy(
18、void *dest, const void *src, size_t count ); dest New buffer src Buffer to copy from count Number of characters to copy 例如:将第y1行像素数据整行复制到y2行 nBytesPerLine=GetBytesPerLine(pImage);/整行像素数据字节数 pPixel = (BYTE*) pImage-GetPixelAddress(0,y1); pNewPixel = (BYTE*) pNewImage-GetPixelAddress(0,y2); memcpy(pNe
19、wPixel,pPixel,nBytesPerLine); pPixel 是y1行像素数据的首地址 pNewPixel 是y2行像素数据的首地址,24,4.4.4 改变调色板,灰阶调色板,蓝阶调色板,默认调色板,25,灰阶调色板,调色板单元各分量的强度相等,色彩呈现灰色,分量值与单元序号成正比,调色板,内存图象数据,图象显示颜色,26,设置灰阶调色板,源文件:第四章图象显示.cpp函数:OnSetGrayPalette() void CImageView:OnSetGrayPalette() RGBQUAD ColorTab;.for(int i=0;i256;i+)/设置灰阶调色板Color
20、Tab.rgbRed = i;ColorTab.rgbGreen = i; ColorTab.rgbBlue = i; SaveCanvus.SetColorTable(i, 1, . ,27,蓝阶调色板,与灰阶调色板相似,它只保留蓝分量,而将红、绿分量全部设置为0,调色板,内存图象数据,图象显示颜色,28,设置蓝阶调色板,源文件:第四章图象显示.cpp 函数:OnSetBluePalette() void CImageView:OnGrayPalette() RGBQUAD ColorTab;.for(int i=0;i256;i+)/设置灰阶调色板ColorTab.rgbRed = 0;C
21、olorTab.rgbGreen = 0; ColorTab.rgbBlue = i; SaveCanvus.SetColorTable(i, 1, . ,29,默认调色板(1),自定义了一个默认调色板,提供一组典型的颜色组合,调色板,内存图象数据,图象显示颜色,30,默认调色板(2),RGBQUAD DefaultPalette256 = 0x00,0x00,0x00,0x00,0xa8,0x00,0x00,0x00,0x00,0xa8,0x00,0x00,0xa8,0xa8,0x00,0x00,0x00,0x00,0xa8,0x00,0xa8,0x00,0xa8,0x00,0x00,0x5
22、4,0xa8,0x00,0xa8,0xa8,0xa8,0x00,0x54,0x54,0x54,0x00,0xfc,0x54,0x54,0x00,0x54,0xfc,0x54,0x00,0xfc,0xfc,0x54,0x00,0x54,0x54,0xfc,0x00,0xfc,0x54,0xfc,0x00,0x54,0xfc,0xfc,0x00,0xfc,0xfc,0xfc,0x00,0x00,0x00,0x00,0x00,0x14,0x14,0x14,0x00,0x20,0x20,0x20,0x00,0x2c,0x2c,0x2c,0x00,0x38,0x38,0x38,0x00,31,设置默认调
23、色板,源文件:第四章图象显示.cpp 函数:OnSetDefaultPalette()RGBQUAD DefaultPalette256 = 。 void CImageView:OnSetDefaultPalette() .for(int i=0;i256;i+)/设置默认调色板SaveCanvus.SetColorTable(i,1, ,32,将副本画布调色板复制到工作画布,源文件:第四章图象显示.cpp 函数:OnCopySavecanvusPaletteToWorkcanvus() void CImageView:OnCopySavecanvusPaletteToWorkcanvus() int nColorTableEntries; RGBQUAD ColorTabs256;nColorTableEntries=SaveCanvus.GetMaxColorTableEntries();SaveCanvus.GetColorTable(0,nColorTableEntries,ColorTabs);WorkCanvus.SetColorTable(0,nColorTableEntries,ColorTabs); ,