程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> 關於VC++ >> 利用VC++開發ASP圖像處理組件(1)

利用VC++開發ASP圖像處理組件(1)

編輯:關於VC++

一、VC++中的DC環境及GUI有關的各種對象

在Windows中有各種圖形用戶界面GUI (Graphics User Interface)對象,當我們在進行繪圖時就需要利用這些對象。而各種對象都 擁有各種屬性,下面首先介紹幾種GUI對象和擁有的屬性。

(一)、GUI有關的各種對象

在Windows中有各種圖形用戶界面GUI(Graphics User Interface)對象,當我們在進 行繪圖時就需要利用這些對象。而各種對象都擁有各種屬性,下面首先介紹幾種GUI對象和擁 有的屬性。

字體對象CFont

字體對象CFont用於輸出文字時選用不同風格和大小的字體。可選擇的風格包括:是 否為斜體,是否為粗體,字體名稱,是否有下劃線等。

刷子CBrush對象

刷子CBrush對象決定填充區域時所采用的顏色或模板。對於一個固定色的刷子來講它 的屬性為顏色,是否采用網格和網格的類型如水平的,垂直的,交叉的等。也可以利用8*8的 位圖來創建一個自定義模板的刷子,在使用這種刷子填充時系統會利用位圖逐步填充區域。

畫筆CPen

畫筆CPen對象在畫點和畫線時有用。它的屬性包括顏色,寬度,線的風格,如虛線, 實線,點劃線等。

位圖CBitmap對象

位圖CBitmap對象可以包含一幅圖像,可以保存在資源中。

CPalette調色板

CPalette調色板是一種顏色映射接口,它允許應用程序在不影響其他應用程序的前提 下,可以充分利用輸出設備的顏色描繪能力。

此外系統中還擁有一些庫存GUI對象,你可以利用CDC::SelectStockObject (SelectStockObject( int nIndex )選入這些對象,它們包括一些固定顏色的刷子,畫筆和 一些基本字體。 如:

BLACK_BRUSH 黑色刷子

NULL_BRUSH 空刷子

WHITE_PEN 白色畫筆

DEVICE_DEFAULT_FONT 默認字體

在Windows中使用GUI對象必須遵守一定的規則。首先需要創建一個合法的對象,不同的對 象創建方法不同。然後需要將該GUI對象選入DC中,同時保存DC中原來的GUI對象。如果選入 一個非法的對象將會引起異常。在使用完後應該恢復原來的對象,這一點特別重要,如果保 存一個臨時對象在DC中,而在臨時對象被銷毀後可能引起異常。有一點必須注意,每一個對 象在重新創建前必須銷毀,下面的代碼演示了這一種安全的使用方法:

OnDraw (CDC* pDC)
{
  a) CPen pen1,pen2;
  b) pen1.CreatePen (PS_SOLID,2,RGB(128,128,128));//創建畫筆對象一
  c) pen2.CreatePen (PS_SOLID,2,RGB(128,128,0));//創建畫筆對象二
  d) CPen* pOldPen=(CPen*) pDC->SelectObject(&pen1);//選擇對象進DC
  e) drawWithPen1...
  f)  (CPen*)pDC->SelectObject(&pen2);//選擇對象進DC
  g) drawWithPen2...
  h)  pen1.DeleteObject();//再次創建前先銷毀
  i) pen1.CreatePen(PS_SOLID,2,RGB(0,0,0));//再次創建對象
  j) (CPen*)pDC- >SelectObject(&pen1);//選擇對象進DC
  k) drawWithPen1...
   l)  pDC->SelectObject(pOldPen);//恢復
}   

OnDraw(CDC* pDC) 函數是VC中最常見的圖形輸出刷新函數,參數pDC 為CDC類的一個指針,我們通過它進行畫圖 操作。

代碼a行定義CPen 類的兩個畫筆對象pen1,pen2;分別在行b,c 調用CPen 類成 員函數CreatePen 創建兩個實心畫筆, 其顏色RGB值分別為RGB(128,128,128), RGB (128,128,0)。行d 將新創建的畫筆pen1選入當前設備上下文DC環境並將舊畫筆保存在 pOldPen裡,這樣在e行輸出的圖形或文本線條將以pen1的屬性填充。f, g 行選入畫筆二並輸 出。i,j 行銷毀畫筆一並且創建RGB(0,0,0)色的畫筆,k行輸出。最後一行l行將舊畫筆選入 當前DC環境,輸出完畢。字體對象,刷子對象及位圖對象的使用方法同上,具體使用將在下 面的實例中描述。

