1. 程式人生 > >VC下2、4、8、16、24、32位點陣圖的資料解析與顯示

VC下2、4、8、16、24、32位點陣圖的資料解析與顯示

在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);
}