使用多文档编程 也可以使用单文档编程
建立一个DIB图像的显示类 ImageDib
成员变量:
4个指针:
LPBYTE m_lpDib; //指向DIB的指针
LPBITMAPINFOHEADER m_lpBmpInfoHead; //图像信息头指针
LPRGBQUAD m_lpColorTable; //图像颜色表指针
unsigned char * m_pImgData; //图像数据指针
4个普通变量(存放图像的参数):
int m_imgWidth; //图像的宽,像素为单位
int m_imgHeight; //图像的高,像素为单位
int m_nBitCount; //每像素占的位数
int m_nColorTableLength; //颜色表长度(多少个表项)
1个句柄:
HPALETTE m_hPalette; //逻辑调色板句柄
成员函数:
带参数构造函数 ImageDib(CSize size, int nBitCount, LPRGBQUAD lpColorTable, unsigned char *pImgData); //带参数的构造函数
ImageDib::ImageDib(CSize size, int nBitCount, LPRGBQUAD lpColorTable,unsigned char *pImgData) {//如果没有位图数据传入,我们认为是空的DIB,此时不分配DIB内存if(pImgData==NULL){m_lpDib=NULL;m_lpColorTable=NULL;m_pImgData=NULL; // 图像数据m_lpBmpInfoHead=NULL; // 图像信息头m_hPalette = NULL;}else{//如果有位图数据传入//可以通过调用ReplaceDib()来实现 代码一样的//ReplaceDib(size,nBitCount,lpColorTable,pImgData);//图像的宽、高、每像素位数等成员变量赋值m_imgWidth=size.cx;m_imgHeight=size.cy;m_nBitCount=nBitCount;//根据每像素位数,计算颜色表长度m_nColorTableLength=ComputeColorTabalLength(nBitCount);//每行像素所占字节数,必须扩展成4的倍数int lineByte=(m_imgWidth*nBitCount/8+3)/4*4;//位图数据缓冲区的大小(图像大小)int imgBufSize=m_imgHeight*lineByte;//为m_lpDib一次性分配内存,生成DIB结构m_lpDib=new BYTE [sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * m_nColorTableLength+imgBufSize];//填写BITMAPINFOHEADER结构m_lpBmpInfoHead = (LPBITMAPINFOHEADER) m_lpDib;m_lpBmpInfoHead->biSize = sizeof(BITMAPINFOHEADER);m_lpBmpInfoHead->biWidth = m_imgWidth;m_lpBmpInfoHead->biHeight = m_imgHeight;m_lpBmpInfoHead->biPlanes = 1;m_lpBmpInfoHead->biBitCount = m_nBitCount;m_lpBmpInfoHead->biCompression = BI_RGB;m_lpBmpInfoHead->biSizeImage = 0;m_lpBmpInfoHead->biXPelsPerMeter = 0;m_lpBmpInfoHead->biYPelsPerMeter = 0;m_lpBmpInfoHead->biClrUsed = m_nColorTableLength;m_lpBmpInfoHead->biClrImportant = m_nColorTableLength;//调色板句柄初始化为空,有颜色表时,MakePalette()函数要生成新的调色板m_hPalette = NULL;//如果有颜色表,则将颜色表拷贝进DIB的颜色表位置if(m_nColorTableLength!=0){//m_lpColorTable指向DIB颜色表的起始位置m_lpColorTable=(LPRGBQUAD)(m_lpDib+sizeof(BITMAPINFOHEADER));//颜色表拷贝memcpy(m_lpColorTable,lpColorTable,sizeof(RGBQUAD) * m_nColorTableLength);//创建逻辑调色板 MakePalette();}//m_pImgData指向DIB位图数据起始位置m_pImgData = (LPBYTE)m_lpDib+sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD) * m_nColorTableLength;//拷贝图像数据进DIB位图数据区 memcpy(m_pImgData,pImgData,imgBufSize);}}
读文件: BOOL Read(LPCTSTR lpszPathName); //DIB读函数
BOOL ImageDib::Read(LPCTSTR lpszPathName) {//读模式打开图像文件 CFile file;if (!file.Open(lpszPathName, CFile::modeRead | CFile::shareDenyWrite))return FALSE;BITMAPFILEHEADER bmfh;//读取BITMAPFILEHEADER结构到变量bmfh中int nCount=file.Read((LPVOID) &bmfh, sizeof(BITMAPFILEHEADER));//为m_lpDib分配空间,读取DIB进内存if(m_lpDib!=NULL) delete []m_lpDib;m_lpDib=new BYTE[file.GetLength() -sizeof(BITMAPFILEHEADER)];file.Read(m_lpDib, file.GetLength() -sizeof(BITMAPFILEHEADER));//m_lpBmpInfoHead位置为m_lpDib起始位置m_lpBmpInfoHead = (LPBITMAPINFOHEADER)m_lpDib;//为成员变量赋值m_imgWidth=m_lpBmpInfoHead->biWidth;m_imgHeight=m_lpBmpInfoHead->biHeight;m_nBitCount=m_lpBmpInfoHead->biBitCount; //计算颜色表长度m_nColorTableLength= ComputeColorTabalLength(m_lpBmpInfoHead->biBitCount);//如果有颜色表,则创建逻辑调色板m_hPalette = NULL;if(m_nColorTableLength!=0){m_lpColorTable=(LPRGBQUAD)(m_lpDib+sizeof(BITMAPINFOHEADER));MakePalette();}//m_pImgData指向DIB的位图数据起始位置m_pImgData = (LPBYTE)m_lpDib+sizeof(BITMAPINFOHEADER) +sizeof(RGBQUAD) * m_nColorTableLength;return TRUE; }
写文件: BOOL Write(LPCTSTR lpszPathName); //DIB写函数
BOOL ImageDib::Write(LPCTSTR lpszPathName) {//写模式打开文件 CFile file;if (!file.Open(lpszPathName, CFile::modeCreate | CFile::modeReadWrite | CFile::shareExclusive))return FALSE;//填写文件头结构 BITMAPFILEHEADER bmfh;bmfh.bfType = 0x4d42; // 'BM'bmfh.bfSize = 0;bmfh.bfReserved1 = bmfh.bfReserved2 = 0;bmfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) +sizeof(RGBQUAD) * m_nColorTableLength; try {//文件头结构写进文件file.Write((LPVOID) &bmfh, sizeof(BITMAPFILEHEADER));//文件信息头结构写进文件file.Write(m_lpBmpInfoHead, sizeof(BITMAPINFOHEADER));//如果有颜色表的话,颜色表写进文件if(m_nColorTableLength!=0)file.Write(m_lpColorTable, sizeof(RGBQUAD) * m_nColorTableLength);//位图数据写进文件int imgBufSize=(m_imgWidth*m_nBitCount/8+3)/4*4*m_imgHeight;file.Write(m_pImgData, imgBufSize);}catch(CException* pe) {pe->Delete();AfxMessageBox("write error");return FALSE;}//函数返回return TRUE; }
计算颜色表长度: int ComputeColorTabalLength(int nBitCount); //计算颜色表的长度
int ImageDib::ComputeColorTabalLength(int nBitCount) {int colorTableLength;switch(nBitCount) {case 1:colorTableLength = 2;break;case 4:colorTableLength = 16;break;case 8:colorTableLength = 256;break;case 16:case 24:case 32:colorTableLength = 0;break;default:ASSERT(FALSE);}ASSERT((colorTableLength >= 0) && (colorTableLength <= 256)); return colorTableLength; }
创建逻辑调色板: void MakePalette(); //创建逻辑调色板
void ImageDib::MakePalette() {//如果颜色表长度为0,则不创建逻辑调色板if(m_nColorTableLength == 0) return;//删除旧的逻辑调色板句柄if(m_hPalette != NULL) ::DeleteObject(m_hPalette);//申请空间,根据颜色表生成LOGPALETTE结构LPLOGPALETTE pLogPal = (LPLOGPALETTE) new char[2 * sizeof(WORD) +m_nColorTableLength * sizeof(PALETTEENTRY)];pLogPal->palVersion = 0x300;pLogPal->palNumEntries = m_nColorTableLength;LPRGBQUAD m_lpDibQuad = (LPRGBQUAD) m_lpColorTable;for(int i = 0; i < m_nColorTableLength; i++) {pLogPal->palPalEntry[i].peRed = m_lpDibQuad->rgbRed;pLogPal->palPalEntry[i].peGreen = m_lpDibQuad->rgbGreen;pLogPal->palPalEntry[i].peBlue = m_lpDibQuad->rgbBlue;pLogPal->palPalEntry[i].peFlags = 0;m_lpDibQuad++;} //创建逻辑调色板m_hPalette = ::CreatePalette(pLogPal);//释放空间 delete pLogPal; }
读取图像维数: CSize GetDimensions(); //读取图像维数
CSize ImageDib::GetDimensions() { if(m_lpDib == NULL) return CSize(0, 0);return CSize(m_imgWidth, m_imgHeight); }
图像绘制: BOOL Draw(CDC* pDC, CPoint origin, CSize size); //图像绘制
BOOL ImageDib::Draw(CDC* pDC, CPoint origin, CSize size) {HPALETTE hOldPal=NULL; //旧的调色板句柄if(m_lpDib == NULL) return FALSE; //如果DIB为空,则返回0if(m_hPalette != NULL) { //如果DIB有调色板//将调色板选进设备环境中hOldPal=::SelectPalette(pDC->GetSafeHdc(), m_hPalette, TRUE);pDC->RealizePalette(); }pDC->SetStretchBltMode(COLORONCOLOR); //设置位图伸缩模式//将DIB在pDC所指向的设备上进行显示::StretchDIBits(pDC->GetSafeHdc(), origin.x, origin.y, size.cx, size.cy,0, 0, m_lpBmpInfoHead->biWidth, m_lpBmpInfoHead->biHeight,m_pImgData,(LPBITMAPINFO) m_lpBmpInfoHead, DIB_RGB_COLORS, SRCCOPY);if(hOldPal!=NULL) //恢复旧的调色板::SelectPalette(pDC->GetSafeHdc(), hOldPal, TRUE);return TRUE; }
用新的数据替代DIB:void ReplaceDib(CSize size, int nBitCount, LPRGBQUAD lpColorTable, unsigned char *pImgData); //用新的数据替换DIB
void ImageDib::ReplaceDib(CSize size, int nBitCount, LPRGBQUAD lpColorTable,unsigned char *pImgData) { //释放原DIB所占空间 Empty();//成员变量赋值m_imgWidth=size.cx;m_imgHeight=size.cy;m_nBitCount=nBitCount;//计算颜色表的长度m_nColorTableLength=ComputeColorTabalLength(nBitCount);//每行像素所占字节数,扩展成4的倍数int lineByte=(m_imgWidth*nBitCount/8+3)/4*4;//位图数据的大小int imgBufSize=m_imgHeight*lineByte;//为m_lpDib重新分配空间,以存放新的DIBm_lpDib=new BYTE [sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * m_nColorTableLength+imgBufSize];//填写位图信息头BITMAPINFOHEADER结构m_lpBmpInfoHead = (LPBITMAPINFOHEADER) m_lpDib;m_lpBmpInfoHead->biSize = sizeof(BITMAPINFOHEADER);m_lpBmpInfoHead->biWidth = m_imgWidth;m_lpBmpInfoHead->biHeight = m_imgHeight;m_lpBmpInfoHead->biPlanes = 1;m_lpBmpInfoHead->biBitCount = m_nBitCount;m_lpBmpInfoHead->biCompression = BI_RGB;m_lpBmpInfoHead->biSizeImage = 0;m_lpBmpInfoHead->biXPelsPerMeter = 0;m_lpBmpInfoHead->biYPelsPerMeter = 0;m_lpBmpInfoHead->biClrUsed = m_nColorTableLength;m_lpBmpInfoHead->biClrImportant = m_nColorTableLength;//调色板置空m_hPalette = NULL;//如果有颜色表,则将颜色表拷贝至新生成的DIB,并创建逻辑调色板if(m_nColorTableLength!=0){m_lpColorTable=(LPRGBQUAD)(m_lpDib+sizeof(BITMAPINFOHEADER));memcpy(m_lpColorTable,lpColorTable,sizeof(RGBQUAD) * m_nColorTableLength);MakePalette();}//m_pImgData指向DIB的位图数据起始位置m_pImgData = (LPBYTE)m_lpDib+sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD) * m_nColorTableLength;//将新位图数据拷贝至新的DIB中 memcpy(m_pImgData,pImgData,imgBufSize); }
清理空间函数: void Empty(); //清理空间
void ImageDib::Empty() {//释放DIB内存缓冲区if(m_lpDib != NULL) {delete [] m_lpDib;m_lpDib=NULL;m_lpColorTable=NULL;m_pImgData=NULL; m_lpBmpInfoHead=NULL;}//释放逻辑调色板缓冲区if(m_hPalette != NULL){::DeleteObject(m_hPalette);m_hPalette = NULL;} }
默认构造函数:
ImageDib::ImageDib() {m_lpDib=NULL;//初始化m_lpDib为空。m_lpColorTable=NULL; //颜色表指针为空m_pImgData=NULL; //图像数据指针为空m_lpBmpInfoHead=NULL; //图像信息头指针为空m_hPalette = NULL; //调色板为空 }
默认析构函数:
ImageDib::~ImageDib() {//释放m_lpDib所指向的内存缓冲区if(m_lpDib != NULL) delete [] m_lpDib; //如果有调色板,释放调色板缓冲区if(m_hPalette != NULL)::DeleteObject(m_hPalette); }
编写好ImageDib类后,在doc文件类中添加一个ImageDib类的指针,在构造函数中new出来,在析构函数中delete,然后重写OnOpenDocument()函数 在其中调用读函数打开图像 在View类的OnDraw()中调用ImageDib类的绘制函数 将图像绘制在打开的新文件中
总结:编程的关键在于几个指针的赋值,指向DIB的指针的分配空间,位图信息头等结构的赋值等等。
只要记住:
BMP文件=位图头文件+位图信息头+颜色表+数据块 (等号后边的内容按顺序写的)
DIB=位图信息头+颜色表+数据块
位图信息=位图信息头+颜色表
这些图像文件的存储组成及顺序,万事OK!