1. 程式人生 > >C++如何把點陣圖儲存到陣列中

C++如何把點陣圖儲存到陣列中

具體的要看你採用什麼點陣圖格式

BMP是一種與硬體裝置無關的影象檔案格式,使用非常廣。它採用位對映儲存格式,除了影象深度可選以外,不採用其他任何壓縮,因此,BMP檔案所佔用的空間很大。BMP檔案的影象深度可選lbit、4bit、8bit及24bit。BMP檔案儲存資料時,影象的掃描方式是按從左到右、從下到上的順序。 由於BMP檔案格式是Windows環境中交換與圖有關的資料的一種標準,因此在Windows環境中執行的圖形影象軟體都支援BMP影象格式。

檔案結構:

  典型的BMP影象檔案由四部分組成:

  1:點陣圖檔案頭資料結構,它包含BMP影象檔案的型別、顯示內容等資訊;

  2:點陣圖資訊資料結構,它包含有BMP影象的寬、高、壓縮方法,以及定義顏色等資訊;

  3:調色盤,這個部分是可選的,有些點陣圖需要調色盤,有些點陣圖,比如真彩色圖(24位的BMP)就不需要調色盤;

  4:點陣圖資料,這部分的內容根據BMP點陣圖使用的位數不同而不同,在24點陣圖中直接使用RGB,而其他的小於24位的使用調色盤中顏色索引值。

  點陣圖的型別:

  點陣圖一共有兩種型別,即:裝置相關點陣圖(DDB)和裝置無關點陣圖(DIB)。DDB點陣圖在早期的Windows系統(Windows 3.0以前)中是很普遍的,事實上它也是唯一的。然而,隨著顯示器製造技術的進步,以及顯示裝置的多樣化,DDB點陣圖的一些固有的問題開始浮現出來了。比如,它不能夠儲存(或者說獲取)建立這張圖片的原始裝置的解析度,這樣,應用程式就不能快速的判斷客戶機的顯示裝置是否適合顯示這張圖片。為了解決這一難題,微軟建立了DIB點陣圖格式。

  裝置無關點陣圖 (Device-Independent Bitmap)

  DIB點陣圖包含下列的顏色和尺寸資訊:

  * 原始裝置(即建立圖片的裝置)的顏色格式。

  * 原始裝置的解析度。

  * 原始裝置的調色盤

  * 一個位數組,由紅、綠、藍(RGB)三個值代表一個畫素。

  * 一個數組壓縮標誌,用於表明資料的壓縮方案(如果需要的話)。

  以上這些資訊儲存在BITMAPINFO結構中,該結構由BITMAPINFOHEADER結構和兩個或更多個RGBQUAD結構所組成。BITMAPINFOHEADER結構所包含的成員表明了影象的尺寸、原始裝置的顏色格式、以及資料壓縮方案等資訊。RGBQUAD結構標識了畫素所用到的顏色資料。

  DIB點陣圖也有兩種形式,即:底到上型DIB(bottom-up),和頂到下型DIB(top-down)。底到上型DIB的原點(origin)在影象的左下角,而頂到下型DIB的原點在影象的左上角。如果DIB的高度值(由BITMAPINFOHEADER結構中的biHeight成員標識)是一個正值,那麼就表明這個DIB是一個底到上型DIB,如果高度值是一個負值,那麼它就是一個頂到下型DIB。注意:頂到下型的DIB點陣圖是不能被壓縮的。

  點陣圖的顏色格式是通過顏色面板值(planes)和顏色位值(bitcount)計算得來的,顏色面板值永遠是1,而顏色位值則可以是1、4、8、16、24、32其中的一個。如果它是1,則表示點陣圖是一張單色點陣圖(譯者注:通常是黑白點陣圖,只有黑和白兩種顏色,當然它也可以是任意兩種指定的顏色),如果它是4,則表示這是一張VGA點陣圖,如果它是8、16、24、或是32,則表示該點陣圖是其他裝置所產生的點陣圖。如果應用程式想獲取當前顯示裝置(或印表機)的顏色位值(或稱位深度),可呼叫API函式GetDeviceCaps(),並將第二個引數設為BITSPIXEL即可。

  顯示裝置的解析度是以每米多少個畫素來表明的,應用程式可以通過以下三個步驟來獲取顯示裝置或印表機的水平解析度:

  1. 呼叫GetDeviceCaps()函式,指定第二個引數為HORZRES。

  2. 再次呼叫GetDeviceCaps()函式,指定第二個引數為HORZSIZE。

  3. 用第一個返回值除以第二個返回值。即:GetDeviceCaps(hDC,HORZRES)/GetDeviceCaps(hDC,HORZSIZE);

  應用程式也可以使用相同的三個步驟來獲取裝置的垂直解析度,不同之處只是要將HORZRES替換為VERTRES,把HORZSIZE替換為VERTSIZE,即可。

  調色盤是被儲存在一個RGBQUAD結構的陣列中,該結構指出了每一種顏色的紅、綠、藍的分量值。位陣列中的每一個索引都對應於一個調色盤項(即一個RGBQUAD結構),應用程式將根據這種對應關係,將畫素索引值轉換為畫素RGB值(真實的畫素顏色)。應用程式也可以通過呼叫GetDeviceCaps()函式來獲取當前顯示裝置的調色盤尺寸(將該函式的第二個引數設為NUMCOLORS即可)。

  Win32 API支援位資料的壓縮(只對8位和4位的底到上型DIB點陣圖)。壓縮方法是採用執行長度編碼方案(RLE),RLE使用兩個位元組來描述一個句法,第一個位元組表示重複畫素的個數,第二個位元組表示重複畫素的索引值。有關壓縮點陣圖的詳細資訊請參見對BITMAPINFOHEADER結構的解釋。

  應用程式可以從一個DDB點陣圖創建出一個DIB點陣圖,步驟是,先初始化一些必要的結構,然後再呼叫GetDIBits()函式。不過,有些顯示裝置有可能不支援這個函式,你可以通過呼叫GetDeviceCaps()函式來確定一下(GetDeviceCaps()函式在呼叫時指定RC_DI_BITMAP作為RASTERCAPS的標誌)。

  應用程式可以用DIB去設定顯示裝置上的畫素(譯者注:也就是顯示DIB),方法是呼叫SetDIBitsToDevice()函式或呼叫StretchDIBits()函式。同樣,有些顯示裝置也有可能不支援以上這兩個函式,這時你可以指定RC_DIBTODEV作為RASTERCAPS標誌,然後呼叫GetDeviceCaps()函式來判斷該裝置是否支援SetDIBitsToDevice()函式。也可以指定RC_STRETCHDIB作為RASTERCAPS標誌來呼叫GetDeviceCaps()函式,來判斷該裝置是否支援StretchDIBits()函式。

  如果應用程式只是要簡單的顯示一個已經存在的DIB點陣圖,那麼它只要呼叫SetDIBitsToDevice()函式就可以。比如一個電子表格軟體,它可以開啟一個圖表檔案,在視窗中簡單的呼叫SetDIBitsToDevice()函式,將圖形顯示在視窗中。但如果應用程式要重複的繪製點陣圖的話,則應該使用BitBlt()函式,因為BitBlt()函式的執行速度要比SetDIBitsToDevice()函式快很多。

  裝置相關點陣圖 (Device-Dependent Bitmaps)

  裝置相關點陣圖(DDB)之所以現在還被系統支援,只是為了相容舊的Windows 3.0軟體,如果程式設計師現在要開發一個與點陣圖有關的程式,則應該儘量使用或生成DIB格式的點陣圖。

  DDB點陣圖是被一個單個結構BITMAP所描述,這個結構的成員標明瞭該點陣圖的寬度、高度、裝置的顏色格式等資訊。

  DDB點陣圖也有兩種型別,即:可廢棄的(discardable)DDB和不可廢棄的(nondiscardable)DDB。可廢棄的DDB點陣圖就是一種當系統記憶體缺乏,並且該點陣圖也沒有被選入裝置描述表(DC)的時候,系統就會把該DDB點陣圖從記憶體中清除(即廢棄)。不可廢棄的DDB則是無論系統記憶體多少都不會被系統清除的DDB。API函式CreateDiscardableBitmap()函式可用於建立可廢棄點陣圖。而函式CreateBitmap()、CreateCompatibleBitmap()、和CreateBitmapIndirect()可用於建立不可廢棄的點陣圖。

  應用程式可以通過一個DIB點陣圖而建立一個DDB點陣圖,只要先初始化一些必要的結構,然後再呼叫CreateDIBitmap()函式就可以。如果在呼叫該函式時指定了CBM_INIT標誌,那麼這一次呼叫就等價於先呼叫CreateCompatibleBitmap()建立當前裝置格式的DDB點陣圖,然後又呼叫SetDIBits()函式轉換DIB格式到DDB格式。(可能有些裝置並不支援SetDIBits()函式,你可以指定RC_DI_BITMAP作為RASTERCAPS的標誌,然後呼叫GetDeviceCaps()函式來判斷一下)。

  對應的資料結構:

  1:BMP檔案組成

  BMP檔案由檔案頭、點陣圖資訊頭、顏色資訊和圖形資料四部分組成。

  2:BMP檔案頭(14位元組)

  BMP檔案頭資料結構含有BMP檔案的型別、檔案大小和點陣圖起始位置等資訊。

  其結構定義如下:

  typedef struct tagBITMAPFILEHEADER

  {

  WORD bfType; // 點陣圖檔案的型別,必須為BM(0-1位元組)

  DWORD bfSize; // 點陣圖檔案的大小,以位元組為單位(2-5位元組)

  WORD bfReserved1; // 點陣圖檔案保留字,必須為0(6-7位元組)

  WORD bfReserved2; // 點陣圖檔案保留字,必須為0(8-9位元組)

  DWORD bfOffBits; // 點陣圖資料的起始位置,以相對於點陣圖(10-13位元組)

  // 檔案頭的偏移量表示,以位元組為單位

  } BITMAPFILEHEADER;

  3:點陣圖資訊頭(40位元組)

  BMP點陣圖資訊頭資料用於說明點陣圖的尺寸等資訊。

  typedef struct tagBITMAPINFOHEADER{

  DWORD biSize; // 本結構所佔用位元組數(14-17位元組)

  LONG biWidth; // 點陣圖的寬度,以畫素為單位(18-21位元組)

  LONG biHeight; // 點陣圖的高度,以畫素為單位(22-25位元組)

  WORD biPlanes; // 目標裝置的級別,必須為1(26-27位元組)

  WORD biBitCount;// 每個畫素所需的位數,必須是1(雙色),(28-29位元組)

  // 4(16色),8(256色)或24(真彩色)之一

  DWORD biCompression; // 點陣圖壓縮型別,必須是 0(不壓縮),(30-33位元組)

  // 1(BI_RLE8壓縮型別)或2(BI_RLE4壓縮型別)之一

  DWORD biSizeImage; // 點陣圖的大小,以位元組為單位(34-37位元組)

  LONG biXPelsPerMeter; // 點陣圖水平解析度,每米畫素數(38-41位元組)

  LONG biYPelsPerMeter; // 點陣圖垂直解析度,每米畫素數(42-45位元組)

  DWORD biClrUsed;// 點陣圖實際使用的顏色表中的顏色數(46-49位元組)

  DWORD biClrImportant;// 點陣圖顯示過程中重要的顏色數(50-53位元組)

  } BITMAPINFOHEADER;

  4:顏色表

  顏色表用於說明點陣圖中的顏色,它有若干個表項,每一個表項是一個RGBQUAD型別的結構,定義一種顏色。RGBQUAD結構的定義如下:

  typedef struct tagRGBQUAD {

  BYTE rgbBlue;// 藍色的亮度(值範圍為0-255)

  BYTE rgbGreen; // 綠色的亮度(值範圍為0-255)

  BYTE rgbRed; // 紅色的亮度(值範圍為0-255)

  BYTE rgbReserved;// 保留,必須為0

  } RGBQUAD;

  顏色表中RGBQUAD結構資料的個數有biBitCount來確定:

  當biBitCount=1,4,8時,分別有2,16,256個表項;

  當biBitCount=24時,沒有顏色表項。

  點陣圖資訊頭和顏色表組成點陣圖資訊,BITMAPINFO結構定義如下:

  typedef struct tagBITMAPINFO {

  BITMAPINFOHEADER bmiHeader; // 點陣圖資訊頭

  RGBQUAD bmiColors[1]; // 顏色表

  } BITMAPINFO;

  5:點陣圖資料

  點陣圖資料記錄了點陣圖的每一個畫素值,記錄順序是在掃描行內是從左到右,掃描行之間是從下到上。點陣圖的一個畫素值所佔的位元組數:

  當biBitCount=1時,8個畫素佔1個位元組;

  當biBitCount=4時,2個畫素佔1個位元組;

  當biBitCount=8時,1個畫素佔1個位元組;

  當biBitCount=24時,1個畫素佔3個位元組;

  Windows規定一個掃描行所佔的位元組數必須是

  4的倍數(即以long為單位),不足的以0填充,

  biSizeImage = ((((bi.biWidth * bi.biBitCount) + 31) & ~31) / 8) * bi.biHeight;

  具體資料舉例:

  如某BMP檔案開頭:

  4D42 4690 0000 0000 0000 4600 0000 2800 0000 8000 0000 9000 0000 0100*1000 0300 0000 0090 0000 A00F 0000 A00F 0000 0000 0000 0000 0000*00F8 0000 E007 0000 1F00 0000 0000 0000*02F1 84F1 04F1 84F1 84F1 06F2 84F1 06F2 04F2 86F2 06F2 86F2 86F2 .... ....

  BMP檔案可分為四個部分:點陣圖檔案頭、點陣圖資訊頭、彩色板、影象資料陣列,在上圖中已用*分隔。

  一、影象檔案頭

  1)1:(這裡的數字代表的是"字",即兩個位元組,下同)影象檔案頭。0x4D42=’BM’,表示是Windows支援的BMP格式。

  2)2-3:整個檔案大小。4690 0000,為00009046h=36934。

  3)4-5:保留,必須設定為0。

  4)6-7:從檔案開始到點陣圖資料之間的偏移量。4600 0000,為00000046h=70,上面的檔案頭就是35字=70位元組。

  二、點陣圖資訊頭

  5)8-9:點陣圖圖資訊頭長度。

  6)10-11:點陣圖寬度,以畫素為單位。8000 0000,為00000080h=128。

  7)12-13:點陣圖高度,以畫素為單位。9000 0000,為00000090h=144。

  8)14:點陣圖的位面數,該值總是1。0100,為0001h=1。

  9)15:每個畫素的位數。有1(單色),4(16色),8(256色),16(64K色,高彩色),24(16M色,真彩色),32(4096M色,增強型真彩色)。1000為0010h=16。

  10)16-17:壓縮說明:有0(不壓縮),1(RLE 8,8位RLE壓縮),2(RLE 4,4位RLE壓縮,3(Bitfields,位域存放)。RLE簡單地說是採用畫素數+畫素值的方式進行壓縮。T408採用的是位域存放方式,用兩個位元組表示一個畫素,位域分配為r5b6g5。圖中0300 0000為00000003h=3。

  11)18-19:用位元組數表示的點陣圖資料的大小,該數必須是4的倍數,數值上等於(≥點陣圖寬度的最小的4的倍數)×點陣圖高度×每個畫素位數。0090 0000為00009000h=80×90×2h=36864。

  12)20-21:用象素/米表示的水平解析度。A00F 0000為0000 0FA0h=4000。

  13)22-23:用象素/米表示的垂直解析度。A00F 0000為0000 0FA0h=4000。

  14)24-25:點陣圖使用的顏色索引數。設為0的話,則說明使用所有調色盤項。

  15)26-27:對圖象顯示有重要影響的顏色索引的數目。如果是0,表示都重要。

  三、彩色板

  16)28-....(不確定):彩色板規範。對於調色盤中的每個表項,用下述方法來描述RGB的值:

  1位元組用於藍色分量

  1位元組用於綠色分量

  1位元組用於紅色分量

  1位元組用於填充符(設定為0)

  對於24-位真彩色影象就不使用彩色板,因為點陣圖中的RGB值就代表了每個象素的顏色。

  如,彩色板為00F8 0000 E007 0000 1F00 0000 0000 0000,其中:

  00FB 0000為FB00h=1111100000000000(二進位制),是藍色分量的掩碼。

  E007 0000為 07E0h=0000011111100000(二進位制),是綠色分量的掩碼。

  1F00 0000為001Fh=0000000000011111(二進位制),是紅色分量的掩碼。

  0000 0000總設定為0。

  將掩碼跟畫素值進行“與”運算再進行移位操作就可以得到各色分量值。看看掩碼,就可以明白事實上在每個畫素值的兩個位元組16位中,按從高到低取5、6、5位分別就是r、g、b分量值。取出分量值後把r、g、b值分別乘以8、4、8就可以補齊第個分量為一個位元組,再把這三個位元組按rgb組合,放入儲存器(同樣要反序),就可以轉換為24位標準BMP格式了。

  四、影象資料陣列

  17)27(無調色盤)-...:每兩個位元組表示一個畫素。陣列中的第一個位元組表示點陣圖左下角的象素,而最後一個位元組表示點陣圖右上角的象素。

  五、儲存演算法

  BMP檔案通常是不壓縮的,所以它們通常比同一幅影象的壓縮影象檔案格式要大很多。例如,一個800×600的24位幾乎佔據1.4MB空間。因此它們通常不適合在因特網或者其它低速或者有容量限制的媒介上進行傳輸。 根據顏色深度的不同,影象上的一個畫素可以用一個或者多個位元組表示,它由n/8所確定(n是位深度,1位元組包含8個數據位)。圖片瀏覽器等基於位元組的ASCII值計算畫素的顏色,然後從調色盤中讀出相應的值。更為詳細的資訊請參閱下面關於點陣圖檔案的部分。 n位2n種顏色的點陣圖近似位元組數可以用下面的公式計算: BMP檔案大小約等於 54+4*2的n次方+(w*h*n)/8,其中高度和寬度都是畫素數。 需要注意的是上面公式中的54是點陣圖檔案的檔案頭,是彩色調色盤的大小。另外需要注意的是這是一個近似值,對於n位的點陣圖影象來說,儘管可能有最多2n中顏色,一個特定的影象可能並不會使用這些所有的顏色。由於彩色調色盤僅僅定義了影象所用的顏色,所以實際的彩色調色盤將小於。 如果想知道這些值是如何得到的,請參考下面檔案格式的部分。 由於儲存演算法本身決定的因素,根據幾個影象引數的不同計算出的大小與實際的檔案大小將會有一些細小的差別。