欧美日韩在线第一页-欧美日韩在线观看精品-欧美日韩在线观看一区二区-欧美日韩在线免费看-欧美日韩在线视频不卡一区二区三区

圖像處理
新聞詳情

DIB位圖(Bitmap)的讀取和保存

發(fā)布時(shí)間:2021-01-19 13:43:34 最后更新:2021-01-21 08:43:48 瀏覽次數(shù):3306

設(shè)備無(wú)關(guān)位圖(Device Independent Bitmap)是可以保存在磁盤(pán)的位圖文件,可以從磁盤(pán)讀取到內(nèi)存或者從內(nèi)存保存到磁盤(pán)上。它的文件結(jié)構(gòu)是標(biāo)準(zhǔn)化的,可以在Windows/Linux/Unix等平臺(tái)上顯示相同的效果。本文主要介紹了

1.   如果將位圖文件從磁盤(pán)讀到內(nèi)存中

2.   在內(nèi)存中對(duì)位圖文件進(jìn)行操作后,如何將位圖保存到磁盤(pán)


1 讀取位圖到內(nèi)存中

1.1 DIB文件結(jié)構(gòu)

要將位圖文件(.bmp)從磁盤(pán)讀取到內(nèi)存,首先要了解其文件結(jié)構(gòu)。DIB的文件組成有以下4個(gè)部分:

1.   文件表頭,主要包含了文件的類(lèi)型(必須是BM),文件的大?。ㄋ加玫淖止?jié)數(shù))和位圖的像素矩陣的便宜量。

2.   信息表頭,包含了兩部分內(nèi)容:位圖的相關(guān)信息(位圖的大小、位深度、位面數(shù)、壓縮和編碼等)和指向RGB顏色表(調(diào)色盤(pán))的指針。

3.   RGB色彩對(duì)照表,也就是調(diào)色板,不一定會(huì)有。16位及以上直接使用RGB通道表示顏色,一般不需要調(diào)色板。

4.   位圖的像素信息矩陣,表示具體的像素。1,4,8位顏色,保存的是調(diào)色板的索引,具體的顏色根據(jù)索引在調(diào)色板中查找;16位及其以上不使用調(diào)色板,直接使用RGB組成像素顏色。

1.2 在Windows下DIB的內(nèi)存結(jié)構(gòu)

要將DIB數(shù)據(jù)讀取到內(nèi)存,就需要在內(nèi)存中分配相應(yīng)的空間。Windows提供了幾種結(jié)構(gòu)體,結(jié)構(gòu)體中的字段對(duì)應(yīng)著DIB文件的各個(gè)信息值,具體如下

引用自 http://blog.csdn.net/wenzhou1219/article/details/26162869

將DIB讀取到內(nèi)存只需要將磁盤(pán)數(shù)據(jù)填充到相應(yīng)到結(jié)構(gòu)體即可。在磁盤(pán)上DIB需要連續(xù)的結(jié)構(gòu)存儲(chǔ),在內(nèi)存中則不需要連續(xù)的存儲(chǔ)空間,可以分段將數(shù)據(jù)讀取到相應(yīng)的結(jié)構(gòu)體中。
讀取DIB到內(nèi)存的具體步驟:

1.   將文件頭信息讀取到BITMAPFILEHEADER結(jié)構(gòu)體中。

2.   將位圖頭信息讀取到BITMAPINFOHEADER結(jié)構(gòu)體中。

3.   如果有調(diào)色板,則將其信息讀取到RGBQUAD中。

4.   讀取位圖像素信息到像素矩陣中。

fp.Read(&bmfileHeader, sizeof(BITMAPFILEHEADER)); // 讀取BMP文件頭 
...
//讀取文件信息頭
ret = fp.Read(&bmHeader, sizeof(BITMAPINFOHEADER)); 
...
fp.Read(m_dibBits, GetBodySize());  //讀取像素信息 

1.3 結(jié)構(gòu)體各字段信息

BITMAPFILEHEADER

代表文件頭信息的結(jié)構(gòu)體BITMAPFILEHEADER的聲明如下:

typedef struct tagBITMAPFILEHEADER {
        WORD    bfType;
        DWORD   bfSize;
        WORD    bfReserved1;
        WORD    bfReserved2;
        DWORD   bfOffBits;
} BITMAPFILEHEADER  

其中,

·        bfType是文件類(lèi)型,該字段必須是BM,如果不是則說(shuō)明該文件不是DIB。

·        bfSize是位圖文件的大小(字節(jié)數(shù))

·        bfReserved1和bfReserved2是保留字段

·        bfOffBits 從BITMAPFILEHEADER的起始位置到位圖像素的字節(jié)偏移量。

BITMAPINFO

在上面提到,位圖信息和位圖的調(diào)色板是存放在同一個(gè)結(jié)構(gòu)體中的,該結(jié)構(gòu)體就是BITMAPINFO,其聲明如下