在繪圖時都需要一個DC對象,DC(Device Context設備環境)對象 是一個抽象的作圖環境,可能是對應屏幕,也可能是對應打印機或其它。這個環境是設備無 關的,所以在對不同的設備輸出時只需要使用不同的設備環境就行了,而作圖方式可以完全 不變。

(二)、DC環境下輸出文本

在MFC裡有一個設備環境類CDC封裝了有關對 物理設備的輸出。CDC是設備環境類的基類直接由CObject派生。是圖形設備接口的關鍵元素 ,它代表了物理設備。每一個C++設備環境對象都有相對應Windows設備環境,並通過一個32 位類型的HDC句柄來標識。CDC類的虛擬性使我們可以很容易的做到編寫同時適用於多種設備 的代碼。例如OnDraw函數的pDC->TextOut(0,0,"Hello");既可以適用於顯示器 、還可以適用於打印預覽和打印,只需要在CView::OnDraw函數的pDC參數指向不同的對象類 。

CClientDC和CWindowDC是顯示設備環境類,都是由CDC派生而來,區別在於 CClientDC是窗口的客戶區不包括邊框、標題欄和菜單欄,(0,0)指客戶區域的左上角。 CWindowDC的(0,0)指整個屏幕的左上角,這意味著我們可以在顯示器的任意地方繪圖,包 括窗口邊框、標題欄和菜單欄等等。CWindowDC一般應用在框架窗口,而不是視圖窗口。

CDC對象被創建後一定要在合適的時候將它刪除掉,如果忘記了刪除設備環境對象則 會造成內存丟失。下面程序段實現在DC環境下輸出文本。

long CImg::OutImgFromText(LPCTSTR vFileName,
LPCTSTR lpText,
LPCTSTR lpBgImg,
long lCSet,
LPCTSTR lpFont,
long lWidth,
long lHeight,
long lLeft,
long lTop,
long llfHeight,
long lWeight,
long l3D)
{
i. m_nWidth = lWidth;
ii. m_nHeight = lHeight;
iii. if((m_nWidth % 8) != 0)
1. m_nWidth = ((int)(m_nWidth/8) + 1) * 8;
iv. if(m_nWidth < 3 * lLeft)
1. m_nWidth = 3 * lLeft;
v. if(m_nHeight < 3 * lTop)
1. m_nHeight = 3 * lTop;
vi. int nFHeight = llfHeight;
vii. if(0 == nFHeight)
1. nFHeight = 1;
viii. int nRealClientWidth = (m_nWidth - 2 * lLeft);
ix. HDC hDC;
x. hDC = CreateCompatibleDC(NULL);
xi. LOGFONT lf;
xii. memset (&lf,0,sizeof(lf));
xiii. lf.lfCharSet = GB2312_CHARSET;
xiv. lf.lfHeight = nFHeight;
xv. lstrcpy(lf.lfFaceName, lpFont);
xvi. lf.lfPitchAndFamily = 8;
xvii. lf.lfWeight = lWeight;
xviii. HFONT hFont = CreateFontIndirect(&lf);
1. HFONT hOldFont = (HFONT) SelectObject(hDC, hFont); //選入字體
xix. CComBSTR bstrText(lpText);
xx. RECT rectClient = {lLeft, lTop, m_nWidth - lLeft, m_nHeight - lTop};
xxi. ::DrawText(
1. hDC,
2. bstrText.m_str,
3. bstrText.Length (),
4. &rectClient,
5. DT_WORDBREAK|DT_LEFT|DT_CALCRECT
6. ); //計算輸出距形
xxii. int nRealHeight = rectClient.bottom + lTop;
xxiii. if(m_nHeight < nRealHeight)
1. m_nHeight = nRealHeight;
xxiv. else
1. rectClient.bottom = m_nHeight - lTop;
xxv. HBITMAP hBitmap;
xxvi. hBitmap = CreateDiscardableBitmap(hDC, m_nWidth, m_nHeight);
xxvii. SelectObject(hDC, hBitmap);
xxviii. //---------------------------------
xxix. HBRUSH hBBg = CreateSolidBrush(RGB(255,255,255));
xxx. RECT rectFull = {0, 0, m_nWidth, m_nHeight};
xxxi. FillRect(hDC, &rectFull, hBBg);
xxxii. if(l3D > 0)
xxxiii. {
1. //SetBkColor(hDC, RGB (200,193,193));
2. SetTextColor(hDC, ::GetSysColor(COLOR_3DDKSHADOW));
3. SetBkMode(hDC, OPAQUE);
xxxiv. }
xxxv. else
xxxvi. {
1. SetBkColor(hDC, RGB(255,255,255));
2. SetTextColor(hDC, RGB(0,0,0));
3. SetBkMode(hDC, TRANSPARENT);
xxxvii. }
xxxviii. ::DrawText(
1. hDC,
2. bstrText.m_str,
3. bstrText.Length(),
4. &rectClient,
5. DT_WORDBREAK
6. ); //輸出
xxxix. if(l3D > 0)
xl. {
1. SetTextColor(hDC, ::GetSysColor(COLOR_3DHILIGHT));
2. SetBkMode(hDC, TRANSPARENT);
3. rectClient.left = rectClient.left + l3D;
4. rectClient.top = rectClient.top - 1;
5. rectClient.right = rectClient.right + l3D;
6. rectClient.bottom = rectClient.bottom - 1;
7. ::DrawText(
a) hDC,
b) lpText,
c) wcslen(lpText),
d) &rectClient,
e) DT_WORDBREAK);
xli. }
xlii. SelectObject(hDC, hOldFont);
xliii. DeleteObject(hFont);
xliv. DeleteObject(hBBg);
xlv. SaveDCBmp(hDC, hBitmap, vFileName);
xlvi. //SaveDCJPG(hDC, hBitmap, vFileName);
xlvii. DeleteObject(hBitmap);
xlviii. ::ReleaseDC(NULL, hDC);
xlix. return 0;
}

