黑白BMP文件的读写和数据黑白图像显示

对于图像处理来说,如何从一幅bmp图像中读取它包含的信息,是十分重要的。对于matlab,只需要一句语句,足以。

im=imread('a.bmp');

而对于c++如何将文件读取到内存,或者将数据保存为bmp黑白图像,则需要研究图像是如何进行存储的。
一般的,黑白图像由文件头,信息头,调色板,最后才是位图矩阵信息组成。
文件头由图像的标识,大小,偏移量等组成,其定义为:

typedef struct tagBITMAPFILEHEADER {
        WORD    bfType;
        DWORD   bfSize;
        WORD    bfReserved1;
        WORD    bfReserved2;
        DWORD   bfOffBits;
} BITMAPFILEHEADER, FAR *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER;

而信息头则由文件的长宽等信息组成,其定义为:

typedef struct tagBITMAPINFOHEADER{
        DWORD      biSize;
        LONG       biWidth;
        LONG       biHeight;
        WORD       biPlanes;
        WORD       biBitCount;
        DWORD      biCompression;
        DWORD      biSizeImage;
        LONG       biXPelsPerMeter;
        LONG       biYPelsPerMeter;
        DWORD      biClrUsed;
        DWORD      biClrImportant;
} BITMAPINFOHEADER, FAR *LPBITMAPINFOHEADER, *PBITMAPINFOHEADER;

其后为调色板,黑白图像调色板则为:

typedef struct tagRGBQUAD {
        BYTE    rgbBlue;
        BYTE    rgbGreen;
        BYTE    rgbRed;
        BYTE    rgbReserved;
} RGBQUAD;

最后才是我们比较关注的二维图像信息,其中,信息的位数一般为8bit,最大值为255。

对于读取BMP黑白图像,程序可以这么写:

bool LoadFromFile(const char* str, unsigned char* & data, int & width, int & height)
{
    //以二进制方式打开图像文件
    ifstream fin(str,ios::in|ios::_Nocreate|ios::binary);
    if(!fin)
        return false;

    fin.seekg(0, ios::end);
    DWORD  size = fin.tellg();  

    //如果文件的大小小于1024+1024+40则放弃读入
    if(size < 14+1024+40)
    {
        return false;
    }
    pAllData = new BYTE[size];
    memset(pAllData, 0, size);

    fin.seekg(0, ios::beg);
    fin.read((char*)pAllData, size);

    //如果文件的头信息不为0x4d42,则不读入
    LPBITMAPFILEHEADER pBitMapFileHeader = (LPBITMAPFILEHEADER)pAllData;
    if(pBitMapFileHeader->bfType != 0x4d42)
    {
        pBitMapFileHeader = NULL;
        delete [] pAllData;

        return false;
    }

    //读取位图文件的宽和高
    LPBITMAPINFO pBitMapInfo = (LPBITMAPINFO) (pAllData + 14);
    width = pBitMapInfo->bmiHeader.biWidth;
    height = pBitMapInfo->bmiHeader.biHeight;

    //将位图矩阵读入内存
    data = new unsigned char[width*height];
    memcpy(data, pAllData + 14 + 40 + 1024, width*height);

    //删除数据,防止内存泄漏
    delete [] pAllData;

    return true;
}

对于将数据写到BMP黑白文件中去,程序可以这么写:

bool FiberWriteBitmap(UINT8* pImage, int biHeight , int biWidth, CString csPath)
{

    BITMAPFILEHEADER BitmapFileHead;
    BITMAPINFOHEADER BitmapInfoHead;

    BitmapInfoHead.biSize = 40;
    BitmapInfoHead.biBitCount = 8;
    BitmapInfoHead.biClrUsed = 256;
    BitmapInfoHead.biCompression = 0;
    BitmapInfoHead.biHeight = biHeight ;
    BitmapInfoHead.biPlanes = 1;    
    BitmapInfoHead.biClrImportant = 0;
    BitmapInfoHead.biWidth = biWidth;
    BitmapInfoHead.biXPelsPerMeter = 2835;//    72 dpi
    BitmapInfoHead.biYPelsPerMeter = 2835;
    BitmapInfoHead.biSizeImage = (DWORD)biHeight*biWidth;

    static RGBQUAD palette[256];
    for ( unsigned int i = 0; i< 256; i++ )
    {
        palette[i].rgbBlue = i;
        palette[i].rgbGreen = i;
        palette[i].rgbRed = i;
    }

    // Build fileheader and write
    BitmapFileHead.bfType=('M' << 8) + 'B'; 
    BitmapFileHead.bfOffBits=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+
        256*sizeof(RGBQUAD);
    BitmapFileHead.bfSize = BitmapFileHead.bfOffBits + BitmapInfoHead.biSizeImage;
    BitmapInfoHead.biClrUsed=256;
    BitmapInfoHead.biClrImportant=0;
    BitmapFileHead.bfReserved1=0;
    BitmapFileHead.bfReserved2=0;

    CFile file;
    if(!file.Open(csPath, CFile::modeCreate|CFile::modeWrite))
        return false;
    file.Write(&BitmapFileHead,sizeof(BITMAPFILEHEADER));
    file.Write(&BitmapInfoHead,sizeof(BITMAPINFOHEADER));
    file.Write(palette,sizeof(RGBQUAD)*256);
    file.Write(pImage,biHeight*biWidth);

    file.Close();   
    return TRUE;
}

将矩阵信息以黑白格式显示到屏幕上,程序为:

bool ShowDataToWindow(CDC *pDC,DWORD width, DWORD height, LPBYTE lpData, int xDest, int yDest, int DestWidth, int DestHeight, int xSrc, int ySrc, int SrcWidth, int SrcHeight)
{
    if(lpData == NULL)
        return false;

    LPBITMAPINFO lpBitMapInfo = (LPBITMAPINFO)new BYTE[40+1024];
        lpBitMapInfo->bmiHeader.biSize = 40;
        lpBitMapInfo->bmiHeader.biBitCount = 8;
        lpBitMapInfo->bmiHeader.biClrUsed = 256;
        lpBitMapInfo->bmiHeader.biCompression = 0;
        lpBitMapInfo->bmiHeader.biHeight = height;
        lpBitMapInfo->bmiHeader.biPlanes = 1;       
        lpBitMapInfo->bmiHeader.biClrImportant = 0;
        lpBitMapInfo->bmiHeader.biWidth = width;
        lpBitMapInfo->bmiHeader.biXPelsPerMeter = 2835;
        lpBitMapInfo->bmiHeader.biYPelsPerMeter = 2835;
        lpBitMapInfo->bmiHeader.biSizeImage = (DWORD)height*width;

    LPBYTE lpQuad = (LPBYTE)lpBitMapInfo;
        for(int i = 0;i<256;++i)
        {
            *(lpQuad+40+i*4+0) = (BYTE)i;
            *(lpQuad+40+i*4+1) = (BYTE)i;
            *(lpQuad+40+i*4+2) = (BYTE)i;
            *(lpQuad+40+i*4+3) = 0xcc;
        }
    pDC->SetStretchBltMode(COLORONCOLOR);
    StretchDIBits(pDC->GetSafeHdc(), xDest, yDest, DestWidth, DestHeight, 
        xSrc, ySrc, SrcWidth, SrcHeight, lpData, lpBitMapInfo, DIB_RGB_COLORS, SRCCOPY);
    delete[] lpBitMapInfo;
    return true;
}

你可能感兴趣的:(黑白位图文件的读写)