在利用VC進行數據庫編程時,經常需要處理數據庫中的圖像數據,將該圖像從數據庫中讀取出來并顯示,圖像數據與文本字段不同,它是作為OLE字段在數據庫中存儲,通過數據集對象的成員變量自動交換得到的圖像數據,得到的數據并不能直接顯示,如何處理圖像數據,一直是數據庫編程中的一個難點,目前關于VC進行數據庫編程的資料不少,但很少涉及圖像數據的操作,筆者針對一現狀,結合自己開發的一個項目,解決了如何顯示數據庫中的圖像這一問題,本文以操作ACESS數據庫為例子,講解一下自己的實現思路,希望對愛好VC編程的朋友們有所幫助,以起到拋磚引玉的作用。
為了簡化問題,該數據庫的表中只有一個名為Images的OLE字段,我使用DAO連接操作數據庫,讀取的圖像數據顯示在一個對話框上,至于使用ODBC、DAO還是ADO,這要根據具體情況而定,但無論使用哪一種,對圖像的顯示來說,實現的過程是大同小異的。由于篇幅有限,文章中對如何實現數據庫的連接不再作具體的說明,有興趣的讀者朋友可以參考VC數據庫編程的資料。實現過程中,首先定義一個CDaoRecordset的子類 CimageData如下:
class CimageData : public CDaoRecordset { public: CimageData (CDaoDatabase* pDatabase = NULL); DECLARE_DYNAMIC(CimageData) file://{{AFX_FIELD(CimageData, CDaoRecordset) CByteArray m_Images;//聲明字節數組用來存放圖像數據 file://}}AFX_FIELD // Overrides // ClassWizard generated virtual function overrides file://{{AFX_VIRTUAL(CimageData) public: virtual CString GetDefaultDBName(); virtual CString GetDefaultSQL(); virtual void DoFieldExchange(CDaoFieldExchange* pFX); file://}}AFX_VIRTUAL
該類的實現為:
CimageData:: CimageData (CDaoDatabase* pdb) : CDaoRecordset(pdb) { file://{{AFX_FIELD_INIT(CimageData) m_nFields = 1;//數據庫的表中僅有一個字段 file://}}AFX_FIELD_INIT m_nDefaultType = dbOpenDynaset;//以動態集方式打開數據庫 } CString CimageData::GetDefaultDBName() { return _T("E:\\IMAGES.mdb");//默認的ACESS數據庫在E盤,名為IMAGES }
CString CimageData::GetDefaultSQL() { return _T("[Table]");//默認打開數據庫中名為"Table"的表 }
void CimageData::DoFieldExchange(CDaoFieldExchange* pFX) { file://{{AFX_FIELD_MAP(CimageData) pFX->SetFieldType(CDaoFieldExchange::outputColumn); DFX_Binary(pFX, _T("[Images]"), m_Images);//以二進制方式在Images字段和m_Images變量間交換數據 file://}}AFX_FIELD_MAP }
有了該類,就可以定義相應的對象來與數據庫中的圖像字段交換數據,下面定義的函數GetImageData()說明了如何根據讀取的OLE字段數據生成待顯示的圖像,需要注意的是該函數中使用的CBitmap類的變量Bitmap是預定義的一個全局變量:
BOOL CImageDlg:: GetImageData(CByteArray & DBArray) { CByteArray Array; Array.Copy( DBArray); int HeaderLen = 78 + sizeof(BITMAPFILEHEADER); file://確定圖像頭信息的起始位置 Array.RemoveAt( 0, HeaderLen ); // 移動到圖像頭信息的起始位置 BITMAPINFOHEADER &bmiHeader = *(LPBITMAPINFOHEADER)Array.GetData() ; BITMAPINFO &bmInfo = *(LPBITMAPINFO)Array.GetData() ; file://得到圖像數據的頭信息 int nColors=bmiHeader.biClrUsed ? bmiHeader.biClrUsed : 1 << bmiHeader.biBitCount; file://確定圖像的顏色數 LPVOID lpDIBBits; if( bmInfo.bmiHeader.biBitCount > 8 ) lpDIBBits=(LPVOID)((LPDWORD)(bmInfo.bmiColors+bmInfo.bmiHeader.biClrUsed)+ ((bmInfo.bmiHeader.biCompression == BI_BITFIELDS) ? 3 : 0)); else lpDIBBits = (LPVOID)(bmInfo.bmiColors + nColors); file://得到圖像各個像素的具體數據 CClientDC dc(NULL); HBITMAP hBmp = CreateDIBitmap( dc.m_hDC, &bmiHeader, CBM_INIT, lpDIBBits, &bmInfo, DIB_RGB_COLORS); file://生成位圖句柄 Bitmap.Attach( hBmp );//將該句柄與定義的Bitmap對象聯系在一起 Array.RemoveAll(); file://釋放內存
return TRUE;
}
有了上面的準備工作,現在可以實現圖像的顯示函數了,其實現如下:
void CImageDlg::OnShowImage() { CimageData db;//定義記錄集對象 db.Open();打開數據庫 GetImageData(db.m_Images);//根據記錄集對象的成員變量生成圖像對象 file://以下是在對話框的固定區域顯示圖像 CPaintDC dc(this); if (!(Bitmap.m_hObject == NULL)) { CDC dcMem; dcMem.CreateCompatibleDC( &dc ); file://create a Memory Image CBitmap* pbmpOld ; BITMAP BmpSize ; Bitmap.GetBitmap(&BmpSize); file://get Image Size pbmpOld = dcMem.SelectObject(&Bitmap); dc.StretchBlt( 20, 20, 200, 200, &dcMem, 0, 0, BmpSize.bmWidth, BmpSize.bmHeight, SRCCOPY); dcMem.SelectObject( pbmpOld );
}
以上代碼中使用的數據庫為ACESS97,程序在windows98、Visual C++6.0環境下編譯通過,運行正常。
|