CDIB类--C++显示数字图像


Visual C++ MFC中没有提供一个专门的类来处理DIB位图,为了方便地使用位图文件,派生一个CDib类。构建一个单文档MFC后,加入CDIB类,类的源代码如下:
 
 (1) CDib类的声明 

// DIB.h:类CDib声明头文件  #ifndef __DIB_H__  #define __DIB_H__  #include <wingdi.h>  class CDib  {   public:    CDib();    ~CDib();    BOOL Load( const char * );    BOOL Save( const char * );    BOOL Draw( CDC *, int nX = 0, int nY = 0, int nWidth = -1, int nHeight = -1, int mode = SRCCOPY);    BOOL SetPalette( CDC * ); 
 private: 
  CPalette m_Palette; 
  unsigned char *m_pDib, *m_pDibBits; 
  DWORD m_dwDibSize; 
  BITMAPINFOHEADER *m_pBIH; 
  RGBQUAD *m_pPalette; 
  int m_nPaletteEntries; 
 }; 
#endif 

(2) CDib类的实现 
#include "stdafx.h" 
#include "DIB.h" 
CDib::CDib() 

 m_pDib = NULL; 

CDib::~CDib() 

 // 如果位图已经被加载,释放内存 
 if (m_pDib != NULL) 
  delete []m_pDib; 

  //其功能为加载位图,类似于CBitmap类的LoadBitmap函数: 
BOOL CDib::Load(const char *pszFilename) 

 CFile cf; 
 // 打开位图文件 
 if (!cf.Open(pszFilename, CFile::modeRead)) 
  return (FALSE); 
 // 获得位图文件大小,并减去BITMAPFILEHEADER的长度 
 DWORD dwDibSize; 
 dwDibSize = cf.GetLength() - sizeof(BITMAPFILEHEADER); 
 // 为DIB位图分配内存 
 unsigned char *pDib; 
 pDib = new unsigned char[dwDibSize]; 
 if (pDib == NULL) 
  return (FALSE); 
 BITMAPFILEHEADER BFH; 
 // 读取位图文件数据 
 try 
 { 
  // 文件格式是否正确有效 
  if ( cf.Read(&BFH, sizeof(BITMAPFILEHEADER)) != sizeof(BITMAPFILEHEADER) || 
     BFH.bfType != 'MB' || cf.Read(pDib, dwDibSize) != dwDibSize) 
  { 
   delete []pDib; 
   return (FALSE); 
  } 
 } 
 catch (CFileException *e) 
 { 
  e->Delete(); 
  delete []pDib; 
  return (FALSE); 
 } 
 // delete先前加载的位图 
 if (m_pDib != NULL) 
  delete m_pDib; 
 // 将临时Dib数据指针和Dib大小变量赋给类成员变量 
 m_pDib = pDib; 
 m_dwDibSize = dwDibSize; 
 // 为相应类成员变量赋BITMAPINFOHEADER和调色板指针 
 m_pBIH = (BITMAPINFOHEADER*)m_pDib; 
 m_pPalette = (RGBQUAD*) &m_pDib[sizeof(BITMAPINFOHEADER)]; 
 // 计算调色板中实际颜色数量 
 m_nPaletteEntries = 1 << m_pBIH->biBitCount; 
 if (m_pBIH->biBitCount > 8) 
  m_nPaletteEntries = 0; 
 else if (m_pBIH->biClrUsed != 0) 
  m_nPaletteEntries = m_pBIH->biClrUsed; 
 // 为相应类成员变量赋image data指针 
 m_pDibBits = &m_pDib[sizeof(BITMAPINFOHEADER) + m_nPaletteEntries * sizeof (RGBQUAD)]; 
 // delete先前的调色板 
 if (m_Palette.GetSafeHandle() != NULL) 
  m_Palette.DeleteObject(); 
 // 如果位图中存在调色板,创建LOGPALETTE 及CPalette 
 if (m_nPaletteEntries != 0) 
 { 
  LOGPALETTE *pLogPal = (LOGPALETTE*)new char[sizeof(LOGPALETTE) + m_nPaletteEntries *sizeof(PALETTEENTRY)]; 
  if (pLogPal != NULL) 
  { 
   pLogPal->palVersion = 0x300; 
   pLogPal->palNumEntries = m_nPaletteEntries; 
   for (int i = 0; i < m_nPaletteEntries; i++) 
   { 
    pLogPal->palPalEntry[i].peRed = m_pPalette[i].rgbRed; 
    pLogPal->palPalEntry[i].peGreen = m_pPalette[i].rgbGreen; 
    pLogPal->palPalEntry[i].peBlue = m_pPalette[i].rgbBlue; 
   } 
   //创建CPalette并释放LOGPALETTE的内存 
   m_Palette.CreatePalette(pLogPal); 
   delete []pLogPal; 
  } 
 } 
 return (TRUE); 

