Bitmap位元影像檔案讀取、儲存、螢幕截圖

來源:互聯網
上載者:User

        雖然現在網上已經有很多位元影像讀取、儲存的文章,很多寫的都很詳細,提供的原始碼功能也很強大,但是我仍然要自己重寫一個位元影像載入程式。主要是因為這些大牛們的文章寫的太深奧了,代碼功能太強大了,以至於像我這樣的菜鳥讀不懂。所以,我要力求簡潔。省略掉一些細節,比方說調色盤。為了能夠方便容易操作,我的程式只支援24位以上的位元影像檔案載入。

        

       首先,瞭解下位元影像檔案的結構。24位以上的位元影像檔案包含3個部分:位元影像檔案頭(BITMAPFILEHEADER)、位元影像資訊頭(BITMAPINFOHEADER)、位元影像資料。

下面是MSDN中兩個資訊頭的具體定義:

typedef struct tagBITMAPFILEHEADER {   WORD    bfType; //映像類型:必須是‘BM’(BM的16進位編碼為:0x4d42)  DWORD   bfSize; //從檔案開頭到資料的位移量。也就是結構BITMAPFILEHEADER和結構BITMAPINFOHEADER的大小  WORD    bfReserved1; //保留值。必須為0  WORD    bfReserved2; //保留值。必須為0  DWORD   bfOffBits; //檔案大小。包含著兩個結構,以及資料的總大小。} BITMAPFILEHEADER, *PBITMAPFILEHEADER; typedef struct tagBITMAPINFOHEADER{  DWORD  biSize; //當前結構體的大小。  LONG   biWidth; //位元影像的寬度。單位是像素  LONG   biHeight; //位元影像高度。單位是像素  WORD   biPlanes; //位元影像平面個數。必須是1  WORD   biBitCount //位元影像的位元,也就是位元影像深度。可以是1、4、8、16、24、32。16位以下的位元影像檔案含有調色盤資訊。  DWORD  biCompression; //壓縮方式。位元影像沒有壓縮,賦予BI_RGB參數(也就是0)。  DWORD  biSizeImage; //位元影像資料佔用的位元組數。可以設定為預設值0。  LONG   biXPelsPerMeter; //指定目標裝置水平解析度,單位是每米的像素個數。可設定為0  LONG   biYPelsPerMeter; //指定目標裝置垂直解析度,同上。  DWORD  biClrUsed; //指定本映像實際用到的像素。可設定為0  DWORD  biClrImportant; //指定本映像重要的顏色個數。可設定為0,表示所有顏色都重要。} BITMAPINFOHEADER, *PBITMAPINFOHEADER; 


接下來就是位元影像資料了:

位元影像按行存貯,位元影像的寬度不等於位元影像的行位元組數。每個像素佔用 biBitCount/8 個位元組,且每行佔用的位元組數必須是4位元組的整數倍!例如:101*101*24的位元影像,行佔用位元組數為:101*3=303,而303%4!=0,所以行佔用位元組數需修改為304,此時位元影像資料的實際大小為304*101,上面的biSizeImage就可設定為304*101。

下面是儲存位元影像檔案的結構體填充例:

    BITMAPFILEHEADER bmheader;    memset(&bmheader,0,sizeof(bmheader));    bmheader.bfType=0x4d42;     //映像格式。必須為'BM'格式。    bmheader.bfOffBits = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER); //從檔案開頭到資料的位移量    bmheader.bfSize = m_nWidthBytes*m_nHeight + bmheader.bfOffBits;//檔案大小    BITMAPINFOHEADER bmInfo;    memset(&bmInfo,0,sizeof(bmInfo));    bmInfo.biSize = sizeof(bmInfo);    bmInfo.biWidth = m_nWidth;     bmInfo.biHeight = m_nHeight;     bmInfo.biPlanes = 1;     bmInfo.biBitCount =  m_nDeep;    bmInfo.biCompression = BI_RGB;

註:m_nWidthBytes 可這樣計算:int m_nWidthBytes = ((m_nWidth*m_nDeep/8 + 3)/4) * 4;

下面是一個用來建立DIB位元影像,獲得HBITMAP控制代碼一個API。

HBITMAP CreateDIBSection(
  HDC hdc,                 // handle to DC
  CONST BITMAPINFO *pbmi,  // bitmap data
  UINT iUsage,             // data type indicator
  VOID **ppvBits,          // bit values
  HANDLE hSection,         // handle to file mapping object
  DWORD dwOffset           // offset to bitmap bit values
);

(這裡就不詳細介紹了,可以去百科裡看看,如:http://www.hudong.com/wiki/CreateDIBSection)


大致說下開啟檔案檔案的流程:

1.讀入檔案頭BITMAPFILEHEADER資料。

2.讀入位元影像資訊頭BITMAPINFOHEADER資料。

3.讀取位元影像資料。

4.使用CreateDIBSection建立Dib位元影像,將讀取到的資料拷貝給Dib位元影像。

然後就可以使用Dib位元影像控制代碼進行位元影像的操作了。


儲存檔案流程:

1.填寫檔案頭BITMAPFILEHEADER,並寫入檔案。

2.填寫位元影像資訊頭BITMAPINFOHEADER,並寫入檔案。

3.獲得位元影像資料(GetBitmapBits,或者是在CreateDIBSection時,將資料地址記錄下來),將資料寫入檔案。


功能(參考範例見文章末尾):

1.建立掩碼DC(CreateCompatibelDC),掩碼位元影像(CreateCompatibleBitmap),將位元影像選到DC中。

2.將 要的視窗的DC內容拷貝(BitBlt)給掩碼DC(也就是拷貝到了掩碼位元影像上了)。

3.接著就是上面說到的儲存檔案流程了。



附件:我將上面的操作封裝起來。

//DIBBitmap.h#pragma onceclass CDIBBitmap{public://方法    CDIBBitmap(void);    ~CDIBBitmap(void);    bool create(HDC hdc,int width,int height,int deep);//建立位元影像    bool create(HDC hDC,HBITMAP hBitmap);//通過拷貝來建立位元影像    bool load(HDC hDC,char *szFileName);//從檔案中價值位元影像    bool save(char *szFileName);//儲存位元影像到檔案    void clear(void);//清空資料    void sampleRender(HDC hDC,int x,int y);//簡單顯示public://屬性    //獲得位元影像    inline HBITMAP getBitmap(void){ return m_hDibBmp; }    //獲得資料    inline BYTE * getBmpData(void){ return m_pBmpData; }    //獲得寬度    inline int  getWidth(void){ return m_nWidth; }    //獲得高度    inline int  getHeight(void){ return m_nHeight; }    //獲得位元深度    inline int  getDeep(void){ return m_nDeep; }    //獲得一行位元組數    inline int  getWidthBytes(void){ return m_nWidthBytes; }   protected://成員    HBITMAP     m_hDibBmp;    BYTE        *m_pBmpData;//指向位元影像資料    int         m_nWidth;   //寬度。(單位:像素pixel)    int         m_nHeight;  //高度。pixel    int         m_nDeep;    //深度。bit。深度必須大於24位    int         m_nWidthBytes;//一行所需的位元組數。必須是4位元組的整數倍。};

//DIBBitmap.cpp#include <Windows.h>#include <stdio.h>#include "DIBBitmap.h"//////////////////////////////////////////////////////////////////////////CDIBBitmap::CDIBBitmap(void){    m_hDibBmp = NULL;    m_pBmpData = NULL;    m_nWidth = 0;   //寬度。(單位:像素pixel)    m_nHeight = 0;  //高度。pixel    m_nDeep = 0;    //深度。bit。深度必須大於24位    m_nWidthBytes = 0;}CDIBBitmap::~CDIBBitmap(void){    clear();}bool CDIBBitmap::create(HDC hdc,int width,int height,int deep){    clear();    m_nWidth = width;    m_nHeight = height;    m_nDeep = deep;    BITMAPINFO bmInfo;    memset(&bmInfo,0,sizeof(bmInfo));    bmInfo.bmiHeader.biSize = sizeof(bmInfo);    bmInfo.bmiHeader.biWidth = m_nWidth;     bmInfo.bmiHeader.biHeight = m_nHeight;     bmInfo.bmiHeader.biPlanes = 1;     bmInfo.bmiHeader.biBitCount =  m_nDeep;    bmInfo.bmiHeader.biCompression = BI_RGB;     m_hDibBmp = CreateDIBSection(hdc,&bmInfo,DIB_RGB_COLORS,(void**)&m_pBmpData,NULL,0);    if (m_hDibBmp == NULL)    {        return false;    }        m_nWidthBytes = ((m_nWidth*m_nDeep/8 + 3)/4) * 4;    return true;}bool CDIBBitmap::create(HDC hDC,HBITMAP hBitmap){    if(NULL==hDC || NULL==hBitmap)    {        return false;    }    //獲得位元影像資訊    BITMAP bm;    GetObject(hBitmap,sizeof(bm),&bm);    //建立位元影像    if(!create(hDC,bm.bmWidth,bm.bmHeight,bm.bmBitsPixel))    {        return false;    }    //獲得hBitmap資料,並拷貝給Dib位元影像    GetBitmapBits(hBitmap,bm.bmWidthBytes*bm.bmHeight,getBmpData());    return true;}void CDIBBitmap::clear(void){    if (m_hDibBmp != NULL)    {        DeleteObject(m_hDibBmp);    }    m_hDibBmp = NULL;    m_pBmpData = NULL;}void CDIBBitmap::sampleRender(HDC hDC,int x,int y){    HDC memDC = CreateCompatibleDC(0);    SelectObject(memDC,m_hDibBmp);    BitBlt(hDC,x,y,m_nWidth,m_nHeight,memDC,0,0,SRCCOPY);    DeleteDC(memDC);}bool CDIBBitmap::load(HDC hDC,char *szFileName){    FILE *fp = NULL;    fopen_s(&fp,szFileName,"rb");    if (NULL == fp)    {        return false;    }    //讀入檔案頭    BITMAPFILEHEADER bmheader;    if(fread(&bmheader,sizeof(bmheader),1,fp) !=1 )    {        fclose(fp);        return false;    }    //讀入位元影像資訊頭    BITMAPINFOHEADER bmInfo;    if(fread(&bmInfo,sizeof(bmInfo),1,fp) !=1 )    {        fclose(fp);        return false;    }    /*註:目前程式不支援調色盤資料位元圖載入。    */    if (bmInfo.biBitCount < 16)    {        return false;    }    //建立DIB位元影像    if (!create(hDC,bmInfo.biWidth,bmInfo.biHeight,bmInfo.biBitCount))    {        fclose(fp);        return false;    }    //讀入位元影像資料    if(fread(m_pBmpData,m_nWidthBytes,m_nHeight,fp) != m_nHeight)    {        fclose(fp);        return false;    }    fclose(fp);    return true;}bool CDIBBitmap::save(char *szFileName){    if (NULL==m_hDibBmp || NULL==m_pBmpData)     {        return false;    }    FILE *fp = NULL;    fopen_s(&fp,szFileName,"wb");    if (NULL == fp)    {        return false;    }    BITMAPFILEHEADER bmheader;    memset(&bmheader,0,sizeof(bmheader));    bmheader.bfType=0x4d42;     //映像格式。必須為'BM'格式。    bmheader.bfOffBits = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER); //從檔案開頭到資料的位移量    bmheader.bfSize = m_nWidthBytes*m_nHeight + bmheader.bfOffBits;//檔案大小    BITMAPINFOHEADER bmInfo;    memset(&bmInfo,0,sizeof(bmInfo));    bmInfo.biSize = sizeof(bmInfo);    bmInfo.biWidth = m_nWidth;     bmInfo.biHeight = m_nHeight;     bmInfo.biPlanes = 1;     bmInfo.biBitCount =  m_nDeep;    bmInfo.biCompression = BI_RGB;     if(fwrite(&bmheader,sizeof(bmheader),1,fp) != 1)    {        fclose(fp);        return false;    }    if(fwrite(&bmInfo,sizeof(bmInfo),1,fp) != 1)    {        fclose(fp);        return false;    }    for(int i=m_nHeight-1;i>=0;--i)    {        int index = m_nWidthBytes*i;        if(fwrite(m_pBmpData+index,m_nWidthBytes,1,fp) != 1)        {            fclose(fp);            return false;        }    }    fclose(fp);    return true;}//////////////////////////////////////////////////////////////////////////

功能參考代碼:

//獲得裝置描述表m_hDeviceContext=GetDC(m_hWnd);//建立掩碼dcm_hBackDC=CreateCompatibleDC(m_hDeviceContext);//建立掩碼位元影像m_bBackBitmap=CreateCompatibleBitmap(m_hDeviceContext,m_nWidth,m_nHeight);SelectObject(m_hBackDC,m_bBackBitmap);...將m_hDeviceContext的內容使用BitBlt拷貝給m_hBackDC...CDIBBitmap bmp;if(!bmp.create(m_hBackDC,m_bBackBitmap)){g_log.write("失敗!");}else{CreateDirectory(TEXT("shot"),NULL);char buffer[64];SYSTEMTIME tm;GetLocalTime(&tm);sprintf_s(buffer,64,"shot/%d_%d_%d_%d_%d_%d.bmp",tm.wYear,tm.wMonth,tm.wDay,tm.wHour,tm.wMinute,tm.wSecond);if(!bmp.save(buffer)){g_log.writex("儲存位元影像【%s】失敗!",buffer);}}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.