typedef struct tagBITMAPINFO {
  BITMAPINFOHEADER bmiHeader;
  RGBQUAD          bmiColors[1];
} BITMAPINFO, *PBITMAPINFO;

bmiHeader是位圖頭信息
bmiColors是調(diào)色板

BITMAPINFOHEADER

位圖的頭信息結(jié)構(gòu)BITMAPINFOHEADER,該結(jié)構(gòu)包含了DIB的尺寸和顏色格式等信息,聲明如下

ypedef 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  

其中,

·        biSize是該結(jié)構(gòu)體所占用的字節(jié)說(shuō)

·        biWidth DIB的寬(以像素為單位),如果biCompression是BI_JPEG或者BI_PNG,則biWidth是解壓縮后JPEG或者PNG圖像的寬度。

·        biHeight,DIB的高(以像素為單位)。

o   如果biHeight是正的,則DIB的像素是按照從下往上(bottom-up,也就是像素?cái)?shù)組的第一行保存的實(shí)際是DIB的最后一行像素值),圖像源點(diǎn)在左下角。

o   如果biHeight是負(fù)的,則DIB的像素是按照從上往下保存的(up-bottom),而且像素的數(shù)據(jù)是不能被壓縮的其biCompression必須是BI_RGB或者BI_FIELDS

o   如果biCompression是BI_JPEG或者BI_PNG,則biHeight是解壓縮后JPEG或者PNG的高

·        biPlanes 目標(biāo)設(shè)備的平面數(shù),總是設(shè)為1.

·        biBitCount,每個(gè)像素所占用的位數(shù)。0,表示JPEG或者PNG指定每個(gè)像素所占用的位數(shù)。還可以是1,4,8,16,24,32。

·        biCompression,數(shù)據(jù)的壓縮方法(up-down的DIB不能被壓縮),可以是以下值:

o   BI_RGB / BI_FIELDS未被壓縮

o   BI_RLE4 / BI_RLE8 使用游程長(zhǎng)度編碼 (RLE,run-length encode)

o   BI_JPEG / BI_PNG 指示該圖像是JPEG或者PNG圖像。

·        biSizeImage 圖像的字節(jié)數(shù),對(duì)于BI_RGB的DIB其值為0.

·        biXPelsPerMeter / biYPelsPerMeter 顯示該DIB的目標(biāo)設(shè)備所需的分辨率(單位是像素每米)

·        biClrUsed DIB實(shí)際使用調(diào)色板中的顏色個(gè)數(shù),通常為0表示使用調(diào)色板中的全部顏色。

·        biClrImportant 顯示DIB所必須的顏色個(gè)數(shù),通常為0表示全部顏色都是必須的。

詳細(xì)的解釋參見(jiàn) https://msdn.microsoft.com/en-us/library/dd183376(v=vs.85).aspx

RGBQUAD

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

注意,其存儲(chǔ)順序是BGR。

1.4 DIB的結(jié)構(gòu)實(shí)例

是一幅寬和高都是32的位圖(放大后,可以看到表示像素的一個(gè)個(gè)方塊),其有16種顏色。下面是該圖像的16進(jìn)制數(shù)據(jù)

·        首先是文件的頭信息 BITMAPFILEINFO 共有14個(gè)字節(jié)(0x00-0x0D),其起始的兩個(gè)字節(jié)為0x4d42(大端存儲(chǔ),高位在前)表示文件類(lèi)型為BM,最后4個(gè)字節(jié) 0x0076是位圖的像素信息相對(duì)于文件頭的偏移量,也就是從0x0076為圖像的像素信息。

·        下面是位圖的頭信息 BITMAPINFOHEADER共有40個(gè)字節(jié)(0x0E-0x35),起始的4個(gè)字節(jié)是0x0028就是該結(jié)構(gòu)體的大小,緊接著的4個(gè)字節(jié)是圖像的寬0x0020

·        跟著是圖像的調(diào)色板,0x36 - 0x75。調(diào)色板共有16種顏色,也就是說(shuō)有調(diào)色板中有16個(gè)RGBQUAD,其大小為16 *4.

·        最后是位圖的數(shù)據(jù) 0x76-0x275

