现在的位置: 首页 > 自动控制 > 工业·编程 > 正文

VC下2、4、8、16、24、32位位图的数据解析与显示

2014-01-07 22:18 工业·编程 ⁄ 共 12655字 ⁄ 字号 暂无评论

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

给我留言

留言无头像?