此函數功能:通過輸入特定長度的 文本,輸出圖像到指定文件

參數說明:

vFileName: 圖像保存文件路徑

lpText: 圖像輸出文本

lpBgImg: 圖像背景路徑

lCSet: 字符集

lpFont: 字體名稱

lWidth: 圖像輸出寬度

lHeight: 圖像輸出高度

lLeft: 圖像輸出左邊距,與右邊距相同

lTop: 圖像輸出上邊距,與下邊距相 同

llfHeight: 文本輸出字體高度,字體寬度隨高度等比例變化

lWeight: 文 本重量

l3D: 三D效果,值為0時無三D效果,大於0時其值為字體偏移量

程序i. 至 viii. 行對輸入參數合法性進行檢查及究正。

行ix. ,x. 定義及創建與指定設備 兼容的設備上下文句柄hDC。

行xi. 至 xviii.1 行定義LOGFONT 邏輯字體結構並填充 。通過CreateFontIndirect(&lf) 創建字體並調用SelectObject(hDC, hFont)將創建字 體選入設備上下文,原字體句柄保存在hOldFont裡。

xix. 至 xxiv. 行取得輸入文本 長度,在當前字體環境下調用DrawText函數計算輸出矩形,並將其矩形保存在rectClient裡 ,以便調整DC輸出矩形大小。

行xxvi. 利用上面計算出的長寬創建位圖句柄,行 xxvii.將其選入設備上下文,准備工作完畢,繪圖工作正式開始。

在此函數中,畫筆 及刷子我們使用系統默認設置,不再重復申請。

行xxxii.判斷三D偏移量是否大於零 ,如果不為零,輸出三D效果。

行xxxviii.在新矩形下輸入文本。如果有三D輸出請求 ,將矩形偏移l3D個像素,再次輸出文本,以顯示三D效果。

xlii. 行選入舊字體。

xliii. 行以後刪除對象保存位圖及恢復現場。保存位圖功能SaveDCBmp將在下節討論 。

二、位圖文件