//函数功能:保存位图入BMP文件 
BOOL CDib::Save(const char *pszFilename) 

 if (m_pDib == NULL) 
  return (FALSE); 
 CFile cf; 
 if (!cf.Open(pszFilename, CFile::modeCreate | CFile::modeWrite)) 
  return (FALSE); 
 try 
 { 
  BITMAPFILEHEADER BFH; 
  memset(&BFH, 0, sizeof(BITMAPFILEHEADER)); 
  BFH.bfType = 'MB'; 
  BFH.bfSize = sizeof(BITMAPFILEHEADER) + m_dwDibSize; 
  BFH.bfOffBits = sizeof(BITMAPFILEHEADER) + 
sizeof(BITMAPINFOHEADER) + m_nPaletteEntries *sizeof(RGBQUAD); 
  cf.Write(&BFH, sizeof(BITMAPFILEHEADER)); 
  cf.Write(m_pDib, m_dwDibSize); 
 } 
 catch (CFileException *e) 
 { 
  e->Delete(); 
  return (FALSE); 
 } 
 return (TRUE); 

//其功能为在pDC指向的CDC中绘制位图,起点坐标为(nX,nY),绘制宽度和高度为nWidth、nHeight,最后一个参数是光栅模式: 
BOOL CDib::Draw(CDC *pDC, int nX, int nY, int nWidth, int nHeight, int mode) 

 if (m_pDib == NULL) 
  return (FALSE); 
 // 获取位图宽度和高度赋值 
 if (nWidth == - 1) 
  nWidth = m_pBIH->biWidth; 
 if (nHeight == - 1) 
  nHeight = m_pBIH->biHeight; 
 // 绘制位图 
 StretchDIBits(pDC->m_hDC, nX, nY, nWidth, nHeight, 0, 0, m_pBIH->biWidth, m_pBIH->biHeight, m_pDibBits, (BITMAPINFO*)m_pBIH, BI_RGB, mode); 
 return (TRUE); 

//函数功能:设置调色板 
BOOL CDib::SetPalette(CDC *pDC) 

 if (m_pDib == NULL) 
  return (FALSE); 
 // 检查当前是否有一个调色板句柄,对于大于256色的位图,为NULL 
 if (m_Palette.GetSafeHandle() == NULL) 
  return (TRUE); 
 // 选择调色板,接着实施之,最后恢复老的调色板 
 CPalette *pOldPalette; 
 pOldPalette = pDC->SelectPalette(&m_Palette, FALSE); 
 pDC->RealizePalette(); 
 pDC->SelectPalette(pOldPalette, FALSE); 
 return (TRUE); 

从整个CDib类的代码中我们可以看出,DIB位图的显示需遵循如下步骤: 

(1)读取位图,本类中使用pDib = new unsigned char[dwDibSize]为位图中的信息分配内存,另一种方法是调用API函数CreateDIBSection,譬如:

m_hBitmap = ::CreateDIBSection(pDC->GetSafeHdc(),
(LPBITMAPINFO) m_lpBMPHdr, DIB_RGB_COLORS,
(LPVOID*) &m_lpDIBits, NULL, 0);

m_hBitmap定义为:

HBITMAP m_hBitmap;

(2)根据读取的位图信息,计算出调色板大小,然后创建调色板;

(3)调用CDib::SetPalette( CDC *pDC )设置调色板,需要用到CDC::SelectPalette及CDC::RealizePalette两个函数;

(4)调用CDib::Draw(CDC *pDC, int nX, int nY, int nWidth, int nHeight, int mode)函数绘制位图。在此函数中,真正发挥显示位图作用的是对StretchDIBits API函数的调用。StretchDIBits函数具有缩放功能,其最后一个参数也是光栅操作的模式。

