Visual C++中DDB與DIB位元影像編程全攻略

來源:互聯網
上載者:User

作者: 宋寶華

出處: 天極網

1. 基本概念

  先來用通俗的語句講解位元影像和調色盤的概念。

  我們知道,自然界中的所有顏色都可以由紅、綠、藍(R,G,B)三基色組合而成。針對含有紅、綠、藍色成分的多少,可以對其分別分成0~255個等級,而紅、綠、藍的不同組合共有256×256×256種,因此約能表示1600萬種顏色。對於人眼而言,這已經是"真彩色"了。

  對每個像素進行了(R,G,B)量化的映像就是位元影像,其在電腦中對應檔案的副檔名一般為.bmp。既然用R,G,B的量化值就可以直接記錄一張位元影像的所有像素,那我們需要調色盤幹什麼呢?

  首先,我們可以計算完全利用(R,G,B)組合來儲存一個800×600的位元影像所需要的空間為:

800×600×3 = 1440000(位元組)= 1.37M(位元組)

  驚人的大!因此,調色盤橫空出世了,它的功能在於緩解位元影像檔案儲存體空間過大的問題。

  假設一個位元影像為16色,其像素總數為800×600。我們只需要用4個bit就可以儲存這個位元影像的每個像素在16種顏色中所處的等級,然後調色盤提供了這16種等級對應的(R,G,B)值,這樣,儲存這個16色位元影像只需要:

800×600×4/8 = 240000(位元組)= 0.22 M(位元組)

  額外的儲存R,G,B表的開銷(即調色盤Palette,也稱為顏色尋找表LUT)僅僅為16×3=48位元組。

  儲存空間被大為減少!

  常見的位元影像有單色、16色、256色、16位及24位真彩色5種,對於前三者(即不大於256色)都可以調色盤方式進行儲存,而對16位及24位真彩色以調色盤進行儲存是不划算的,它們直接按照R,G,B分量進行儲存。

  在此基礎上我們來分析DDB位元影像(Device-dependent bitmap,與裝置相關的位元影像)與DIB位元影像(Device-independent bitmap,與裝置無關的位元影像)的概念以及二者的區別。

  DDB依賴於具體裝置,它只能存在於記憶體中(視頻記憶體或系統記憶體),其顏色模式必須與特定的輸出裝置相一致,使用系統調色盤。一般只能載入色彩較簡單的DDB位元影像,對於顏色較豐富的位元影像,需使用DIB才能長期儲存。

  DIB不依賴於具體裝置,可以用來永久性地儲存圖象。DIB一般是以*.BMP檔案的形式儲存在磁碟中的,有時也會儲存在*.DIB檔案中。 DIB位元影像的特點是將顏色資訊儲存在位元影像檔案自身的顏色表中,應用程式要根據此顏色表為DIB建立邏輯調色盤。因此,在輸出一幅DIB位元影像之前,程式應該將其邏輯調色盤選入到相關的裝置上下文並實現到系統調色盤中。

  2. 常式簡述

  本文後續的講解都基於這樣的一個例子工程,它是一個基於對話方塊的MFC應用程式,包括2個父菜單:

  (1) DDB位元影像

  DDB位元影像父菜單又包括兩個子功能表:

  a. ID:IDM_LOADDDBPIC caption:載入

  單擊事件:載入資源中的DDB位元影像並顯示之

  b. ID:IDM_MARK_DDBPIC caption:標記

  單擊事件:在DIB位元影像中透明地添加天極網logo

  (2) DIB位元影像

  DIB位元影像父菜單又包括兩個子功能表:

  a. ID:IDM_OPENDIBPIC caption:開啟

  單擊事件:彈出檔案對話方塊,開啟.bmp位元影像檔案,並顯示

  b. ID:IDM_MARK_DIBPIC caption:標記

  單擊事件:在DIB位元影像中透明地添加天極網logo

  工程中還包含下列位元影像資源:

  (1)IDB_LOADED_BITMAP:要載入的位元影像資源

  (2)IDB_YESKY_BITMAP:天極網logo

  後續篇章將集中在對4個子功能表單擊事件訊息處理函數的講解,下面的代碼是整個對話方塊類CBitMapExampleDlg的訊息映射:

