在VC中,位图显示一般有现成的方式,如使用picture控件、GetDC()->StretchBlt、::BitBlt等,但这些方式都是高层的封装,让你不清楚一副位图是如何解析并显示到DC上的。实际应用中,比如图像处理,视频显示等,需要操作到位图中的像素,这需要弄明白位图文件如何组成,网上有太多的位图文件格式说明,下面借助实例和SetPixel函数完成解析与显示。
读入一幅位图,结合位图文档说明,按着F5、F10把程序走一遍,你就会把位图弄的明明白白。
源码打包放在:http://download.csdn.net/detail/dijkstar/7014189
- void CTestDlg::OnButton1()
- {
- //读入位图文件名
- char *filename = "720bmp16.bmp";
- CDC *pDC = GetDC();
- //
- // 一次性将位图文件读入到内容中,待处理
- //
- CFile f;
- f.Open(filename, CFile::modeRead);
- char* buff = (char*)malloc(f.GetLength());
- f.SeekToBegin();
- f.Read(buff, f.GetLength());
- //
- BITMAPFILEHEADER *fileheader = NULL; //数据结构大小为14
- BITMAPINFO *info = NULL; //数据结构大小为40
- fileheader = (BITMAPFILEHEADER*)buff;
- if(fileheader->bfType!=0x4D42)
- {
- AfxMessageBox("不是BMP文件");
- f.Close();
- return ;
- }
- //位图信息区域,在偏移14处
- info = (BITMAPINFO*)(buff+(sizeof(BITMAPFILEHEADER)));
- //位图的宽和高
- int width = info->bmiHeader.biWidth;
- int height= info->bmiHeader.biHeight;
- //指向位图像素区域
- char* buffer = buff+fileheader->bfOffBits;
- //
- // 显示位图的一些基本信息
- //
- CString str;
- str.Format("位图大小= %d\n"
- "位图数据起始偏移 = %d\n"
- "BITMAPINFOHEADER.biSize = %d\n"
- "宽=%d, 高=%d\n"
- "颜色位数=%d\n"
- "压缩=%d\n"
- "biSizeImage=%d\n"
- "biClrUsed=%d\n"
- "biClrImportant=%d",
- fileheader->bfSize, //位图大小
- fileheader->bfOffBits, //位图数据起始偏移
- info->bmiHeader.biSize,
- info->bmiHeader.biWidth,
- info->bmiHeader.biHeight,
- info->bmiHeader.biBitCount,
- info->bmiHeader.biCompression,
- info->bmiHeader.biSizeImage,
- info->bmiHeader.biClrUsed,
- info->bmiHeader.biClrImportant
- );
- AfxMessageBox(str);
- int i,j;
- //
- // 单色图的解析
- //
- if(info->bmiHeader.biBitCount==1)
- {
- int n=0;
- int color[500][500];
- if(height>0)
- {
- //height>0 表示图片颠倒
- for(i=0; i<height; i++)
- for(j=0; j<width; j=j+8)
- {
- int k=7;
- while(k>=0)
- {
- color[i][k+j]=buffer[n]%2;
- buffer[n]=buffer[n]/2;
- k--;
- }
- n++;
- }
- for(i=0; i<height; i++)
- for(j=0; j<width; j++)
- {
- if(color[i][j] == 0)
- {
- pDC->SetPixel(j,height-i,RGB(0,0,0));
- }
- if(color[i][j] == 1)
- {
- pDC->SetPixel(j,height-i,RGB(255,255,255));
- }
- }
- }
- else
- {
- for(i=0; i<0-height; i++)
- for(j=0; j<width; j=j+8)
- {
- int k=7;
- while(k>=0)
- {
- color[i][k+j]=buffer[n]%2;
- buffer[n]=buffer[n]/2;
- k--;
- }
- n++;
- }
- for(i=0; i<0-height; i++)
- for(j=0; j<width; j++)
- {
- if(color[i][j] == 0)
- {
- pDC->SetPixel(j,i,RGB(0,0,0));
- }
- if(color[i][j] == 1)
- {
- pDC->SetPixel(j,i,RGB(255,255,255));
- }
- }
- }
- }
- //
- // 16色图的解析
- //
- else if(info->bmiHeader.biBitCount==4)
- {
- int pitch;
- if(width%8==0)
- pitch=width;
- else
- pitch=width+8-width%8;
- //调色板数据
- RGBQUAD quad[16];
- memcpy(quad, buff+fileheader->bfOffBits-sizeof(quad), sizeof(quad));
- //指向真正的像素数据
- buffer = buff+fileheader->bfOffBits;
- if(height>0)
- {
- //height>0 表示图片颠倒
- for(i=0; i<height; i++)
- for(j=0; j<width; j++)
- {
- int index;
- if(j%2==0)
- index = buffer[(i*pitch+j)/2]/16;
- if(j%2==1)
- index = buffer[(i*pitch+j)/2]%16;
- unsigned char r=quad[index].rgbRed;
- unsigned char g=quad[index].rgbGreen;
- unsigned char b=quad[index].rgbBlue;
- pDC->SetPixel(j,height-i,RGB(r,g,b));
- }
- }
- else
- {
- for(i=0; i<0-height; i++)
- for(j=0; j<width; j++)
- {
- int index;
- if(j%2==0)
- index = buffer[(i*pitch+j)/2]/16;
- if(j%2==1)
- index = buffer[(i*pitch+j)/2]%16;
- unsigned char r=quad[index].rgbRed;
- unsigned char g=quad[index].rgbGreen;
- unsigned char b=quad[index].rgbBlue;
- pDC->SetPixel(j,i,RGB(r,g,b));
- }
- }
- }
- //
- // 256色(8位)图的解析
- //
- else if(info->bmiHeader.biBitCount==8)
- {
- int pitch;
- if(width%4==0)
- {
- pitch=width;
- }
- else
- {
- pitch=width+4-width%4;
- }
- //8位位图,有调试板数据
- RGBQUAD quad[256] = {0};
- memcpy(quad, buff+fileheader->bfOffBits-sizeof(quad), sizeof(quad));
- // 指向像素数据的起始偏移(其实并不是像素,8位位图的“像素”值代入调色板的下标,
- // 得到的值才是真正的像素)
- buffer = buff+fileheader->bfOffBits;
- //显示
- if(height>0)
- {
- //height>0 表示图片颠倒
- for(int i=0;i<height;i++)
- {
- for(int j=0;j<width;j++)
- {
- int index=buffer[i*pitch+j];
- UCHAR r=quad[index].rgbRed;
- UCHAR g=quad[index].rgbGreen;
- UCHAR b=quad[index].rgbBlue;
- pDC->SetPixel(j, height-i, RGB(r,g,b));
- }
- }
- }
- else
- {
- for(int i=0;i<0-height;i++)
- {
- for(int j=0;j<width;j++)
- {
- int index=buffer[i*pitch+j];
- UCHAR r=quad[index].rgbRed;
- UCHAR g=quad[index].rgbGreen;
- UCHAR b=quad[index].rgbBlue;
- pDC->SetPixel(j,i,RGB(r,g,b));
- }
- }
- }
- }
- //
- // 65536色(16位)图解析
- //
- else if(info->bmiHeader.biBitCount==16)
- {
- int pitch=width+width%2;
- if(height>0)
- {
- //height>0 表示图片颠倒
- if(info->bmiHeader.biCompression==BI_RGB)
- {
- //该模式只有555
- for(int i=0;i<height;i++)
- {
- for(int j=0;j<width;j++)
- {
- // 555 格式
- unsigned char b=buffer[(i*pitch+j)*2]&0x1F;
- unsigned char g=(((buffer[(i*pitch+j)*2+1]<<6)&0xFF)>>3)+(buffer[(i*pitch+j)*2]>>5);
- unsigned char r=(buffer[(i*pitch+j)*2+1]<<1)>>3;
- pDC->SetPixel(j,height-i,RGB((r*0xFF)/0x1F,(g*0xFF)/0x1F,(b*0xFF)/0x1F));
- }
- }
- }
- if(info->bmiHeader.biCompression==BI_BITFIELDS)
- {
- //该模式在bitmapinfoheader之后存在RGB掩码 每个掩码1 DWORD
- //fseek(fp,fileheader.bfOffBits-sizeof(DWORD )*3,0);
- DWORD rMask;
- //fread(&rMask,sizeof(DWORD ),1,fp);
- memcpy(&rMask, buff+fileheader->bfOffBits-sizeof(DWORD )*3, sizeof(DWORD ));
- if(rMask==0x7C00)
- {
- // 5 5 5 格式
- //MessageBeep(0);
- for(int i=0;i<height;i++)
- {
- for(int j=0;j<width;j++)
- {
- unsigned char b=buffer[(i*pitch+j)*2]&0x1F;
- unsigned char g=(((buffer[(i*pitch+j)*2+1]<<6)&0xFF)>>3)+(buffer[(i*pitch+j)*2]>>5);
- unsigned char r=(buffer[(i*pitch+j)*2+1]<<1)>>3;
- pDC->SetPixel(j,height-i,RGB((r*0xFF)/0x1F,(g*0xFF)/0x1F,(b*0xFF)/0x1F));
- }
- }
- }
- if(rMask==0xF800)
- {
- //5 6 5 格式
- for(int i=0;i<height;i++)
- {
- for(int j=0;j<width;j++)
- {
- UCHAR b=buffer[(i*pitch+j)*2]&0x1F;
- UCHAR g=(((buffer[(i*pitch+j)*2+1]<<5)&0xFF)>>2)+(buffer[(i*pitch+j)*2]>>5);
- UCHAR r=buffer[(i*pitch+j)*2+1]>>3;
- pDC->SetPixel(j,height-i,RGB(r*0xFF/0x1F,g*0xFF/0x3F,b*0xFF/0x1F));
- }
- }
- }
- }
- }
- else
- {
- if(info->bmiHeader.biCompression==BI_RGB)
- {
- //该模式只有555
- for(int i=0;i<0-height;i++){
- for(int j=0;j<width;j++){
- //5 5 5 格式
- UCHAR b=buffer[(i*pitch+j)*2]&0x1F;
- UCHAR g=(((buffer[(i*pitch+j)*2+1]<<6)&0xFF)>>3)+(buffer[(i*pitch+j)*2]>>5);
- UCHAR r=(buffer[(i*pitch+j)*2+1]<<1)>>3;
- pDC->SetPixel(j,i,RGB((r*0xFF)/0x1F,(g*0xFF)/0x1F,(b*0xFF)/0x1F));
- }
- }
- }
- if(info->bmiHeader.biCompression==BI_BITFIELDS)
- {
- //该模式在bitmapinfoheader之后存在RGB掩码 每个掩码1 DWORD
- //fseek(fp,fileheader.bfOffBits-sizeof(DWORD )*3,0);
- DWORD rMask;
- //fread(&rMask,sizeof(DWORD ),1,fp);
- memcpy(&rMask, buff+fileheader->bfOffBits-sizeof(DWORD )*3, sizeof(DWORD ));
- if(rMask==0x7C00)
- {
- // 5 5 5 格式
- MessageBeep(0);
- for(int i=0;i<0-height;i++)
- {
- for(int j=0;j<width;j++)
- {
- UCHAR b=buffer[(i*pitch+j)*2]&0x1F;
- UCHAR g=(((buffer[(i*pitch+j)*2+1]<<6)&0xFF)>>3)+(buffer[(i*pitch+j)*2]>>5);
- UCHAR r=(buffer[(i*pitch+j)*2+1]<<1)>>3;
- pDC->SetPixel(j,i,RGB((r*0xFF)/0x1F,(g*0xFF)/0x1F,(b*0xFF)/0x1F));
- }
- }
- }
- if(rMask==0xF800)
- {
- //565 格式
- for(int i=0;i<0-height;i++)
- {
- for(int j=0;j<width;j++)
- {
- UCHAR b=buffer[(i*pitch+j)*2]&0x1F;
- UCHAR g=(((buffer[(i*pitch+j)*2+1]<<5)&0xFF)>>2)+(buffer[(i*pitch+j)*2]>>5);
- UCHAR r=buffer[(i*pitch+j)*2+1]>>3;
- pDC->SetPixel(j,i,RGB(r*0xFF/0x1F,g*0xFF/0x3F,b*0xFF/0x1F));
- }
- }
- }
- }
- }
- }
- //
- // 24位图解析
- //
- else if(info->bmiHeader.biBitCount==24)
- {
- int pitch=width%4;
- // bgr
- int i,j;
- if(height>0)
- {
- //height>0 表示图片颠倒
- for(i=0;i<height;i++)
- {
- int realPitch=i*pitch;
- for(j=0;j<width;j++)
- {
- unsigned char b=buffer[(i*width+j)*3+realPitch];
- unsigned char g=buffer[(i*width+j)*3+1+realPitch];
- unsigned char r=buffer[(i*width+j)*3+2+realPitch];
- pDC->SetPixel(j,height-i,RGB(r,g,b));
- }
- }
- }
- else
- {
- for(i=0;i<0-height;i++)
- {
- int realPitch=i*pitch;
- for(j=0;j<width;j++)
- {
- unsigned char r=buffer[(i*width+j)*3+realPitch];
- unsigned char g=buffer[(i*width+j)*3+1+realPitch];
- unsigned char b=buffer[(i*width+j)*3+2+realPitch];
- pDC->SetPixel(j,i,RGB(r,g,b));
- }
- }
- }
- }
- //
- // 32位图进行解析
- //
- else if(info->bmiHeader.biBitCount==32)
- {
- // bgra
- if(height>0)
- {
- //height>0 表示图片颠倒
- for(i=0;i<height;i++)
- {
- for(j=0;j<width;j++)
- {
- unsigned char b=buffer[(i*width+j)*4];
- unsigned char g=buffer[(i*width+j)*4+1];
- unsigned char r=buffer[(i*width+j)*4+2];
- pDC->SetPixel(j,height-i, RGB(r,g,b));
- }
- }
- }
- else
- {
- for(i=0;i<0-height;i++)
- {
- for(j=0;j<width;j++)
- {
- unsigned char b=buffer[(i*width+j)*4];
- unsigned char g=buffer[(i*width+j)*4+1];
- unsigned char r=buffer[(i*width+j)*4+2];
- pDC->SetPixel(j, i, RGB(r,g,b));
- }
- }
- }
- }
- f.Close();
- buff = NULL;
- free(buff);
- ReleaseDC(pDC);
- }