<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    weidagang2046的專欄

    物格而后知致
    隨筆 - 8, 文章 - 409, 評論 - 101, 引用 - 0
    數據加載中……

    位圖文件讀寫綜述

    作者:吉林大學 胡卓瑋一、位圖文件結構
    1. 位圖文件頭
    2. 位圖信息
      2.1 位圖信息頭
      2.2 顏色表
    3. 位圖數據

    二、位圖文件讀寫操作

    1. 類的聲明
    2. 位圖的讀取
    3. 位圖讀取過程中的調色板的創建和調用
    4. 位圖的顯示
    5. 位圖的存儲
    6. 新位圖的創建
    7. 其它問題

    三、CFG_DIB的使用


    下載本文配套代碼


    關于位圖文件操作的資料很多。為了方便開發人員的工作,寫下本文,介紹了位圖文件結構,在此基礎之上設計了通用類CFG_DIB,用于進行位圖文件的讀寫操作。

    一、位圖文件結構

    位圖文件由三部分組成:文件頭 + 位圖信息 + 位圖像素數據

    1、位圖文件頭。位圖文件頭主要用于識別位圖文件。以下是位圖文件頭結構的定義:

    typedef struct tagBITMAPFILEHEADER { // bmfh 
        WORD    bfType; 
        DWORD   bfSize; 
        WORD    bfReserved1; 
        WORD    bfReserved2; 
        DWORD   bfOffBits; 
    } BITMAPFILEHEADER;
    其中的bfType值應該是“BM”(0x4d42),標志該文件是位圖文件。bfSize的值是位圖文件的大小。
    2、位圖信息中所記錄的值用于分配內存,設置調色板信息,讀取像素值等。
    以下是位圖信息結構的定義:

    typedef struct tagBITMAPINFO {
        BITMAPINFOHEADER    bmiHeader;
        RGBQUAD             bmiColors[1];
    } BITMAPINFO;
    
    可見位圖信息也是由兩部分組成的:位圖信息頭 + 顏色表



    2.1位圖信息頭。位圖信息頭包含了單個像素所用字節數以及描述顏色的格式,此外還包括位圖的寬度、高度、目標設備的位平面數、圖像的壓縮格式。以下是位圖信息頭結構的定義:
    typedef struct tagBITMAPINFOHEADER{ // bmih 
        DWORD  biSize; 
        LONG   biWidth; 
        LONG   biHeight; 
        WORD   biPlanes; 
        WORD   biBitCount 
        DWORD  biCompression; 
        DWORD  biSizeImage; 
        LONG   biXPelsPerMeter; 
        LONG   biYPelsPerMeter; 
        DWORD  biClrUsed; 
        DWORD  biClrImportant; 
    } BITMAPINFOHEADER; 
    
    下表是對結構體當中各個成員的說明:
    結構成員
    說 明
    biSize結構BITMAPINFOHEADER的字節數,即sizeof(BITMAPINFOHEADER)*
    biWidth
    以像素為單位的圖像寬度*
    biHeight
    以像素為單位的圖像長度*
    biplanes
    目標設備的位平面數
    biBitCount
    每個像素的位數*(1)
    biCompression
    圖像的壓縮格式(這個值幾乎總是為0)
    biSizeImage
    以字節為單位的圖像數據的大小(對BI_RGB壓縮方式而言)
    biXPelsPermeter
    水平方向上的每米的像素個數
    biYpelsPerMeter
    垂直方向上的每米的像素個數
    biClrused
    調色板中實際使用的顏色數(2)
    biClrImportant
    現實位圖時必須的顏色數(3)

    說明:*是需要加以注意的部分,因為它們是我們在進行位圖操作時經常參考的變量
    (1)對于每個像素的字節數,分別有一下意義:
    0,用在JPEG格式中
    1,單色圖,調色板中含有兩種顏色,也就是我們通常說的黑白圖片
    4,16色圖
    8,256色圖,通常說的灰度圖
    16,64K圖,一般沒有調色板,圖像數據中每兩個字節表示一個像素,5個或6個位表示一個RGB分量
    24,16M真彩色圖,一般沒有調色板,圖像數據中每3個字節表示一個像素,每個字節表示一個RGB分量
    32,4G真彩色,一般沒有調色板,每4個字節表示一個像素,相對24位真彩圖而言,加入了一個透明度,即RGBA模式

    (2)這個值通常為0,表示使用biBitCount確定的全部顏色,例外是使用的顏色樹木小于制定的顏色深度的顏色數目的最大值。

    (3)這個值通常為0,表示所有的顏色都是必需的

    2.2顏色表。顏色表一般是針對16位一下的圖像而設置的,對于16位和16位以上的圖像,由于其位圖像素數據中直接對對應像素的RGB(A)顏色進行描述,因而省卻了調色板。而對于16位一下的圖像,由于其位圖像素數據中記錄的只是調色板索引值,因而需要根據這個索引到調色板去取得相應的RGB(A)顏色。顏色表的作用就是創建調色板。

    下圖是帶調色板和不帶調色板的位圖的簡單示意圖

    圖1 帶調色板和不帶調色板位圖之間的區別

    顏色表是由顏色表項組成的,顏色表項結構的定義如下:

    typedef struct tagRGBQUAD { // rgbq 
        BYTE    rgbBlue; 
        BYTE    rgbGreen; 
        BYTE    rgbRed; 
        BYTE    rgbReserved; 
    } RGBQUAD;
    其中需要注意的問題是,RGBQUAD結構中的顏色順序是BGR,而不是平常的RGB。

    3、位圖數據。最后,在位圖文件頭、位圖信息頭、位圖顏色表之后,便是位圖的主體部分:位圖數據。根據不同的位圖,位圖數據所占據的字節數也是不同的,比如,對于8位位圖,每個字節代表了一個像素,對于16位位圖,每兩個字節代表了一個像素,對于24位位圖,每三個字節代表了一個像素,對于32位位圖,每四個字節代表了一個像素。

    二、位圖文件讀寫操作

    認識了位圖文件的結構以后,對特定位圖文件進行讀寫操作就顯得簡單了。本文附帶的源代碼中包含了一個能夠方便進行位圖讀寫操作的C++類。以下給出該類的使用參考,對于實現代碼中的關鍵部分做出了講解。

    1、類的聲明

    class CFG_DIB : public CObject  
    {
    public:
    	//默認構造函數
    	CFG_DIB();
    	//構造函數,根據圖象寬和高,以及記錄每個象素所需字節數來初始化
    	CFG_DIB(int width, int height, int nBitCounts);
    	virtual ~CFG_DIB();
    
    public:
    	HBITMAP m_hBitmap;
    	LPBYTE m_lpDIBits;					//DIB位的起始位置
    	LPBITMAPINFOHEADER m_lpBMPHdr;		//BITMAPINFOHEADER信息
    	LPVOID m_lpvColorTable;				//顏色表信息
    	HPALETTE m_hPalette;				//條調色板
    
    private:
    	DWORD m_dwImageSize;				//非BITMAPINFOHEADER或BITMAPFILEHEADER的位
    	int m_nColorEntries;				//顏色表項的個數
    
    //顯示參數
    public:
    	CPoint m_Dest;						//目的矩形域的左上角坐標
    	CSize m_DestSize;					//顯示矩形的寬度和高度
    	CPoint m_Src;						//原矩形左下角坐標
    	CSize m_SrcSize;					//原矩形寬度和高度
    
    public:
    	void InitDestroy();							//初始化變量
    	void ComputePaletteSize(int nBitCounts);	//計算調色板大小
    	void ComputeImage();						//計算圖象大小
    
    	//從BMP文件中讀入DIB信息
    	BOOL ReadFile(CFile* pFile);
    	//從BMP文件中讀入DIB信息,與ReadFile不同的是使用CreateSection創建位圖位
    	BOOL ReadSection(CFile* pFile, CDC* pDC = NULL);
    	//將DIB寫入文件,保存成BMP圖片格式
    	BOOL WriteFile(CFile* pFile);
    	//創建新的位圖文件,根據參數width,height,nBitCounts分配內存空間
    	BOOL NewFile(int width, int height, int nBitCounts);
    	//關閉位圖文件
    	BOOL CloseFile();
    
    	//顯示位圖
    	BOOL Display(CDC* pDC);
    
    	HBITMAP CreateBitmap(CDC* pDC);				//用DIB創建DDB
    	HBITMAP CreateSection(CDC* pDC = NULL);		//創建位圖位數據,即象素數據
    	//如果DIB沒有顏色表,可以用邏輯調色板
    	BOOL SetLogPalette(CDC* pDC);
    	//如果DIB有顏色表,可以創建系統調色板
    	BOOL SetWinPalette();
    	//把DIB對象的邏輯調色板選進設備環境里,然后實現調色板
    	UINT UseLogPalette(CDC* pDC);
    
    	//得到BitmapInfoHeader的大小,包含顏色表數據
    	int GetHeaderSize()
    	{
    		return sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * m_nColorEntries;
    	}
    	//得到圖像的高度
    	int GetHeight()
    	{
    		if(m_lpBMPHdr == NULL) return 0;
    		return m_lpBMPHdr->biHeight;
    	}
    	//得到圖像的寬度
    	int GetWidth()
    	{
    		if(m_lpBMPHdr == NULL) return 0;
    		return m_lpBMPHdr->biWidth;
    	}
    	//得到圖像的大小
    	int GetImageSize()
    	{
    		return m_dwImageSize;
    	}
    	long GetLineBit();		//得到一行的象素數
    };
    2、位圖的讀取。
    CFG_DIB提供了兩個從位圖文件讀取位圖數據的方法:ReadFile和ReadSection,二者不同之處,前者使用動態分配內存的方法初始化存儲位位圖數據的指針,后者則使用API函數,根據位圖信息初始化存儲位圖數據的指針。

    方法1
    m_lpDIBits = (LPBYTE) new char[m_dwImageSize];
    方法2
    m_hBitmap = ::CreateDIBSection(pDC->GetSafeHdc(), 
             (LPBITMAPINFO) m_lpBMPHdr, DIB_RGB_COLORS,
             (LPVOID*) &m_lpDIBits, NULL, 0);
    3、位圖讀取過程中的調色板的創建和調用。
    關于調色板的詳細情況,本文不作詳細介紹,只是對讀取位圖的過程中需要調用的對調色板進行操作的相關函數進行說明。

    讀取文件的過程中,計算出調色板大小,然后調用創建調色板函數:

    ComputePaletteSize(m_lpBMPHdr->biBitCount);
    SetWinPalette();
    在顯示位圖之前,設置調色板:
    if(m_hPalette != NULL) {
         ::SelectPalette(pDC->GetSafeHdc(), m_hPalette, TRUE);
    }
    4、位圖的顯示。
    位圖的顯示還是調用Windows的API函數來進行,需要傳遞的參數包括當前位圖信息頭,位圖數據等:
    ::StretchDIBits(pDC->GetSafeHdc(), m_Dest.x, m_Dest.y,
                                 m_DestSize.cx, m_DestSize.cy,
                                 m_Src.x, m_Src.y,
                                 m_SrcSize.cx, m_SrcSize.cy,
                                 m_lpDIBits, (LPBITMAPINFO) m_lpBMPHdr, 
                                 DIB_RGB_COLORS, SRCCOPY);
    其中的m_Dest,m_DestSize,m_Src,m_SrcSize分別代表了圖像在當前設備上顯示的左上角坐標和范圍以及需要顯示的源圖像的左下角坐標和范圍。此處需要說明的是,位圖數據的字節數組是從圖像的最下面一行開始逐行想上存儲的,所以用戶在選取源位圖的現實范圍的時候需要特別注意!
    m_Dest,m_DestSize,m_Src,m_SrcSize需要在現實之前設置好。

    5、位圖的存儲。位圖的存儲用WriteFile實現。
    6、新位圖的創建。新位圖的創建由NewFile實現。需要的參數是位圖的寬度、高度、以及位圖像素占用的位數。
    7、其它問題。存取位圖數據的字節數組有個問題需要引起開發人員的注意:字節數組中每個掃描行的字節數必需是4的倍數,如果不足要用0補齊。
    以下是處理的辦法:
    DWORD dwBytes = ((DWORD) m_lpBMPHdr->biWidth * m_lpBMPHdr->biBitCount) / 32;
    if(((DWORD) m_lpBMPHdr->biWidth * m_lpBMPHdr->biBitCount) % 32) {
         dwBytes++;
    }
    dwBytes *= 4;
    m_dwImageSize = dwBytes * m_lpBMPHdr->biHeight;
    這段代碼按照要求算出了用于記錄圖像數據的字節數組的大小。

    三、CFG_DIB的使用

    以下是CFG_DIB的使用示例代碼。

    #include "fg_dib.h"
    
    CFG_DIB m_fgdib;
    
    //new file
    m_fgdib.NewFile(width, height, nbitnum);
    
    //open file
    CFile* pf;
    pf = new CFile;
    pf->Open(sFileName, CFile::modeRead);
    m_fgdib.ReadFile(pf);
    pf->Close();
    delete pf;
    
    //draw BMP
    m_fgdib.m_Dest.x = 0;
    m_fgdib.m_Dest.y = 0;
    m_fgdib.m_DestSize.cx = m_fgdib.GetWidth();
    m_fgdib.m_DestSize.cy = m_fgdib.GetHeight();
    m_fgdib.m_Src.x = 0;
    m_fgdib.m_Src.y = 0;
    m_fgdib.m_SrcSize.cx = m_fgdib.GetWidth();
    m_fgdib.m_SrcSize.cy = m_fgdib.GetHeight();
    CDC* pDC = GetDC();
    m_fgdib.Display(pDC);
    
    //close BMP
    m_fgdib.CloseFile();

    如果您在閱讀文章和使用代碼過程中遇到的問題,請與作者聯系:

    吉林省長春市西民主大街6號地球探測科學與技術學院2001級碩士研究生(130026)
    歡迎訪問作者的主頁:Forevergis.6to23.com

    from: http://www.vckbase.com/document/viewdoc/?id=674

    posted on 2006-07-30 21:22 weidagang2046 閱讀(228) 評論(0)  編輯  收藏 所屬分類: Windows

    主站蜘蛛池模板: 亚洲国产一级在线观看| 免费能直接在线观看黄的视频| 久久亚洲精品成人无码网站| 国产精品内射视频免费| 亚洲精品无码成人片在线观看| 一区二区三区视频免费| 亚洲欧洲一区二区三区| 久久精品无码专区免费| 亚洲级αV无码毛片久久精品| a毛片免费全部播放完整成| 免费激情视频网站| 亚洲AV无码精品色午夜果冻不卡| 中文字幕在线视频免费| 可以免费观看一级毛片黄a| 亚洲国产高清美女在线观看| 国产精品1024在线永久免费| 国产成人综合亚洲AV第一页| 久久青草免费91观看| 中文字幕亚洲综合久久2| 100000免费啪啪18免进| 亚洲爆乳少妇无码激情| 国产成人亚洲影院在线观看| 免费一级不卡毛片| 精品国产综合成人亚洲区| 亚洲美女免费视频| 亚洲精品第一国产综合亚AV| 亚洲美女在线国产| 2019中文字幕免费电影在线播放| 亚洲中文字幕久久无码| 亚洲精品动漫免费二区| 亚洲免费视频观看| av大片在线无码免费| 色婷婷六月亚洲综合香蕉| 在线亚洲人成电影网站色www| 99国产精品免费观看视频| 亚洲啪AV永久无码精品放毛片| 黄页网站在线看免费| 亚洲Av高清一区二区三区| 国产成人免费高清激情明星| 激情无码亚洲一区二区三区| 亚洲人成网77777色在线播放|