BEGIN_MESSAGE_MAP(CBitMapExampleDlg, CDialog)
//{{AFX_MSG_MAP(CBitMapExampleDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_COMMAND(IDM_LOADDDBPIC, OnLoadddbpic)
ON_COMMAND(IDM_MARK_DDBPIC, OnMarkDdbpic)
ON_COMMAND(IDM_OPENDIBPIC, OnOpendibpic)
ON_COMMAND(IDM_MARK_DIBPIC,OnMarkDibpic) //}}AFX_MSG_MAP
END_MESSAGE_MAP()

 

3. DDB位元影像編程

  先看DDB載入按鈕的單擊事件代碼:

void CBitMapExampleDlg::OnLoadddbpic()
{
1: CBitmap bmpDraw;
2:  bmpDraw.LoadBitmap( IDB_LOADED_BITMAP );//裝入要載入的DDB位元影像
3:  BITMAP bmpInfo;
4:  bmpDraw.GetBitmap( &bmpInfo ); //擷取要載入DDB位元影像的尺寸
5:  CDC memDC;//定義一個相容DC
6:  CClientDC dc( this );
7:  memDC.CreateCompatibleDC( &dc );//建立相容DC
8:  CBitmap* pbmpOld = memDC.SelectObject( &bmpDraw );//儲存原有DDB,並選入新DDB入DC

9:  dc.BitBlt( 0, 0, bmpInfo.bmWidth, bmpInfo.bmHeight, &memDC, 0, 0, SRCCOPY );

10: memDC.SelectObject( pbmpOld );//選入原DDB
}

  上述代碼將產生1所示的效果,位元影像被安置在對話方塊(0,0)座標開始的位置上。


圖1 載入DDB位元影像資源

  我們來逐行解析上述代碼是怎樣產生圖1的效果的。

  第1、2行定義了一個CBitmap對象,並調用其成員函數LoadBitmap載入工程中的位元影像資源IDB_LOADED_BITMAP。第3、4行定義了BITMAP結構體的執行個體並調用CBitmap的成員函數GetBitmap獲得位元影像資訊,BITMAP結構體定義在<wingdi.h>標頭檔中,其形式為:

/* Bitmap Header Definition */
typedef struct tagBITMAP
{
 LONG bmType; //必需為0
 LONG bmWidth; //位元影像的寬度(以像素為單位)
 LONG bmHeight; //位元影像的高度(以像素為單位)
 LONG bmWidthBytes; //每一掃描行所需的位元組數,應是偶數
 WORD bmPlanes; //色平面數
 WORD bmBitsPixel; //色平面的顏色位元
 LPVOID bmBits; //指向儲存像素陣列的數組
} BITMAP, *PBITMAP, NEAR *NPBITMAP, FAR *LPBITMAP;

  第5~8行的作用是:構建一個CDC對象,調用CDC::CreateCompatibleDC建立一個相容的記憶體裝置上下文,接著調用CDC::SelectObject將DDB選入記憶體裝置上下文中。

  第9行調用函數CDC::BitBlt繪製位元影像,CDC::BitBlt的原型為:

CDC::BitBlt(int x, int y, int nWidth, int nHeight, CDC *pSrcDC, int xSrc, int ySrc, DWORD dwRop)

  CDC::BitBlt執行的操作為將源DC中位元影像複製到目的DC中。其中前四個參數為目的地區的座標(x,y)及長度和寬度(Width, nHeight),第五個參數是源DC指標,接下來的參數是源DC中的起始座標,最後一個參數為光柵操作的類型。

  第10行調用CDC::SelectObject把原來的DDB選入到記憶體裝置上下文中並使新DDB脫離出來。

  與CDC::BitBlt對應的還有另一個函數CDC::StretchBlt,它具有縮放功能,其原型為:

BOOL CDC::StretchBlt(int x, int y, int nWidth, int nHeight, CDC *pSrcDC, int
xSrc, int ySrc, int nSrcWidth, int nSrcHeight, DWORD dwRop);

  該函數把位元影像從源矩形拷貝到目的矩形中,如果源和目的矩形尺寸不同,那麼將縮放位元影像的功能以適應目的矩形的大小。函數的大部分參數與BitBlt的相同,但多了兩個參數nSrcWidth和nSrcHeight用來指定源矩形的寬和高。

  如果我們將函數CBitMapExampleDlg::OnLoadddbpic() 中的第9行改為:

CRect clientRect;
GetClientRect(&clientRect); //獲得對話方塊視窗的大小
dc.StretchBlt(0, 0, clientRect.right, clientRect.bottom, &memDC, 0, 0,
bmpInfo.bmWidth, bmpInfo.bmHeight, SRCCOPY);

  則單擊載入按鈕後的對話方塊2所示,位元影像被展開至整個對話方塊的範圍。


圖2 展開位元影像

  CDC::BitBlt和dc.StretchBlt函數中的dwRop參數較為有用,它定義光柵操作的類型。請看"DDB位元影像"父菜單下"標記"子功能表單擊事件的訊息處理函數代碼:

void CBitMapExampleDlg::OnMarkDdbpic()
{
 CBitmap bmpDraw;
 bmpDraw.LoadBitmap(IDB_YESKY_BITMAP); //裝入天極網logo DDB位元影像資源
 BITMAP bmpInfo;
 bmpDraw.GetBitmap(&bmpInfo); //擷取天極網logo位元影像的尺寸

 CDC memDC; //定義一個相容DC
 CClientDC dc(this);
 memDC.CreateCompatibleDC(&dc); //建立DC

 CBitmap *pbmpOld = memDC.SelectObject(&bmpDraw);
 //儲存原有DDB,並選入天極網logo位元影像入DC
 dc.BitBlt(0, 0, bmpInfo.bmWidth, bmpInfo.bmHeight, &memDC, 0, 0, SRCAND);
 memDC.SelectObject(pbmpOld); //選入原DDB
}

  單擊該按鈕後,將產生3的效果,天極網的logo被透明地添加到了位元影像中!


圖3 在DDB位元影像中加入天極網logo

  能產生這個效果的原因在於我們在程式碼:

dc.BitBlt ( 0, 0, bmpInfo.bmWidth, bmpInfo.bmHeight, &memDC, 0, 0, SRCAND );

  中使用了參數SRCAND(不同於先前代碼中SRCCOPY,它僅僅意味著複製源位元影像到目的位元影像),它的含義為源和目的間進行AND操作。我們不知道天極網的編輯同志是怎麼為文章中的圖片加logo的,有可能他們就使用了具有自動AND功能的映像加logo批處理軟體。的確,我們可以利用常式中的原理寫一個批處理軟體,一次對一堆圖片自動添加logo。

  參數dwRop除了可以為SRCAND和SRCCOPY外,還可以有如下取值:

  BLACKNESS:輸出地區為黑色

  DSTINVERT:反轉目的位元影像

  MERGECOPY:用與操作把圖案(Pattern)與源位元影像融合起來

  MERGEPAINT:用或操作把反轉的源位元影像與目的位元影像融合起來

  NOTSRCCOPY:把源位元影像反轉然後拷貝到目的地

  NOTSRCERASE:用或操作融合源和目的位元影像,然後再反轉

  PATCOPY:把圖案拷貝到目的位元影像中

  PATINVERT:用異或操作把圖案與目的位元影像相融合

  PATPAINT:用或操作融合圖案和反轉的源位元影像,然後用或操作把結果與目的位元影像融合

  SRCERASE:先反轉目的位元影像,再用與操作將其與源位元影像融合

  SRCINVERT:用異或操作融合源位元影像和目的位元影像

  SRCPAINT:用或操作融合源位元影像和目的位元影像

  WHITENESS:輸出地區為白色

  合理利用這些取值將協助我們製作出特定要求的影像處理軟體。

  從上述執行個體我們可以看出,在VC中使用CBitmap類,必須將位元影像放入工程的資源中,並使用類 CBitmap的成員函數LoadBitmap載入之,再通過CDC類的成員函數BitBlt進行DC拷貝等操作達到顯示的目的。CBitmap有顯示的不足:

  (1) 位元影像需要放入工程資源中,這將導致工程的可執行檔變大;

  (2) 因為位元影像需放入工程資源中,而資源中不能無窮無盡地包含位元影像,應用程式無法自適應地選取其它位元影像,能使用的位元影像十分有限的;

  (3) 類CBitmap只是DDB位元影像操作API的封裝,不能獨立於平台。

  DIB位元影像則可以解決上述問題,其特點是以.BMP位元影像檔案格式儲存獨立於平台的映像資料,下面我們來詳細分析。

