作者:符文科 (龍飛)
發布時間: 2004-04 作者:符文科 西北師范大學2001級計算機成人專升本 E-Mail vc@hahame.net 聯系方式: 13359319378 0931-8553848 網站 http://www.ourcode.net
代碼下載:http://www.nwnu.net/src/XTAspImage_to_vckbase.rar
一 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);
以 文件頭 + 位圖信息 + 位圖像素數據 的順序進行存儲。 三 COM組件接口設計 前面我們在輸入文本后,在程序中創建設備上下文,對輸入的文本進行計算并輸出了指定文件名的位圖文件,在本設計中,我們使用了以JPEG壓縮格式存儲文件的方式以減小網絡傳輸時間,因jpeg壓縮方法的論述已超出本文范圍,故在此不再贅述。 為了讓其他語言調用此接口,我們以 COM 組件的方式發布此程序,可供VB,DELPHI,PB,ASP等程序調用,下面給出COM組件的設計方法,一般COM組件的創建及編譯超出本文范圍,故不再作解釋。 在組件中清加方法
STDMETHOD(OutTextImg)(/*[out, retval]*/ long *pVal);ltvalue(500)] long lWeight, [in,optional,defaultvalue(0)] long l3D);
和
STDMETHOD(OutImg)(BSTR bstrFileName, long lDelFile);
分別實現處理文件本保存為圖像及把圖像輸出到用戶瀏覽器。 實現代碼如下:
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類中,在前面做過介紹,在這里只是簡單調用即可。
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 函數只簡單調用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);將讀入內存的圖像數據轉發給用戶瀏覽器。
另外,為了靈活地改變圖像字體,大小,字符集及圖像長寬等,我們要為組件添加以下屬性。
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);
分別實現自定義圖象長,寬,字體大小,字體名稱等屬性。如: 設置圖像文本 STDMETHODIMP CAspImage::put_bstrText(BSTR newVal) { bstrText = newVal;
return S_OK; }
設置圖像高度 STDMETHODIMP CAspImage::put_lHeight(long newVal) { lHeight = newVal;
return S_OK; } 四 ASP程序使用此組件輸出圖像到用戶瀏覽器 在使用之前首先在服務器上注冊此組件,方法: 拷貝XTAspImage.dll 到系統目錄,一般為C:\WINNT\SYSTEM32 運行-> regsvr32 XTAspImage.dll 如果安裝成功,會有成功提示。此過程只使用一次。 下面是在asp里調用方法
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 "請先在服務器安裝信天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 '是否刪除臨時文件,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 行為包含一數據庫連接文件及網站配置信息 4.a 至 4.x 從通過傳入ID號從數據庫里讀取文本,并通過字數計算輸出頁要輸出的文本并保存到sPageText里。 4.y 至 4.nn創建信天asp 圖像處理組件并設置輸出文件名,圖像長寬,字符集,字體等。 4.oo以后輸出文件及把圖像數據轉發給用戶瀏覽器。
在普通網頁里的調用方法為: <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" >
五 結束語
圖片處理組件在互聯網程序開發中使用很常見,例如我們注冊論壇會員或商城會員里,總會有提示輸入驗證碼的提示,而此驗證碼為了防軟件自動識別,是以圖像數據輸出的。當我們掌握了圖片處理組件開發方法時,開發基于asp的圖片驗證數字輸出及字符輸出將是輕而易舉。
參考資料: MSDN, www.vckbase.com, www.vchelp.net www.codeguru.com, www.codeproject.com
附:
設計演示站點:http://www.nwnu.net
代碼下載:http://www.nwnu.net/src/XTAspImage_to_vckbase.rar
|