下面给出DIB位图的打开及显示的函数源代码。"DIB位图"父菜单下"打开"子菜单的单击事件消息处理函数为(其功能为打开位图并显示之):
void CImageProcessView::OnFileOpen() 
{
// TODO: Add your command handler code here
// 弹出文件对话框,让用户选择位图文件 
 CFileDialog fileDialog(TRUE, "*.BMP", NULL, NULL,"位图文件(*.BMP)|*.bmp;*.BMP|"); 
 if (IDOK == fileDialog.DoModal()) 
 { 
  // 加载位图并显示之 
  CDib dib; 
  if (dib.Load(fileDialog.GetPathName())) 
  { 
   CClientDC dc(this); 
   dib.SetPalette(&dc); 
   dib.Draw(&dc); 
  } 
 } 

运行程序,打开位图:


已标记关键词 清除标记
相关推荐
/*声明*/ #ifndef _CDIB_H #define _CDIB_H class CDib :public CObject{ //父为CObject public: RGBQUAD*m_pRGB; BYTE*m_pData; UINT m_numberOfColors; BOOL m_valid; BITMAPFILEHEADER bitmapFileHeader; BITMAPINFOHEADER *m_pBitmapInfoHeader; BITMAPINFO *m_pBitmapInfo; BYTE *pDib; DWORD size; public: CDib(); ~CDib(); char m_fileName[256]; char *GetFileName(); BOOL IsValid(); DWORD GetSize(); UNIT GetHight(); UINT GetNumberOfColors(); RGBQUAD *GetRGB(); BYTE *GetData(); BITMAPINFO *GetInfo(); WORD PaletteSize(LPBYTE lpDIB); WORD DIBNumColors(LPBYTE lpDIB); void SaveFile(const CString filename); public(); void LoadFile(const char*dibFileName); } #include "Stdafx.h" #include "CDib.h" #include "windowsx.h" CDib::CDib(){ size=0; } CDib::~CDib(){ GlobalFreePtr(m_pBitmapInfo); } void CDib::LoadFile(const char*dibFileName){ strcpy(m_fileName,dibFileName); CFile dibFile(m_fileName,CFile::modeRead); dibFile.Read((void*)&bitmapFileHeader,sizeof(BITMAPFILEHEADER)); if(bitmapFileHeader.bfType== ox4d42;){ DWORD fileLength=dibFile.GetLength(); size=fileLength-sizeof(BITMAPFILEHEADER); pDib=(BYTE*)GlobalAllocPtr(GMEM_MOVEABLE,size); dibFile.Read((void*)pDib,size); dibFile.Close(); m_pBitmapInfo=(BITMAPINF0*)pDib; m_pBitmapInfoHeader=(BITMAPINFOHEADER*)pDib; m_pRGB=(RGBQUAD*)(pDib+m_pBitmapInfoHeader->biSize); int m_numberOfColors=GetNumberOfColors(); if(m_pBitmapInfoHeader->biClrUsed==0) m_pBitmapInfoHeader->biClrUsed=m_numberOfColors; DWORD colorTableSize=m_numberOfColors*sizeof(RGBQUAD); m_pData=pDib+m_pBitmapInfoHeader->biSize+colorTableSize; if(m_pRGB==(RGBQUAD*)m_pData) m_pRGB=NULL; m_pBitmapInfoHeader->biSizeImage=GetSize(); m_valid=TRUE; } else{ m_valid=FALSE; AfxMessageBox("This isn't a bitmap file!"); } } BOOL CDib::IsValid(){ return m_valid; } char *CDib::GetFileName(){ return m_fileName; } UINT CDib::GetWidth(){ return(UINT)m_pBitmapInfoHeader->biWidth; } UINT CDib::GetHeight(){ return(UINT)m_pBitmapInfoHeader->biHeight; } UINT CDib::GetSize(){ if(m_pbitmapInfoHeader->biSizeImage!=0) return m_pBitmapInfoHeader->biSizeImage; else{ DWORD height=(DWORD)GetHeight(); DWORD width=(DWORD)GetWidth(); return height*width; } } UNIT CDib::GetNumberOfColors(){ int numberOfColors; if((m_pBitmapInfoHeader->biClrUsed==0)&&(m_pBitmapInfoHeader->biBitCount<9)){ switch(m_pBitmapInfoHeader->biBitCount){ case1: numberOfColors=2; break; case4: numberOfColors=16; break; case8: numberOfColors=256; } }else{ numberOfColors=(int)m_pBitmapInfoHeader->biClrUsed; } return numberOfColors; } BYTE*CDib::GetData(){ return m_pData; } RGBQUAD*CDib::GetRGB(){ return m_pRGB; } BITMAPINFO*CDib::GetInfo(){ return m_pBitmapInfo; } WORD CDib::PaletteSize(LPBYTE lpDIB){ return (DIBNumColors(lpDIB)*sizeof(RGBTRIPLE); } WORD CDib::DIBNumColors(LPBYTE lpDIB){ WORD wBitCount; wBitCount=((LPBITMAPCOREHEADER)lpDIB)->bcBitCount; switch(wBitCount){ case1: return 2; case4; return 16; case8: return 256; default: return 0; } } void CDib::SaveFile(const CString filename){ stcpy(m_fileName,filename); CFile dibFile(m_fileName,CFile::modeCreate|CFile::modeWrite); dibFile.Write((void*)&bitmapFileHeader,sizeof(BITMAPFILEHEADER)); dibFile.Write((void*)pDib,size); dibFile.Close(); }
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页