(一)、位圖文件結構

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

1、位圖文件頭

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

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

其中的bfType 值應該是“BM”(0x4d42),標志該文件是位圖文件。bfSize的值是位圖文件的 大小。bfReserved1, bfReserved2 為保留字,值為0。bfOffBits為位圖文件大小與DIB(設 備無關的位圖 Device-indepentent bitmap)位圖數據的大小之差。如:

BITMAPFILEHEADER bmfHdr;
bmfHdr.bfType = 0x4D42; // "BM"
dwDIBSize = sizeof(BITMAPFILEHEADER) + sizeof (BITMAPINFOHEADER) + dwPaletteSize + dwBmBitsSize;
bmfHdr.bfSize = dwDIBSize;
bmfHdr.bfReserved1 = 0;
bmfHdr.bfReserved2 = 0;
bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof (BITMAPINFOHEADER) + dwPaletteSize;

2、位圖信息

位圖信息中所記錄的 值用於分配內存,設置調色板信息,讀取像素值等。以下是位圖信息結構的定義:

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

可見位圖信息也是由兩部分組成 的:位圖信息頭 + 顏色表

2.1、位圖信息頭

位圖信息頭包含了單個像素所用 字節數以及描述顏色的格式,此外還包括位圖的寬度、高度、目標設備的位平面數、圖像的 壓縮格式。以下是位圖信息頭結構的定義:

typedef 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 結 構BITMAPINFOHEADER的字節數,即sizeof(BITMAPINFOHEADER)

biWidth 以像素為單位 的圖像寬度

biHeight 以像素為單位的圖像長度

biplanes 目標設備的位平面 數

biBitCount 每個像素的位數

對於每個像素的位數,分別有一下意義:

0,用在JPEG格式中

1,單色圖,調色板中含有兩種顏色,也就是我們通常說 的黑白圖片

4,16色圖

8,256色圖,通常說的灰度圖

16,64K圖,一般 沒有調色板,圖像數據中每兩個字節表示一個像素,5個或6個位表示一個RGB分量

24 ,16M真彩色圖,一般沒有調色板,圖像數據中每3個字節表示一個像素,每個字節表示一個 RGB分量

32,4G真彩色,一般沒有調色板,每4個字節表示一個像素,相對24位真彩圖 而言,加入了一個透明度,即RGBA模式

biCompression 圖像的壓縮格式(這個值幾乎 總是為0)

biSizeImage 以字節為單位的圖像數據的大小(對BI_RGB壓縮方式而言)

biXPelsPermeter 水平方向上的每米的像素個數

biYpelsPerMeter 垂直方向 上的每米的像素個數

biClrused 調色板中實際使用的顏色數,這個值通常為 0

biClrImportant 現實位圖時必須的顏色數, 這個值通常為0,表示所有的顏色都是 必需的

2.2、顏色表

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

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

rgbBlue 藍色的強度

rgbGreen 綠色的強 度

rgbRed 紅色的強度

rgbReserved 保留字,為0

其中需要注意的問題 是,RGBQUAD結構中的顏色順序是BGR,而不是平常的RGB。

3、位圖數據

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

(二)、存儲區域DC到位圖文件

認識了位圖文件的結構以後,對特定位圖文件進行操作就顯得簡單了。我們通過創建 特定的畫筆,刷子及位圖對象,在DC 環境下進行繪圖後,就要將保存在DC 裡的圖像存儲到 位圖文件中,以便使用及輸出到其他媒體。下面代碼實現將設圖上下文圖形保存為位圖文件 。

