MFC提供绘图API只支持Windows操作系统中的标准图像文件格式,即BMP格式,可以分成两类:设备相关位图(DDB)和设备无关位图(DIB)。
我的理解用代码与注释的方式表现了,有什么不正确的地方请指正,谢谢!
1)以整个文件的信息作为数据源的显示方式(文件格式为bmp)
LPBITMAPINFO bmi;
LPBYTE pBits;
// data为fwrite读取整个文件的数据
int LoadMemToBitmap(unsigned char* data, int size)
{
BITMAPFILEHEADER bmfh;
int pos = 0;
//读文件信息头
memcpy((LPVOID)&bmfh, data + pos, sizeof(bmfh) );
pos += sizeof(bmfh);
if(bmfh.bfType != 0x4d42)
{
AfxMessageBox("This is not a bmp file!");
return -1;
}
//读位图信息头
int infoSize = bmfh.bfOffBits - sizeof(bmfh);
bmi = (LPBITMAPINFO)new BYTE[infoSize];
memcpy((LPVOID)bmi, data + pos, infoSize);
pos += infoSize;
if(bmi->bmiHeader.biBitCount!=1 && bmi->bmiHeader.biBitCount!=4 && bmi->bmiHeader.biBitCount!=8 && bmi->bmiHeader.biBitCount!=24)
{
AfxMessageBox("The number of colors is not valid!");
return -2;
}
//读图像数据
pBits = new BYTE[bmi->bmiHeader.biSizeImage];
//file.Read( (LPVOID)pBits, bmi->bmiHeader.biSizeImage);
memcpy((LPVOID)pBits, data + pos, bmi->bmiHeader.biSizeImage);
pos += bmi->bmiHeader.biSizeImage;
return 0;
}
void OnPaint()
{
CPaintDC dc(this); // device context for painting
// TODO: Add your message handler code here
// Do not call CDialog::OnPaint() for painting messages
if (bmi != NULL)
{
int width = bmi->bmiHeader.biWidth;
int height = bmi->bmiHeader.biHeight;
int xDest = 0;
int yDest = 0;
int nRate = 2;
CRect rect;
GetClientRect(rect);//获取客户区大小,如果需要画整个位图,可以根据需要修改
xDest = (rect.Width() - width * nRate)/2;
yDest = (rect.Height() - height * nRate)/2 + 76;
StretchDIBits(dc.GetSafeHdc(),xDest,yDest,bmi->bmiHeader.biWidth * nRate,bmi->bmiHeader.biHeight * nRate,0,0,bmi->bmiHeader.biWidth,bmi->bmiHeader.biHeight,pBits,bmi,DIB_RGB_COLORS,SRCCOPY);
}
}
2)以图像数据块作为数据源的显示方式(格式任意)
int ConvertToBitmap(CBitmap &bitmap,unsigned char *Img,int SizeX, int SizeY, int Channels)
{
unsigned char*pImage;
pImage = Img;
int byteSize = 0;
int _sizeX = SizeX,_sizeY = SizeY,bds = Channels,_bands = Channels;
if(NULL == pImage)
{
return 0;
}
//注释该if分支,可减少嵌套结构,有利于阅读和优化 liu_sh 2012-5-17
//单通道图
if (bds == 1 )
{
int widthBytes = (_sizeX * 3 * 8 + 31) / 32 * 4;
byteSize = widthBytes * _sizeY;
int newlen = _sizeX * _sizeY * 3;
unsigned char * dstData = new unsigned char[newlen];
unsigned char * srcData = pImage;
for (int i = 0 ; i < 3 ; i ++)
{
for (int j = 0 ; j < _sizeX * _sizeY ; j ++)
{
dstData[i * _sizeX * _sizeY + j] = srcData[j];
}
}
debugout("dst data set suc");
if (dstData != NULL && byteSize)
{
BITMAPINFO bmpinfo;
memset(&bmpinfo, 0, sizeof(bmpinfo));
bmpinfo.bmiHeader.biBitCount = 8 * 3;//每个像素的二进制位数
bmpinfo.bmiHeader.biHeight = _sizeY;//图像高度
bmpinfo.bmiHeader.biPlanes = 1;//面数,必须设为
bmpinfo.bmiHeader.biSize = sizeof(bmpinfo.bmiHeader);//bmpinfo.bmiHeader的大小
bmpinfo.bmiHeader.biSizeImage = (DWORD)byteSize;//图像数据区大小,注意一个扫描行所占的字节数必须是的倍数,不足用填充.也就是如果宽*3不是的倍数就要加到是的倍数.*3是相当于位来说的.
bmpinfo.bmiHeader.biWidth = _sizeX;//图像宽度
bitmap.DeleteObject();
HBITMAP hBitmap;
hBitmap = CreateDIBSection(NULL,&bmpinfo, DIB_RGB_COLORS ,NULL ,0, 0);
bitmap.Attach(hBitmap);
if (!bitmap.m_hObject)
{
delete[] dstData;//防止内存泄露 liu_sh 2012-5-22
dstData=NULL;
return -1;
}
BITMAP bmp;
bitmap.GetBitmap(&bmp);
unsigned char* buff = new unsigned char[byteSize];
ConvertFromChannelToDib(dstData, buff, _sizeX, _sizeY, 3);
memcpy(bmp.bmBits, buff, byteSize);
delete[] buff;
buff = NULL;
}
if(NULL != dstData)
{
delete []dstData;
dstData = NULL;
}
}
else //多通道图
{
int widthBytes = (_sizeX * _bands * 8 + 31) / 32 * 4;//计算每行需要的字节数
byteSize = widthBytes * _sizeY;//计算图像占用的总字节数
if(pImage == NULL || byteSize <=0) //此时无法转换图像
return 0;
//if (pImage != NULL && byteSize)
//{
BITMAPINFO bmpinfo;
memset(&bmpinfo, 0, sizeof(bmpinfo));
bmpinfo.bmiHeader.biBitCount = 8 * _bands;//每个像素的二进制位数
bmpinfo.bmiHeader.biHeight = _sizeY;//图像高度
bmpinfo.bmiHeader.biPlanes=1;//面数,必须设为
bmpinfo.bmiHeader.biSize=sizeof(bmpinfo.bmiHeader);//bmpinfo.bmiHeader的大小
bmpinfo.bmiHeader.biSizeImage = (DWORD)byteSize;//图像数据区大小,注意一个扫描行所占的字节数必须是的倍数,不足用填充.也就是如果宽*3不是的倍数就要加到是的倍数.*3是相当于位来说的.
bmpinfo.bmiHeader.biWidth = _sizeX;//图像宽度
bitmap.DeleteObject();
HBITMAP hBitmap;
hBitmap = CreateDIBSection(NULL,&bmpinfo, DIB_RGB_COLORS ,NULL ,0, 0);
bitmap.Attach(hBitmap);
if (!bitmap.m_hObject)
return -1;
BITMAP bmp;
bitmap.GetBitmap(&bmp);
unsigned char* buff = new unsigned char[byteSize];
memset(buff, 0, byteSize);
ConvertFromChannelToDib(pImage, buff, _sizeX, _sizeY, _bands, byteSize);
memcpy(bmp.bmBits, buff, byteSize);
delete[] buff;
//}// end of if (pImage != NULL && byteSize) liu_sh 2012-5-17
}
return 0;
}
void ConvertFromChannelToDib(unsigned char * srcData, unsigned char * dstData, int SizeX , int SizeY , int nChannels, int Len)
{
int i, j, k;
unsigned char *pcolor[3];
CString logStr;
if(NULL == srcData || NULL == dstData || SizeX <=0 || SizeY <=0 || nChannels <=0 )
{
return;
}
int widthBytes = (SizeX * nChannels * 8 + 31) / 32 * 4;
for (k=0; k<nChannels; k++)
pcolor[k] = srcData + SizeX * SizeY * k;
for (i=0; i<SizeY; i++)
{
for (j=0; j<SizeX; j++)
{
for (k=0; k<nChannels; k++)
{
dstData[widthBytes * (SizeY - i -1) + nChannels * j + k] = *pcolor[nChannels - 1 - k];
pcolor[nChannels - 1 - k]++;
}
}
for (k=0; k<widthBytes - SizeX * 3; k++)
dstData[widthBytes * (SizeY - i -1) + SizeX * 3 + k] = 0;
}
}
unsigned char* m_imgData = NULL; //读入的数据块信息
int m_nSizeX; // 传入的数据块的宽度
int m_nSizeY; // 传入的数据块的高度
int m_nChannels ; // 传入的数据块的通道数
void OnPaint()
{
CPaintDC dc(this); // device context for painting
{
if (m_imgData != NULL)
{
CWnd *pwnd = GetDlgItem(IDC_PIC1); // 定义的picture控件
pwnd->ShowWindow(SW_SHOW);
if(pwnd == NULL)
{
return;
}
CDC *pDC = pwnd->GetDC();
if(pDC == NULL)
{
return;
}
CRect rect;
pwnd->GetClientRect(&rect);
CDC memDC;
memDC.CreateCompatibleDC(pDC);
CBitmap* pOldBmp;
CBitmap bmp;
ConvertToBitmap(bmp,m_imgData ,m_nSizeX,m_nSizeY,m_nChannels);
if (!bmp.m_hObject)
{
return;
}
pOldBmp = memDC.SelectObject(&bmp);
try
{
pDC->BitBlt(0, 0, rect.Width(), rect.Height(), &memDC, 0, 0, SRCCOPY);
}
catch(...)
{
debugout("\n\n+++pDC->BitBlt error+++\n\n");
}
debugout("###################xiejianping 010097");
memDC.SelectObject(pOldBmp);
ReleaseDC(pDC);
memDC.DeleteDC();
if (m_imgData != NULL)
{
delete [] m_imgData;
m_imgData = NULL;
}
}
}
}