使用VC++開發(fā)ASP圖像處理組件
發(fā)表時(shí)間:2024-02-13 來源:明輝站整理相關(guān)軟件相關(guān)文章人氣:2
[摘要]作者:符文科 (龍飛) 發(fā)布時(shí)間: 2004-04 作者:符文科 西北師范大學(xué)2001級(jí)計(jì)算機(jī)成人專升本E-Mail vc@hahame.net 聯(lián)系方式: 13359319378 0931-8553848網(wǎng)站 http://www.ourcode.net代碼下載:http://www.nwnu....
作者:符文科 (龍飛)
發(fā)布時(shí)間: 2004-04 作者:符文科 西北師范大學(xué)2001級(jí)計(jì)算機(jī)成人專升本
E-Mail vc@hahame.net 聯(lián)系方式: 13359319378 0931-8553848
網(wǎng)站 http://www.ourcode.net
代碼下載:http://www.nwnu.net/src/XTAspImage_to_vckbase.rar
一 VC++中的DC環(huán)境及GUI有關(guān)的各種對(duì)象
在Windows中有各種圖形用戶界面GUI(Graphics User Interface)對(duì)象,當(dāng)我們?cè)谶M(jìn)行繪圖時(shí)就需要利用這些對(duì)象。而各種對(duì)象都擁有各種屬性,下面首先介紹幾種GUI對(duì)象和擁有的屬性。
(一) GUI有關(guān)的各種對(duì)象
在Windows中有各種圖形用戶界面GUI(Graphics User Interface)對(duì)象,當(dāng)我們?cè)谶M(jìn)行繪圖時(shí)就需要利用這些對(duì)象。而各種對(duì)象都擁有各種屬性,下面首先介紹幾種GUI對(duì)象和擁有的屬性。
字體對(duì)象CFont
字體對(duì)象CFont用于輸出文字時(shí)選用不同風(fēng)格和大小的字體。可選擇的風(fēng)格包括:是否為斜體,是否為粗體,字體名稱,是否有下劃線等。
刷子CBrush對(duì)象
刷子CBrush對(duì)象決定填充區(qū)域時(shí)所采用的顏色或模板。對(duì)于一個(gè)固定色的刷子來講它的屬性為顏色,是否采用網(wǎng)格和網(wǎng)格的類型如水平的,垂直的,交叉的等。也可以利用8*8的位圖來創(chuàng)建一個(gè)自定義模板的刷子,在使用這種刷子填充時(shí)系統(tǒng)會(huì)利用位圖逐步填充區(qū)域。
畫筆CPen
畫筆CPen對(duì)象在畫點(diǎn)和畫線時(shí)有用。它的屬性包括顏色,寬度,線的風(fēng)格,如虛線,實(shí)線,點(diǎn)劃線等。
位圖CBitmap對(duì)象
位圖CBitmap對(duì)象可以包含一幅圖像,可以保存在資源中。
CPalette調(diào)色板
CPalette調(diào)色板是一種顏色映射接口,它允許應(yīng)用程序在不影響其他應(yīng)用程序的前提下,可以充分利用輸出設(shè)備的顏色描繪能力。
此外系統(tǒng)中還擁有一些庫存GUI對(duì)象,你可以利用CDC::SelectStockObject(SelectStockObject( int nIndex )選入這些對(duì)象,它們包括一些固定顏色的刷子,畫筆和一些基本字體。 如:
BLACK_BRUSH 黑色刷子
NULL_BRUSH 空刷子
WHITE_PEN 白色畫筆
DEVICE_DEFAULT_FONT 默認(rèn)字體
在Windows中使用GUI對(duì)象必須遵守一定的規(guī)則。首先需要?jiǎng)?chuàng)建一個(gè)合法的對(duì)象,不同的對(duì)象創(chuàng)建方法不同。然后需要將該GUI對(duì)象選入DC中,同時(shí)保存DC中原來的GUI對(duì)象。如果選入一個(gè)非法的對(duì)象將會(huì)引起異常。在使用完后應(yīng)該恢復(fù)原來的對(duì)象,這一點(diǎn)特別重要,如果保存一個(gè)臨時(shí)對(duì)象在DC中,而在臨時(shí)對(duì)象被銷毀后可能引起異常。有一點(diǎn)必須注意,每一個(gè)對(duì)象在重新創(chuàng)建前必須銷毀,下面的代碼演示了這一種安全的使用方法:
OnDraw(CDC* pDC)
{
a) CPen pen1,pen2;
b) pen1.CreatePen(PS_SOLID,2,RGB(128,128,128));//創(chuàng)建畫筆對(duì)象一
c) pen2.CreatePen(PS_SOLID,2,RGB(128,128,0));//創(chuàng)建畫筆對(duì)象二
d) CPen* pOldPen=(CPen*)pDC->SelectObject(&pen1);//選擇對(duì)象進(jìn)DC
e) drawWithPen1...
f) (CPen*)pDC->SelectObject(&pen2);//選擇對(duì)象進(jìn)DC
g) drawWithPen2...
h) pen1.DeleteObject();//再次創(chuàng)建前先銷毀
i) pen1.CreatePen(PS_SOLID,2,RGB(0,0,0));//再次創(chuàng)建對(duì)象
j) (CPen*)pDC->SelectObject(&pen1);//選擇對(duì)象進(jìn)DC
k) drawWithPen1...
l) pDC->SelectObject(pOldPen);//恢復(fù)
}
OnDraw(CDC* pDC) 函數(shù)是VC中最常見的圖形輸出刷新函數(shù),參數(shù)pDC 為CDC類的一個(gè)指針,我們通過它進(jìn)行畫圖操作。
代碼a行定義CPen 類的兩個(gè)畫筆對(duì)象pen1,pen2, 分別在行b,c 調(diào)用CPen 類成員函數(shù)CreatePen 創(chuàng)建兩個(gè)實(shí)心畫筆, 其顏色RGB值分別為RGB(128,128,128), RGB(128,128,0)。行d 將新創(chuàng)建的畫筆pen1選入當(dāng)前設(shè)備上下文DC環(huán)境并將舊畫筆保存在pOldPen里,這樣在e行輸出的圖形或文本線條將以pen1的屬性填充。f, g 行選入畫筆二并輸出。i , j 行銷毀畫筆一并且創(chuàng)建RGB(0,0,0)色的畫筆,k行輸出。最后一行l(wèi)行將舊畫筆選入當(dāng)前DC環(huán)境,輸出完畢。
字體對(duì)象,刷子對(duì)象及位圖對(duì)象的使用方法同上,具體使用將在下面的實(shí)例中描述。
在繪圖時(shí)都需要一個(gè)DC對(duì)象,DC(Device Context設(shè)備環(huán)境)對(duì)象是一個(gè)抽象的作圖環(huán)境,可能是對(duì)應(yīng)屏幕,也可能是對(duì)應(yīng)打印機(jī)或其它。這個(gè)環(huán)境是設(shè)備無關(guān)的,所以在對(duì)不同的設(shè)備輸出時(shí)只需要使用不同的設(shè)備環(huán)境就行了,而作圖方式可以完全不變。
(二)DC環(huán)境下輸出文本
在MFC里有一個(gè)設(shè)備環(huán)境類CDC封裝了有關(guān)對(duì)物理設(shè)備的輸出。
CDC是設(shè)備環(huán)境類的基類直接由CObject派生。是圖形設(shè)備接口的關(guān)鍵元素,它代表了物理設(shè)備。每一個(gè)C++設(shè)備環(huán)境對(duì)象都有相對(duì)應(yīng)Windows設(shè)備環(huán)境,并通過一個(gè)32位類型的HDC句柄來標(biāo)識(shí)。CDC類的虛擬性使我們可以很容易的做到編寫同時(shí)適用于多種設(shè)備的代碼。例如OnDraw函數(shù)的pDC->TextOut(0,0,"Hello");既可以適用于顯示器、還可以適用于打印預(yù)覽和打印,只需要在CView::OnDraw函數(shù)的pDC參數(shù)指向不同的對(duì)象類。
CClientDC和CWindowDC是顯示設(shè)備環(huán)境類,都是由CDC派生而來,區(qū)別在于CClientDC是窗口的客戶區(qū)不包括邊框、標(biāo)題欄和菜單欄,(0,0)指客戶區(qū)域的左上角。CWindowDC的(0,0)指整個(gè)屏幕的左上角,這意味著我們可以在顯示器的任意地方繪圖,包括窗口邊框、標(biāo)題欄和菜單欄等等。CWindowDC一般應(yīng)用在框架窗口,而不是視圖窗口。
CDC對(duì)象被創(chuàng)建后一定要在合適的時(shí)候?qū)⑺鼊h除掉,如果忘記了刪除設(shè)備環(huán)境對(duì)象則會(huì)造成內(nèi)存丟失。下面程序段實(shí)現(xiàn)在DC環(huán)境下輸出文本。
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. ); //計(jì)算輸出距形
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;
}
此函數(shù)功能:通過輸入特定長度的文本,輸出圖像到指定文件
參數(shù)說明:
vFileName: 圖像保存文件路徑
lpText: 圖像輸出文本
lpBgImg: 圖像背景路徑
lCSet: 字符集
lpFont: 字體名稱
lWidth: 圖像輸出寬度
lHeight: 圖像輸出高度
lLeft: 圖像輸出左邊距,與右邊距相同
lTop: 圖像輸出上邊距,與下邊距相同
llfHeight: 文本輸出字體高度,字體寬度隨高度等比例變化
lWeight: 文本重量
l3D: 三D效果,值為0時(shí)無三D效果,大于0時(shí)其值為字體偏移量
程序i. 至 viii. 行對(duì)輸入?yún)?shù)合法性進(jìn)行檢查及究正。
行ix. ,x. 定義及創(chuàng)建與指定設(shè)備兼容的設(shè)備上下文句柄hDC。
行xi. 至 xviii.1 行定義LOGFONT 邏輯字體結(jié)構(gòu)并填充。通過CreateFontIndirect(&lf) 創(chuàng)建字體并調(diào)用SelectObject(hDC, hFont)將創(chuàng)建字體選入設(shè)備上下文,原字體句柄保存在hOldFont里。
xix. 至 xxiv. 行取得輸入文本長度,在當(dāng)前字體環(huán)境下調(diào)用DrawText函數(shù)計(jì)算輸出矩形,并將其矩形保存在rectClient里,以便調(diào)整DC輸出矩形大小。
行xxvi. 利用上面計(jì)算出的長寬創(chuàng)建位圖句柄,行xxvii.將其選入設(shè)備上下文,準(zhǔn)備工作完畢,繪圖工作正式開始。
在此函數(shù)中,畫筆及刷子我們使用系統(tǒng)默認(rèn)設(shè)置,不再重復(fù)申請(qǐng)。
行xxxii.判斷三D偏移量是否大于零,如果不為零,輸出三D效果。
行xxxviii.在新矩形下輸入文本。如果有三D輸出請(qǐng)求,將矩形偏移l3D個(gè)像素,再次輸出文本,以顯示三D效果。
xlii. 行選入舊字體。
xliii. 行以后刪除對(duì)象保存位圖及恢復(fù)現(xiàn)場(chǎng)。保存位圖功能SaveDCBmp將在下節(jié)討論。
二 位圖文件
(一)、位圖文件結(jié)構(gòu)
位圖文件由三部分組成:文件頭 + 位圖信息 + 位圖像素?cái)?shù)據(jù)
1、位圖文件頭
位圖文件頭主要用于識(shí)別位圖文件。以下是位圖文件頭結(jié)構(gòu)的定義:
typedef struct tagBITMAPFILEHEADER {
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
} BITMAPFILEHEADER;
其中的bfType值應(yīng)該是“BM”(0x4d42),標(biāo)志該文件是位圖文件。bfSize的值是位圖文件的大小。bfReserved1, bfReserved2 為保留字,值為0。bfOffBits為位圖文件大小與DIB(設(shè)備無關(guān)的位圖 Device-indepentent bitmap)位圖數(shù)據(jù)的大小之差。如:
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、位圖信息
位圖信息中所記錄的值用于分配內(nèi)存,設(shè)置調(diào)色板信息,讀取像素值等。
以下是位圖信息結(jié)構(gòu)的定義:
typedef struct tagBITMAPINFO {
BITMAPINFOHEADER bmiHeader;
RGBQUAD bmiColors[1];
} BITMAPINFO;
可見位圖信息也是由兩部分組成的:位圖信息頭 + 顏色表
2.1位圖信息頭
位圖信息頭包含了單個(gè)像素所用字節(jié)數(shù)以及描述顏色的格式,此外還包括位圖的寬度、高度、目標(biāo)設(shè)備的位平面數(shù)、圖像的壓縮格式。
以下是位圖信息頭結(jié)構(gòu)的定義:
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 結(jié)構(gòu)BITMAPINFOHEADER的字節(jié)數(shù),即sizeof(BITMAPINFOHEADER)
biWidth 以像素為單位的圖像寬度
biHeight 以像素為單位的圖像長度
biplanes 目標(biāo)設(shè)備的位平面數(shù)
biBitCount 每個(gè)像素的位數(shù)
對(duì)于每個(gè)像素的位數(shù),分別有一下意義:
0,用在JPEG格式中
1,單色圖,調(diào)色板中含有兩種顏色,也就是我們通常說的黑白圖片
4,16色圖
8,256色圖,通常說的灰度圖
16,64K圖,一般沒有調(diào)色板,圖像數(shù)據(jù)中每?jī)蓚€(gè)字節(jié)表示一個(gè)像素,5個(gè)或6個(gè)位表示一個(gè)RGB分量
24,16M真彩色圖,一般沒有調(diào)色板,圖像數(shù)據(jù)中每3個(gè)字節(jié)表示一個(gè)像素,每個(gè)字節(jié)表示一個(gè)RGB分量
32,4G真彩色,一般沒有調(diào)色板,每4個(gè)字節(jié)表示一個(gè)像素,相對(duì)24位真彩圖而言,加入了一個(gè)透明度,即RGBA模式
biCompression 圖像的壓縮格式(這個(gè)值幾乎總是為0)
biSizeImage 以字節(jié)為單位的圖像數(shù)據(jù)的大�。▽�(duì)BI_RGB壓縮方式而言)
biXPelsPermeter 水平方向上的每米的像素個(gè)數(shù)
biYpelsPerMeter 垂直方向上的每米的像素個(gè)數(shù)
biClrused 調(diào)色板中實(shí)際使用的顏色數(shù),這個(gè)值通常為0
biClrImportant 現(xiàn)實(shí)位圖時(shí)必須的顏色數(shù), 這個(gè)值通常為0,表示所有的顏色都是必需的
2.2顏色表
顏色表一般是針對(duì)16位以下的圖像而設(shè)置的,對(duì)于16位和16位以上的圖像,由于其位圖像素?cái)?shù)據(jù)中直接對(duì)對(duì)應(yīng)像素的RGB(A)顏色進(jìn)行描述,因而省卻了調(diào)色板。而對(duì)于16位以下的圖像,由于其位圖像素?cái)?shù)據(jù)中記錄的只是調(diào)色板索引值,因而需要根據(jù)這個(gè)索引到調(diào)色板去取得相應(yīng)的RGB(A)顏色。顏色表的作用就是創(chuàng)建調(diào)色板。
顏色表是由顏色表項(xiàng)組成的,顏色表項(xiàng)結(jié)構(gòu)的定義如下:
typedef struct tagRGBQUAD { // rgbq
BYTE rgbBlue;
BYTE rgbGreen;
BYTE rgbRed;
BYTE rgbReserved;
} RGBQUAD;
rgbBlue 藍(lán)色的強(qiáng)度
rgbGreen 綠色的強(qiáng)度
rgbRed 紅色的強(qiáng)度
rgbReserved 保留字,為0
其中需要注意的問題是,RGBQUAD結(jié)構(gòu)中的顏色順序是BGR,而不是平常的RGB。
3、位圖數(shù)據(jù)
最后,在位圖文件頭、位圖信息頭、位圖顏色表之后,便是位圖的主體部分:位圖數(shù)據(jù)。根據(jù)不同的位圖,位圖數(shù)據(jù)所占據(jù)的字節(jié)數(shù)也是不同的,比如,對(duì)于8位位圖,每個(gè)字節(jié)代表了一個(gè)像素,對(duì)于16位位圖,每?jī)蓚€(gè)字節(jié)代表了一個(gè)像素,對(duì)于24位位圖,每三個(gè)字節(jié)代表了一個(gè)像素,對(duì)于32位位圖,每四個(gè)字節(jié)代表了一個(gè)像素。
(二)、存儲(chǔ)區(qū)域DC到位圖文件
認(rèn)識(shí)了位圖文件的結(jié)構(gòu)以后,對(duì)特定位圖文件進(jìn)行操作就顯得簡(jiǎn)單了。
我們通過創(chuàng)建特定的畫筆,刷子及位圖對(duì)象,在DC 環(huán)境下進(jìn)行繪圖后,就要將保存在DC 里的圖像存儲(chǔ)到位圖文件中,以便使用及輸出到其他媒體。下面代碼實(shí)現(xiàn)將設(shè)圖上下文圖形保存為位圖文件。
BOOL CImg::SaveDCBmp(HDC hDC, HBITMAP hBitmap, LPCTSTR lpFileName)
{
//當(dāng)前分辨率下每象素所占字節(jié)數(shù)
int iBits;
//位圖中每象素所占字節(jié)數(shù)
WORD wBitCount;
//定義調(diào)色板大小, 位圖中像素字節(jié)大小 ,位圖文件大小 , 寫入文件字節(jié)數(shù)
DWORD dwPaletteSize=0, dwBmBitsSize=0, dwDIBSize=0, dwWritten=0;
//位圖屬性結(jié)構(gòu)
BITMAP Bitmap;
//位圖文件頭結(jié)構(gòu)
BITMAPFILEHEADER bmfHdr;
//位圖信息頭結(jié)構(gòu)
BITMAPINFOHEADER bi;
//指向位圖信息頭結(jié)構(gòu)
LPBITMAPINFOHEADER lpbi;
//定義文件,分配內(nèi)存句柄,調(diào)色板句柄
HANDLE fh, hDib, hPal,hOldPal=NULL;
//計(jì)算位圖文件每個(gè)像素所占字節(jié)數(shù)
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;
//為位圖內(nèi)容分配內(nèi)存
hDib = GlobalAlloc(GHND,dwBmBitsSize + dwPaletteSize + sizeof(BITMAPINFOHEADER));
lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDib);
*lpbi = bi;
// 處理調(diào)色板
hPal = GetStockObject(DEFAULT_PALETTE);
if (hPal)
{
hOldPal = ::SelectPalette(hDC, (HPALETTE)hPal, FALSE);
}
// 獲取該調(diào)色板下新的像素值
GetDIBits(hDC, hBitmap, 0, (UINT) Bitmap.bmHeight, (LPSTR)lpbi + sizeof(BITMAPINFOHEADER)
+dwPaletteSize, (BITMAPINFO *)lpbi, DIB_RGB_COLORS);
//恢復(fù)調(diào)色板
if (hOldPal)
{
::SelectPalette(hDC, (HPALETTE)hOldPal, TRUE);
RealizePalette(hDC);
}
//創(chuàng)建位圖文件
fh = CreateFile(lpFileName, GENERIC_WRITE,0, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if (fh == INVALID_HANDLE_VALUE) return FALSE;
// 設(shè)置位圖文件頭
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);
// 寫入位圖文件其余內(nèi)容
WriteFile(fh, (LPSTR)lpbi, dwDIBSize, &dwWritten, NULL);
//清除
GlobalUnlock(hDib);
GlobalFree(hDib);
CloseHandle(fh);
return TRUE;
}
保存位圖文件前通過GetObject函數(shù)取得位圖長度, 通過GetDIBits取得位圖圖像掃描數(shù)據(jù),填充BITMAPFILEHEADER(位圖文件頭結(jié)構(gòu)); BITMAPINFOHEADER (位圖信息頭結(jié)構(gòu)); 然后
寫入位圖文件頭
WriteFile(fh, (LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER), &dwWritten, NULL);
寫入位圖文件其余內(nèi)容
WriteFile(fh, (LPSTR)lpbi, dwDIBSize, &dwWritten, NULL);
以 文件頭 + 位圖信息 + 位圖像素?cái)?shù)據(jù) 的順序進(jìn)行存儲(chǔ)。
三 COM組件接口設(shè)計(jì)
前面我們?cè)谳斎胛谋竞螅诔绦蛑袆?chuàng)建設(shè)備上下文,對(duì)輸入的文本進(jìn)行計(jì)算并輸出了指定文件名的位圖文件,在本設(shè)計(jì)中,我們使用了以JPEG壓縮格式存儲(chǔ)文件的方式以減小網(wǎng)絡(luò)傳輸時(shí)間,因jpeg壓縮方法的論述已超出本文范圍,故在此不再贅述。
為了讓其他語言調(diào)用此接口,我們以 COM 組件的方式發(fā)布此程序,可供VB,DELPHI,PB,ASP等程序調(diào)用,下面給出COM組件的設(shè)計(jì)方法,一般COM組件的創(chuàng)建及編譯超出本文范圍,故不再作解釋。
在組件中清加方法
STDMETHOD(OutTextImg)(/*[out, retval]*/ long *pVal);ltvalue(500)] long lWeight, [in,optional,defaultvalue(0)] long l3D);
和
STDMETHOD(OutImg)(BSTR bstrFileName, long lDelFile);
分別實(shí)現(xiàn)處理文件本保存為圖像及把圖像輸出到用戶瀏覽器。
實(shí)現(xiàn)代碼如下:
STDMETHODIMP CAspImage::OutImgFromText(BSTR bstrFilePath,
BSTR bstrText,
BSTR bstrBgImg,
long lCSet,
BSTR bstrFont,
long lWidth,
long lHeight,
long lLeft,
long lTop,
long llfHeight,
long lWeight,
long l3D)
{
CImg img;
try{
if(0 == img.OutImgFromText(
bstrFilePath,
bstrText,
bstrBgImg,
lCSet,
bstrFont,
lWidth,
lHeight,
lLeft,
lTop,
llfHeight,
lWeight,
l3D))
{
return S_OK;
}
else
{
return S_FALSE;
}
}
catch(...)
{
return S_FALSE;
}
return S_OK;
/**/
}
一些處理代碼我們封裝在了Cimg類中,在前面做過介紹,在這里只是簡(jiǎn)單調(diào)用即可。
STDMETHODIMP CAspImage::OutTextImg(long *pVal)
{
HRESULT hr = OutImgFromText(bstrFilePath,
bstrText,
bstrBgImg,
lCSet,
bstrFont,
lWidth,
lHeight,
lLeft,
lTop,
llfHeight,
lWeight,
l3D);
if(SUCCEEDED(hr))
*pVal = 0;
else
*pVal = -1;
return S_OK;
}
OutTextImg 函數(shù)只簡(jiǎn)單調(diào)用OutImgFromText 接口。
STDMETHODIMP CAspImage::OutImg(BSTR bstrFileName, long lDelFile)
{
// TODO: Add your implementation code here
_variant_t vReturnBuffer;
LPSAFEARRAY psaFile;
HANDLE hFile;
DWORD dwSizeOfFile;
DWORD dwNumberOfBytesRead;
BOOL bResult;
unsigned char *pReturnBuffer = NULL;
long k;
HRESULT hr = S_OK;
// Create file in this case only OPENS an existing file (or fails
// if the file does not exist!)
hFile = ::CreateFile(
bstrFileName, // name of the file
GENERIC_READ, // desired access
FILE_SHARE_READ, // shared access
NULL, // security attributes
OPEN_EXISTING, // creation disposition - open only if existing!
FILE_FLAG_SEQUENTIAL_SCAN, // flag attributes
NULL );
if( hFile == INVALID_HANDLE_VALUE )
{
return E_FAIL;
}
dwSizeOfFile = ::GetFileSize( hFile, NULL );
if (dwSizeOfFile == 0xFFFFFFFF)
{
return E_FAIL;
}
pReturnBuffer = new unsigned char[dwSizeOfFile];
// Get the binary content of the file
bResult = ::ReadFile( hFile, pReturnBuffer, dwSizeOfFile, &dwNumberOfBytesRead, NULL );
if( FALSE == bResult )
{
return E_FAIL;
}
psaFile = ::SafeArrayCreateVector( VT_UI1 , 0, dwSizeOfFile );
if( !psaFile )
{
return E_FAIL;
}
// Fill in the SAFEARRAY with the binary content of the file
for( k = 0; k < (int) dwSizeOfFile; k++ )
{
if( FAILED(::SafeArrayPutElement( psaFile, &k, &pReturnBuffer[k] )) )
{
return E_FAIL;
}
}
vReturnBuffer.vt = VT_ARRAY VT_UI1;
V_ARRAY(&vReturnBuffer) = psaFile;
m_piResponse->BinaryWrite(vReturnBuffer);
if( pReturnBuffer )
delete [] pReturnBuffer;
//_variant_t vOut("OutImg TEST....................");
//m_piResponse->Write(vOut);
::CloseHandle(hFile);
if(lDelFile != 0)
::DeleteFile(bstrFileName);
return SUCCEEDED(hr) ? S_OK : E_FAIL;
return S_OK;
}
此接口我們使用m_piResponse->BinaryWrite(vReturnBuffer);將讀入內(nèi)存的圖像數(shù)據(jù)轉(zhuǎn)發(fā)給用戶瀏覽器。
另外,為了靈活地改變圖像字體,大小,字符集及圖像長寬等,我們要為組件添加以下屬性。
STDMETHOD(get_bAutoHeighten)(/*[out, retval]*/ BOOL *pVal);
STDMETHOD(put_bAutoHeighten)(/*[in]*/ BOOL newVal);
STDMETHOD(get_l3D)(/*[out, retval]*/ long *pVal);
STDMETHOD(put_l3D)(/*[in]*/ long newVal);
STDMETHOD(get_lWeight)(/*[out, retval]*/ long *pVal);
STDMETHOD(put_lWeight)(/*[in]*/ long newVal);
STDMETHOD(get_lTop)(/*[out, retval]*/ long *pVal);
STDMETHOD(put_lTop)(/*[in]*/ long newVal);
STDMETHOD(get_lLeft)(/*[out, retval]*/ long *pVal);
STDMETHOD(put_lLeft)(/*[in]*/ long newVal);
STDMETHOD(get_lCSet)(/*[out, retval]*/ long *pVal);
STDMETHOD(put_lCSet)(/*[in]*/ long newVal);
STDMETHOD(put_bstrBgImg)(/*[in]*/ BSTR newVal);
STDMETHOD(put_bstrFilePath)(/*[in]*/ BSTR newVal);
STDMETHOD(put_bstrFont)(/*[in]*/ BSTR newVal);
STDMETHOD(put_bstrText)(/*[in]*/ BSTR newVal);
STDMETHOD(get_llfHeight)(/*[out, retval]*/ long *pVal);
STDMETHOD(put_llfHeight)(/*[in]*/ long newVal);
STDMETHOD(get_lHeight)(/*[out, retval]*/ long *pVal);
STDMETHOD(put_lHeight)(/*[in]*/ long newVal);
STDMETHOD(get_lWidth)(/*[out, retval]*/ long *pVal);
STDMETHOD(put_lWidth)(/*[in]*/ long newVal);
分別實(shí)現(xiàn)自定義圖象長,寬,字體大小,字體名稱等屬性。如:
設(shè)置圖像文本
STDMETHODIMP CAspImage::put_bstrText(BSTR newVal)
{
bstrText = newVal;
return S_OK;
}
設(shè)置圖像高度
STDMETHODIMP CAspImage::put_lHeight(long newVal)
{
lHeight = newVal;
return S_OK;
}
四 ASP程序使用此組件輸出圖像到用戶瀏覽器
在使用之前首先在服務(wù)器上注冊(cè)此組件,方法:
拷貝XTAspImage.dll 到系統(tǒng)目錄,一般為C:\WINNT\SYSTEM32
運(yùn)行-> regsvr32 XTAspImage.dll
如果安裝成功,會(huì)有成功提示。此過程只使用一次。
下面是在asp里調(diào)用方法
1. <!--#include file="Config/Function.asp"-->
2. <!--#include file="Config/SiteInfo.asp"-->
3. <!--#include file="Config/DbConn.asp"-->
4. <%
a) Dim TeachID, PageTextLen, Page, SumPage, BodyLen, TemplateBody, Width, Height, FHeight, sEndStr
b) TeachID = INT(Request("TeachID"))
c) PageTextLen = INT(Request("PageTextLen"))
d) IF PageTextLen <= 0 THEN
i. PageTextLen = 300
e) END IF
f) Page = INT(Request("Page"))
g) Set Rs = Server.CreateObject("ADODB.Recordset")
h) Sql="select * from Article where id=" & TeachID
i) Rs.open sql,conn,1,1
j) IF NOT Rs.EOF THEN
i. TeachingBody = Rs("Content") & constEndStr
k) ELSE
i. Response.Write("記錄不存在")
ii. Rs.Close
iii. Set Rs = Nothing
iv. Conn.Close
v. Set Conn = Nothing
vi. Response.End
l) END IF
m) BodyLen = len(TeachingBody)
n) SumPage = GetMaxPageNum(BodyLen, PageTextLen)
o) Dim sPageText
p) IF Page >= SumPage THEN
i. Page = SumPage
q) END IF
r) IF Page <= 0 THEN
i. Page = 1
s) END IF
t) sPageText = mid(TeachingBody, (Page-1) * PageTextLen + 1, PageTextLen)
u) Dim sFont
v) sFont = Request("FontFace")
w) Dim FileName
x) FileName = GetTempFileName(Server.MapPath("tmp"), "XTImg_", "jpg")
y) On Error Resume Next
z) Set Obj = Server.CreateObject("XTAspImage.AspImage")
aa) Response.Clear
bb) If Err.Number <> 0 Then
i. Response.Write "請(qǐng)先在服務(wù)器安裝信天ASPIMAGE組件!"
ii. Response.End
cc) End If
dd) Obj.bstrFilePath = FileName
ee) Obj.lHeight = INT(Request("Height"))
ff) Obj.lWidth = INT(Request("Width"))
gg) Obj.bstrFont = sFont
hh) Obj.lLeft = INT(Request("ImgLeft"))
ii) Obj.lTop = INT(Request("ImgTop"))
jj) Obj.llfHeight = INT(Request("llfHeight"))
kk) Obj.lWeight = INT(Request("Weight"))
ll) Obj.l3D = INT(Request("l3D"))
mm) Obj.lCSet = INT(Request("CSet"))
nn) Obj.bstrText = sPageText
oo) IF Obj.OutTextImg = 0 THEN
i. Dim lDelFile '是否刪除臨時(shí)文件,0為不刪除,非0為刪除
ii. lDelFile = 1
iii. ret = Obj.OutImg(FileName, lDelFile)
iv. 'Response.Write "輸出文件成功!"
pp) ELSE
i. Response.Write "輸出文件失敗!"
qq) END IF
rr) Set Obj = nothing
5. %>
6. <body>
7. </body>
8. </html>
1,2,3 行為包含一數(shù)據(jù)庫連接文件及網(wǎng)站配置信息
4.a 至 4.x 從通過傳入ID號(hào)從數(shù)據(jù)庫里讀取文本,并通過字?jǐn)?shù)計(jì)算輸出頁要輸出的文本并保存到sPageText里。
4.y 至 4.nn創(chuàng)建信天asp 圖像處理組件并設(shè)置輸出文件名,圖像長寬,字符集,字體等。
4.oo以后輸出文件及把圖像數(shù)據(jù)轉(zhuǎn)發(fā)給用戶瀏覽器。
在普通網(wǎng)頁里的調(diào)用方法為:
<img src="outteachimg.asp?TeachID=67&PageTextLen=500&Height=300&Width=600&Page=1&FontFace=%BB%AA%CE%C4%D0%C2%CE%BA&l3D=0&FontColor=0&CSet=134&BGImgPath=&ImgLeft=10&ImgTop=20&ImgBottom=10&ImgRight=10&llfHeight=24&Weight=300" width="580" >
五 結(jié)束語
圖片處理組件在互聯(lián)網(wǎng)程序開發(fā)中使用很常見,例如我們注冊(cè)論壇會(huì)員或商城會(huì)員里,總會(huì)有提示輸入驗(yàn)證碼的提示,而此驗(yàn)證碼為了防軟件自動(dòng)識(shí)別,是以圖像數(shù)據(jù)輸出的。當(dāng)我們掌握了圖片處理組件開發(fā)方法時(shí),開發(fā)基于asp的圖片驗(yàn)證數(shù)字輸出及字符輸出將是輕而易舉。
參考資料:
MSDN,
www.vckbase.com,
www.vchelp.net
www.codeguru.com,
www.codeproject.com
附:
設(shè)計(jì)演示站點(diǎn):http://www.nwnu.net
代碼下載:http://www.nwnu.net/src/XTAspImage_to_vckbase.rar