BOOL CImg::SaveDCBmp(HDC hDC, HBITMAP hBitmap, LPCTSTR lpFileName)
{
  //當前分辨率下每象素所占字節數
  int iBits;
  //位圖中每象素所占字節數
  WORD wBitCount;
  //定義調色板大小 , 位圖中像素字節大小 ,位圖文件大小 , 寫入文件字節數
  DWORD dwPaletteSize=0, dwBmBitsSize=0, dwDIBSize=0, dwWritten=0;
  //位圖屬性結 構
  BITMAP Bitmap;
  //位圖文件頭結構
  BITMAPFILEHEADER bmfHdr;
  //位圖信息頭結構
  BITMAPINFOHEADER bi;
  //指向位 圖信息頭結構
  LPBITMAPINFOHEADER lpbi;
  //定義文件,分配內存句柄 ,調色板句柄
  HANDLE fh, hDib, hPal,hOldPal=NULL;

  //計算位 圖文件每個像素所占字節數
  iBits = GetDeviceCaps(hDC, BITSPIXEL) * GetDeviceCaps(hDC, PLANES);

  if (iBits <= 1) wBitCount = 1;
  else if (iBits <= 4) wBitCount = 4;
  else if (iBits <= 8) wBitCount = 8;
  else wBitCount = 24;

  //wBitCount = 4;

  GetObject(hBitmap, sizeof(Bitmap), (LPSTR)&Bitmap);
   bi.biSize = sizeof(BITMAPINFOHEADER);
  bi.biWidth = Bitmap.bmWidth;
  bi.biHeight = Bitmap.bmHeight;
  bi.biPlanes = 1;
   bi.biBitCount = wBitCount;
  bi.biCompression = BI_RGB;
   bi.biSizeImage = 0;
  bi.biXPelsPerMeter = 0;
  bi.biYPelsPerMeter = 0;
  bi.biClrImportant = 0;
  bi.biClrUsed = 0;

   dwBmBitsSize = ((Bitmap.bmWidth * wBitCount + 31) / 32) * 4 * Bitmap.bmHeight;

  //為位圖內容分配內存
  hDib = GlobalAlloc(GHND,dwBmBitsSize + dwPaletteSize + sizeof(BITMAPINFOHEADER));
  lpbi = (LPBITMAPINFOHEADER) GlobalLock(hDib);
  *lpbi = bi;

  // 處理調色板
  hPal = GetStockObject(DEFAULT_PALETTE);
  if (hPal)
  {
     hOldPal = ::SelectPalette(hDC, (HPALETTE)hPal, FALSE);
  }

   // 獲取該調色板下新的像素值
  GetDIBits(hDC, hBitmap, 0, (UINT) Bitmap.bmHeight, (LPSTR)lpbi + sizeof(BITMAPINFOHEADER)
     +dwPaletteSize, (BITMAPINFO *)lpbi, DIB_RGB_COLORS);

  //恢復調色板
  if (hOldPal)
  {
    ::SelectPalette(hDC, (HPALETTE) hOldPal, TRUE);
    RealizePalette(hDC);
  }

  //創 建位圖文件
  fh = CreateFile(lpFileName, GENERIC_WRITE,0, NULL, CREATE_ALWAYS,
    FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);

  if (fh == INVALID_HANDLE_VALUE) return FALSE;

   // 設置位圖文件頭
  bmfHdr.bfType = 0x4D42; // "BM"
   dwDIBSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + dwPaletteSize + dwBmBitsSize;
  bmfHdr.bfSize = dwDIBSize;
  bmfHdr.bfReserved1 = 0;
  bmfHdr.bfReserved2 = 0;
  bmfHdr.bfOffBits = (DWORD)sizeof (BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER) + dwPaletteSize;
  // 寫入位圖文件頭
  WriteFile(fh, (LPSTR)&bmfHdr, sizeof (BITMAPFILEHEADER), &dwWritten, NULL);
  // 寫入位圖文件其余內容
  WriteFile(fh, (LPSTR)lpbi, dwDIBSize, &dwWritten, NULL);
  //清除
  GlobalUnlock(hDib);
  GlobalFree(hDib);
  CloseHandle (fh);

  return TRUE;
}    

保存位圖文件前通過 GetObject函數取得位圖長度, 通過GetDIBits取得位圖圖像掃描數據,填充 BITMAPFILEHEADER(位圖文件頭結構); BITMAPINFOHEADER (位圖信息頭結構); 然後寫入位圖 文件頭:

WriteFile(fh, (LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER), &dwWritten, NULL);

寫入位圖文件其余內容:

WriteFile(fh, (LPSTR)lpbi, dwDIBSize, &dwWritten, NULL);

以 文件頭 + 位圖信息 + 位 圖像素數據 的順序進行存儲。

下載源代碼:http://www.vckbase.com/code/downcode.asp?id=2362

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved