VC下2、4、8、16、24、32位點陣圖的資料解析與顯示
阿新 • • 發佈:2019-01-10
在VC中,點陣圖顯示一般有現成的方式,如使用picture控制元件、GetDC()->StretchBlt、::BitBlt等,但這些方式都是高層的封裝,讓你不清楚一副點陣圖是如何解析並顯示到DC上的。實際應用中,比如影象處理,視訊顯示等,需要操作到點陣圖中的畫素,這需要弄明白點陣圖檔案如何組成,網上有太多的點陣圖檔案格式說明,下面藉助例項和SetPixel函式完成解析與顯示。
讀入一幅點陣圖,結合點陣圖文件說明,按著F5、F10把程式走一遍,你就會把點陣圖弄的明明白白。
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); }