4. DIB位元影像編程

  4.1位元影像檔案格式

  先來分析DIB位元影像檔案的格式。位元影像檔案分為四部分:

  (1)位元影像檔案頭BITMAPFILEHEADER

  位元影像檔案頭BITMAPFILEHEADER是一個結構體,長度為14位元組,定義為:

typedef struct tagBITMAPFILEHEADER
{
 WORD bfType; //檔案類型,必須是0x424D,即字串"BM"
 DWORD bfSize; //檔案大小,包括BITMAPFILEHEADER的14個位元組
 WORD bfReserved1; //保留字
 WORD bfReserved2; //保留字
 DWORD bfOffBits; //從檔案頭到實際的位元影像資料的位移位元組數
} BITMAPFILEHEADER;

  (2)位元影像資訊頭BITMAPINFOHEADER

  位元影像資訊頭BITMAPINFOHEADER也是一個結構體,長度為40位元組,定義為:

typedef struct tagBITMAPINFOHEADER
{
 DWORD biSize; //本結構的長度,為40
 LONG biWidth; //圖象的寬度,單位是象素
 LONG biHeight; //圖象的高度,單位是象素
 WORD biPlanes; //必須是1
 WORD biBitCount;
 //表示顏色時要用到的位元,1(單色), 4(16色), 8(256色), 24(真彩色)
 DWORD biCompression;
 //指定位元影像是否壓縮,有效值為BI_RGB,BI_RLE8,BI_RLE4,BI_BITFIELDS等,BI_RGB表示不壓縮
 DWORD biSizeImage;
 //實際的位元影像資料佔用的位元組數,即 biSizeImage=biWidth’ × biHeight,biWidth’是biWidth 按照4的整倍數調整後的結果
 LONG biXPelsPerMeter; //目標裝置的水平解析度,單位是每米的象素個數
 LONG biYPelsPerMeter; //目標裝置的垂直解析度,單位是每米的象素個數
 DWORD biClrUsed; //位元影像實際用到的顏色數,0表示顏色數為2biBitCount
 DWORD biClrImportant; //位元影像中重要的顏色數,0表示所有顏色都重要
} BITMAPINFOHEADER;

  (3)調色盤Palette

  調色盤Palette針對的是需要調色盤的位元影像,即單色、16色和256色位元影像。對於不以調色盤方式儲存的位元影像,則無此項資訊。調色盤是一個數組,共有biClrUsed個元素(如果該值為0,則有2biBitCount個元素)。數組中每個元素是一個RGBQUAD結構體,長度為4個位元組,定義為:

typedef struct tagRGBQUAD
{
 BYTE rgbBlue; //藍色分量
 BYTE rgbGreen; //綠色分量
 BYTE rgbRed; //紅色分量
 BYTE rgbReserved; //保留值
} RGBQUAD;

  (4)實際的位元影像資料ImageDate

  對於用到調色盤的位元影像,實際的圖象資料ImageDate為該象素的顏色在調色盤中的索引值;對於真彩色圖,圖象資料則為實際的R、G、B值:

  a.單色位元影像:用1bit就可以表示象素的色彩索引值;

  b.16色位元影像:用4bit可以表示象素的色彩索引值;

  c. 256色位元影像:1個位元組表示1個象素的色彩索引值;

  d.真彩色:3個位元組表示1個象素的顏色R,G,B值。

  此外,位元影像資料每一行的位元組數必須為4的整倍數,如果不是,則需要補齊。奇怪的是,位元影像檔案中的資料是從下到上(而不是從上到下)、從左至右方式儲存的。

4.2位元影像的顯示
 
  Visual C++ MFC中沒有提供一個專門的類來處理DIB位元影像,因此,為了方便地使用位元影像檔案,我們有必要派生一個CDib類。類的原始碼如下:

  (1) CDib類的聲明

// DIB.h:類CDib聲明標頭檔
#ifndef __DIB_H__
#define __DIB_H__
#include <wingdi.h>
class CDib
{
 public:
  CDib();
  ~CDib();

  BOOL Load( const char * );
  BOOL Save( const char * );
  BOOL Draw( CDC *, int nX = 0, int nY = 0, int nWidth = -1, int nHeight = -1, int mode = SRCCOPY);
  BOOL SetPalette( CDC * );

 private:
  CPalette m_Palette;
  unsigned char *m_pDib, *m_pDibBits;
  DWORD m_dwDibSize;
  BITMAPINFOHEADER *m_pBIH;
  RGBQUAD *m_pPalette;
  int m_nPaletteEntries;
};
#endif

  (2) CDib類的實現

// DIB.cpp:類CDib實現檔案
#include "stdafx.h"
#include "DIB.h"

CDib::CDib()
{
 m_pDib = NULL;
}

CDib::~CDib()
{
 // 如果位元影像已經被載入,釋放記憶體
 if (m_pDib != NULL)
  delete []m_pDib;
}

  下面這個函數非常重要,其功能為載入位元影像,類似於CBitmap類的LoadBitmap函數:

BOOL CDib::Load(const char *pszFilename)
{
 CFile cf;

 // 開啟位元影像檔案
 if (!cf.Open(pszFilename, CFile::modeRead))
  return (FALSE);

 // 獲得位元影像檔案大小,並減去BITMAPFILEHEADER的長度
 DWORD dwDibSize;
 dwDibSize = cf.GetLength() - sizeof(BITMAPFILEHEADER);

 // 為DIB位元影像分配記憶體
 unsigned char *pDib;
 pDib = new unsigned char[dwDibSize];
 if (pDib == NULL)
  return (FALSE);

 BITMAPFILEHEADER BFH;

 // 讀取位元影像檔案資料
 try
 {
  // 檔案格式是否正確有效
  if ( cf.Read(&BFH, sizeof(BITMAPFILEHEADER)) != sizeof(BITMAPFILEHEADER) ||
     BFH.bfType != ’MB’ || cf.Read(pDib, dwDibSize) != dwDibSize)
  {
   delete []pDib;
   return (FALSE);
  }
 }
 catch (CFileException *e)
 {
  e->Delete();
  delete []pDib;
  return (FALSE);
 }

 // delete先前載入的位元影像
 if (m_pDib != NULL)
  delete m_pDib;

 // 將臨時Dib資料指標和Dib大小變數賦給類成員變數
 m_pDib = pDib;
 m_dwDibSize = dwDibSize;

 // 為相應類成員變數賦BITMAPINFOHEADER和調色盤指標
 m_pBIH = (BITMAPINFOHEADER*)m_pDib;
 m_pPalette = (RGBQUAD*) &m_pDib[sizeof(BITMAPINFOHEADER)];

 // 計算調色盤中實際顏色數量
 m_nPaletteEntries = 1 << m_pBIH->biBitCount;
 if (m_pBIH->biBitCount > 8)
  m_nPaletteEntries = 0;
 else if (m_pBIH->biClrUsed != 0)
  m_nPaletteEntries = m_pBIH->biClrUsed;

 // 為相應類成員變數賦image data指標
 m_pDibBits = &m_pDib[sizeof(BITMAPINFOHEADER) + m_nPaletteEntries * sizeof (RGBQUAD)];

 // delete先前的調色盤
 if (m_Palette.GetSafeHandle() != NULL)
  m_Palette.DeleteObject();

 // 如果位元影像中存在調色盤,建立LOGPALETTE 及CPalette
 if (m_nPaletteEntries != 0)
 {
  LOGPALETTE *pLogPal = (LOGPALETTE*)new char[sizeof(LOGPALETTE) + m_nPaletteEntries *sizeof(PALETTEENTRY)];

  if (pLogPal != NULL)
  {
   pLogPal->palVersion = 0x300;
   pLogPal->palNumEntries = m_nPaletteEntries;

   for (int i = 0; i < m_nPaletteEntries; i++)
   {
    pLogPal->palPalEntry[i].peRed = m_pPalette[i].rgbRed;
    pLogPal->palPalEntry[i].peGreen = m_pPalette[i].rgbGreen;
    pLogPal->palPalEntry[i].peBlue = m_pPalette[i].rgbBlue;
   }

   //建立CPalette並釋放LOGPALETTE的記憶體
   m_Palette.CreatePalette(pLogPal);
   delete []pLogPal;
  }
 }

 return (TRUE);
}