1.5 讀取

    CFile fp(dibName, CFile::modeRead | CFile::typeBinary);
    BITMAPFILEHEADER bmfileHeader;
    BITMAPINFOHEADER bmHeader;
    ULONGLONG headpos;
    int paletteSize = 0;
    int ret, cbHeaderSize;
    headpos = fp.GetPosition(); // 獲取文件指針的位置
    ret = fp.Read(&bmfileHeader, sizeof(BITMAPFILEHEADER)); // 讀取BMP文件頭
    if (bmfileHeader.bfType != 0x4d42) //判斷文件類(lèi)型標(biāo)頭是不是x4d42,表示該文件為BMP類(lèi)型文件
    {
        AfxMessageBox(_T("文件不是bmp!"));
        return;
    }
    //讀取文件信息頭
    ret = fp.Read(&bmHeader, sizeof(BITMAPINFOHEADER));
    // 計(jì)算RGBQUAD的大小
    switch (bmHeader.biBitCount)
    {
    case 1:
        paletteSize = 2;
        break;
    case 4:
        paletteSize = 16;
        break;
    case 8:
        paletteSize = 256;
        break;
    }
    // 為BITMAPINFO分配存儲(chǔ)空間
    cbHeaderSize = sizeof(BITMAPINFOHEADER)+paletteSize * sizeof(RGBQUAD);
    m_dibInfo = (BITMAPINFO*) new char[cbHeaderSize];
    m_dibInfo->bmiHeader = bmHeader;
    if (paletteSize) //是否有調(diào)色板
    {
        ret = fp.Read(&(m_dibInfo->bmiColors[0]), paletteSize * sizeof(RGBQUAD));
        if (ret != int(paletteSize * sizeof(RGBQUAD) ) )
        {
            delete[] m_dibInfo;
            m_dibInfo = NULL;
            return;
        }
    }
    //為像素?cái)?shù)組分配存儲(chǔ)空間,大小由GetBodySize決定
    m_dibBits = (void*) new char[GetBodySize()];
    fp.Seek(headpos + bmfileHeader.bfOffBits, CFile::begin); // 將文件指針移動(dòng)到DIB像素?cái)?shù)組
    ret = fp.Read(m_dibBits, GetBodySize());
    if (ret != int(GetBodySize()))
    {
        delete[] m_dibInfo;
        delete[] m_dibBits;
        m_dibInfo = NULL;
        m_dibBits = NULL;
    }
    fp.Close();  

知道了DIB的文件結(jié)構(gòu)后,讀取其到內(nèi)存還是挺簡(jiǎn)單的,需要注意的是DIB的像素?cái)?shù)組的大小。由于DIB的寬度需要時(shí)4的倍數(shù),不是的話需要填充0將其湊成4的倍數(shù),所以其像素?cái)?shù)組的大小不能簡(jiǎn)單的width * height * biBitCount / 8,其中biBitCount是每個(gè)像素占用的位數(shù)。其具體的計(jì)算方法如下

1.    首先計(jì)算一行所占用的字節(jié)數(shù)bytesPerLine
bytesPerLine =((m_dibInfo->bmiHeader.biWidth * m_dibInfo->bmiHeader.biBitCount + 31) /32 ) * 4

2.    將bytesPerLine乘以圖像的高
bytesPerLine *m_dibInfo->bmiHeader.biHeight

1.6 總結(jié)

本文主要對(duì)DIB的文件結(jié)構(gòu)以及其對(duì)應(yīng)的內(nèi)存中的結(jié)構(gòu)體做了一個(gè)總結(jié),并對(duì)一個(gè)具體的DIB16進(jìn)制數(shù)據(jù)結(jié)構(gòu)進(jìn)行分析,最后實(shí)現(xiàn)了如何將一個(gè)DIB數(shù)據(jù)讀取到內(nèi)存中。

一直對(duì)位圖結(jié)構(gòu)不是很了解,趁著在公司實(shí)習(xí)沒(méi)有具體的工作安排,對(duì)DIB的結(jié)構(gòu)作了個(gè)總結(jié)。至于如何將處理后的位圖數(shù)據(jù)寫(xiě)回磁盤(pán)文件,在知道位圖結(jié)構(gòu)的情況下,只需要填充相應(yīng)的結(jié)構(gòu)字段就行了,需要注意的還是位圖的寬需要是4的倍數(shù),不是的話要用0補(bǔ)齊。

在線客服 雙翌客服
客服電話
  • 0755-23712116
  • 13310869691
主站蜘蛛池模板: 欧美大黄特黄一级毛片| 国产成人精品视频频| 黄址在线观看| 久久成人国产精品青青| 国产真实乱人视频在线看| 免费播放欧美毛片欧美a| 国产女在线| 日韩欧美一区二区三区在线观看 | 国产成人一级片| 黄色成人在线网站| 丁香六月欧美| 精品国产免费久久久久久| 91视频网页| 亚洲精品色婷婷在线影院麻豆| 国产人妖一区二区| 国产精品久久久久久搜索| 精品久久久久久亚洲| 国产精品久久天天影视| 免费vip影院| 婷婷亚洲激情| 亚洲男女视频| 日韩一级一欧美一级国产| 欧美日本一级在线播放| 国产肉丝在线| 国产精品第一页爽爽影院| 福利视频网页| 大片毛片| 国产精品午夜性视频| 四虎hk网址| 亚洲国产综合久久精品| 中文字幕日韩高清版毛片| 曰本在线网| 亚洲黄色一级大片| 国产xxwwxxww视频| 国产成人精品1024在线| 国产激情一区二区三区在线观看| 黄色片免费看视频| 嘛豆传媒的短视频动漫| 91麻豆视频网站| 91久久爱| 精品成人一区二区三区免费视频|