前幾天有朋友突然找我幫他想想如何用VC編程在圖片上繪字,並且能夠批量生成新的圖片。其實我對VC編程也不怎麼樣,很多東西都沒用過,大體的概念也就覺得應該可以用GDI編程,讀入圖片入內存,然後使用內存與設備無關的設備描述表作圖來實現,可是仔細翻 Windows程序設計 來看也沒發現可行的辦法,於是沒辦法只好上網上搜,結果發現有人提出過類似問題,網上的高手們的回答有用GDI+的,以前還真沒聽過這個庫。我就只得硬着頭皮上了。
一,建立GDI+的VC&VS開發環境
先下了這個庫的頭文件和庫文件,然後在VC工程配置添加庫和頭文件。具體的操作是這樣的:
VC6.0下面的操作:
在菜單項:Project->settings->Link->Object/Library Module裏面填入gdiplus.lib.這個靜態庫文件應該拷到工程的文件夾下,不然應該填入全整路徑。
在stdafx.h中我添加了如下代碼:
#ifndef ULONG_PTR
#define ULONG_PTR unsigned long*
#include "./GDIPlus/Includes/GdiPlus.h"
using namespace Gdiplus;
#include "./GDIPlus/Includes/GdiPlus.h"這兒是因爲我解壓的路徑在工程文件夾下。網上也有人把include文件夾內容直接拷到VC的安裝文件裏面的include裏面的。
VS2005下面的配置與上面略有不同。沒有定義宏ULONG_PTR。其餘也就是界面不一樣而已。
接下來,在工程應用程序類(C*App類)裏面添加成員變量 :
ULONG_PTR m_gdiplusToken;
重載CWinApp成員函數:
virtual int ExitInstance();
在C*App::InitInstance()添加語句裝載gdiplus
Gdiplus::GdiplusStartupInput gdiplusStartupInput;
Gdiplus::GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);
在C*App::ExitInstance()中缷載:
Gdiplus::GdiplusShutdown(m_gdiplusToken);
return CWinApp::ExitInstance();
如此即可以在View或Fram類裏面使用gdiplus相應的類了
二,如何在一張圖片(常見的幾種格式)上作圖
我在網上學到的方法大致如此:
首先定義一個Bitmap或Image的對象
如Image img(L"example.jpg");
然後由Image或Bitmap 的一個靜態函數FromImage();
得到一個Graphics 的對象指針。Graphics是一個有作圖接口的類,支持常見的如畫點,線,矩形,橢圓,字符串,填充等操作。顯然這兒作圖的所謂有的DC應該是內存DC,也就是圖片文件的數據區內存。所以做圖後img對象調用其保存函數
img.Save(....);後打開保存後的圖片,就能看見作圖的效果了。
另外,還有一個問題在於如何將一個小圖片複製到一張大圖片,或者說幾張圖片一起拼接成一大圖片。應該是網上的資源是挺豐富的,但是人應該是學以致用的。學會理解,活用,纔是在網上學習的最好方法吧。我對此問題的大致操作如下:
先建立一個大圖片的對象,並指定其寬高:Bitmap bigBmp(width,height);
獲取小圖片對象:Bitmap smallBmp(L"resource.jpg");
由上面總結的在圖片上繪圖的方法得到Graphics *並在smallBmp完成相應字符串等的繪製。
同樣的得到一個指向bigBmp的Graphics*,將完成做圖後的小圖片smallBmp畫到指定的位置就OK了。即:
Bitmap::FromImage(bigBmp)->DrawImage(&smallBmp,x,y);
三:關於Char* ,CString ,WCHAR*之間的轉換問題
GDI+所有類的接口函數如果要傳遞字符串作爲參數的話,似乎都用UNICODE串,即WCHAR*。我開始也被整得暈頭轉向,因爲窗口編程所用往往是CString,用IO流讀文件數據又得到char *。得益於網上牛人們的總結,我用到以下幾種基本方法去實現三者間的轉換:
char * 轉WCHAR *:
::MultiByteToWideChar(CP_ACP,0,(const char *)res,int count,char * dest,int count);
類似地,WCHAR *轉char *:
WideCharToMultiByte(CP_ACP, 0,.........);
CString 轉WCHAR *:
wchar_t * p=str.AllocSysStrinig()
也有A2W(str)的,但是要包括ATL轉換頭文件#include;
並且在A2W前使用USES_CONVERSION宏。
其它:
char*轉CString:
除了直接賦值外,還可使用CString::Format進行。
如char * p="sfdasf";
CString str=p; 或者str.Format("%s",p);
CString 轉char *
1.直接強制類型轉換:
CString ss="sfasf";
char *p=(LPSTR)(LPCSTR)ss;
2.CString::GetBuffer或LockBuffer
char * p=str.GetBuffer();
char * pt=str.LockBuffer();
WCHAR *轉CString
在網上沒有找到相關的文檔,想想應該是可以直接賦值的
但是試驗發現雖無編譯錯誤,但是用中文的時候卻生亂碼,用字母的時候卻是正常,想其中肯定沒有錯誤,只是用MessageBox顯示的時候亂碼應該有其它原因,比如說使用了雙字節字符集DBCS來顯示漢字(純屬猜測而已)。總體來說在Windows編程中:#define UNICODE
則CString .TCHAR,等均用的是UNICODE碼,一個字符佔兩個字節。