//函數功能:儲存位元影像入BMP檔案
BOOL CDib::Save(const char *pszFilename)
{
 if (m_pDib == NULL)
  return (FALSE);

 CFile cf;
 if (!cf.Open(pszFilename, CFile::modeCreate | CFile::modeWrite))
  return (FALSE);

 try
 {
  BITMAPFILEHEADER BFH;
  memset(&BFH, 0, sizeof(BITMAPFILEHEADER));
  BFH.bfType = ’MB’;
  BFH.bfSize = sizeof(BITMAPFILEHEADER) + m_dwDibSize;
  BFH.bfOffBits = sizeof(BITMAPFILEHEADER) +
sizeof(BITMAPINFOHEADER) + m_nPaletteEntries *sizeof(RGBQUAD);

  cf.Write(&BFH, sizeof(BITMAPFILEHEADER));
  cf.Write(m_pDib, m_dwDibSize);
 }
 catch (CFileException *e)
 {
  e->Delete();
  return (FALSE);
 }
 return (TRUE);
}

  下面這個函數也非常重要,其功能為在pDC指向的CDC中繪製位元影像,起點座標為(nX,nY),繪製寬度和高度為nWidth、nHeight,最後一個參數是光柵模式:

BOOL CDib::Draw(CDC *pDC, int nX, int nY, int nWidth, int nHeight, int mode)
{
 if (m_pDib == NULL)
  return (FALSE);

 // 擷取位元影像寬度和高度賦值
 if (nWidth == - 1)
  nWidth = m_pBIH->biWidth;
 if (nHeight == - 1)
  nHeight = m_pBIH->biHeight;

 // 繪製位元影像
 StretchDIBits(pDC->m_hDC, nX, nY, nWidth, nHeight, 0, 0, m_pBIH->biWidth, m_pBIH->biHeight, m_pDibBits, (BITMAPINFO*)m_pBIH, BI_RGB, mode);

 return (TRUE);
}

//函數功能:設定調色盤
BOOL CDib::SetPalette(CDC *pDC)
{
 if (m_pDib == NULL)
  return (FALSE);

 // 檢查當前是否有一個調色盤控制代碼,對於大於256色的位元影像,為NULL
 if (m_Palette.GetSafeHandle() == NULL)
  return (TRUE);

 // 選擇調色盤,接著實施之,最後恢複老的調色盤
 CPalette *pOldPalette;
 pOldPalette = pDC->SelectPalette(&m_Palette, FALSE);
 pDC->RealizePalette();
 pDC->SelectPalette(pOldPalette, FALSE);

 return (TRUE);
}

  從整個CDib類的代碼中我們可以看出,DIB位元影像的顯示需遵循如下步驟:

  (1)讀取位元影像,本類中使用pDib = new unsigned char[dwDibSize]為位元影像中的資訊分配記憶體,另一種方法是調用API函數CreateDIBSection,譬如:

m_hBitmap = ::CreateDIBSection(pDC->GetSafeHdc(),
(LPBITMAPINFO) m_lpBMPHdr, DIB_RGB_COLORS,
(LPVOID*) &m_lpDIBits, NULL, 0);

  m_hBitmap定義為:

HBITMAP m_hBitmap;

  (2)根據讀取的位元影像資訊,計算出調色盤大小,然後建立調色盤;

  (3)調用CDib::SetPalette( CDC *pDC )設定調色盤,需要用到CDC::SelectPalette及CDC::RealizePalette兩個函數;

  (4)調用CDib::Draw(CDC *pDC, int nX, int nY, int nWidth, int nHeight, int mode)函數繪製位元影像。在此函數中,真正發揮顯示位元影像作用的是對StretchDIBits API函數的調用。StretchDIBits函數具有縮放功能,其最後一個參數也是光柵操作的模式。

  下面給出DIB位元影像的開啟及顯示並在其中加入天極網logo的函數原始碼。"DIB位元影像"父菜單下"開啟"子功能表的單擊事件訊息處理函數為(其功能為開啟位元影像並顯示之):

void CBitMapExampleDlg::OnOpendibpic()
{
 // 彈出檔案對話方塊,讓使用者選擇位元影像檔案
 CFileDialog fileDialog(TRUE, "*.BMP", NULL, NULL,"位元影像檔案(*.BMP)|*.bmp;*.BMP|");
 if (IDOK == fileDialog.DoModal())
 {
  // 載入位元影像並顯示之
  CDib dib;
  if (dib.Load(fileDialog.GetPathName()))
  {
   CClientDC dc(this);
   dib.SetPalette(&dc);
   dib.Draw(&dc);
  }
 }
}

  "DIB位元影像"父菜單下"標記"子功能表的單擊事件訊息處理函數為(其功能為給位元影像加上天極網logo):

void CBitMapExampleDlg::OnMarkDibpic()
{
 // 彈出檔案對話方塊,讓使用者選擇標記logo
 CFileDialog fileDialog(TRUE, "*.BMP", NULL, NULL, "標記位元影像檔案(*.BMP)|*.bmp;*.BMP|");
 if (IDOK == fileDialog.DoModal())
 {
  // 載入標記logo位元影像並與目標位元影像相與
  CDib dib;
  if (dib.Load(fileDialog.GetPathName()))
  {
   CClientDC dc(this);
   dib.SetPalette(&dc);
   dib.Draw(&dc, 0, 0, - 1, - 1, SRCAND);
  }
 }
}

  圖4顯示了DIB位元影像載入天極網logo後的效果,要好於圖3中加天極網logo後的DDB位元影像。圖4顯示的是真彩色位元影像相互與的結果,而圖3中的映像顏色被減少了。


圖4 在DIB位元影像中加入天極網logo

  5. 結束語

  本文介紹了位元影像及調色盤的概念,並講解了DDB位元影像與DIB位元影像的區別。在此基礎上,本文以執行個體講解了DDB位元影像和DIB位元影像的操作方式。DDB位元影像的處理相對比較簡單,對於DIB位元影像,我們需要定義一個MFC所沒有的新類CDib,它屏蔽位元影像資訊的讀取及調色盤建立的技術細節,應用程式可以方便地使用之。

  本文中的所有程式在Visual C++6.0及Windows XP平台上調試通過。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.