大部分是參照其它資料,然后加以自己的理解,那是什么,總結。算不得什么教程。。。。。。。汗,自己看着就行了。。如果別人能看那就更好了。
首先下載GDI+文件包,一個動態鏈接庫,使用GDI+就是調用那個動態鏈接庫里的函數。類似畫圖什么的,了解這個主要是想把bmp圖片轉換成jpg的,然后做個簡單屏幕監控,幾個月前嘗試做了一下,差不多是半分鍾才傳過來一張圖片。知識有限,沒辦法,那時候,也沒怎么上心,就落下了。廢話就不多說了,先下載GDI+文件包。
GDI+文件包下載地址:www.codeguru.com/code/legacy/gdi/GDIPlus.zip
另附一個GDI+教程:http://ishare.iask.sina.com.cn/f/22577823.html (GDI+ SDK參考.chm)
解壓后,Includes里的文件就復制到VC98\include文件夾里,lib里的文件也一樣,復制到對應的lib文件夾里,那個gdiplus就復制到工程文件夾里,就跟使用平常的動態鏈接庫一樣。
先在控制台下來測試一下,新建一個控件台工程,代碼如下:
#include<windows.h>
#define ULONG_PTR ULONG
#include<gdiplus.h>//gdi+頭文件
using namespace Gdiplus;
#pragma comment(lib,"gdiplus.lib")
int main()
{
GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR pGdiToken;
GdiplusStartup(&pGdiToken,&gdiplusStartupInput,NULL);//初始化GDI+
HWND hWnd=::FindWindow(NULL,"無標題.txt - 記事本");
HDC hDC=::GetDC(hWnd);
Graphics graphics(hDC);
Pen newPen(Color(255,0,0),3);//畫筆,最后一個參數,畫筆大小
while(true)
{
graphics.DrawRectangle(&newPen,50,50,100,60);//畫一個矩形
Sleep(350);
}
//死循環,下面這句不會調用,只是想把那個意思表明
GdiplusShutdown(pGdiToken);//關閉GDI+
}
Color解釋
上面的例子中畫筆的顏色由Color(255,0,0)返回的值來確定,這個也就是顏色值,跟GDI中的RGB一樣,不過前者可以有四個參數,多出的一個參數用來表示什么呢?Alpha值,也就是透明度。0~255,0是完全透明。255是不透明,如果Color有四個參數的話,那個Alpha值就由第一個參數指定。看下面例子。
#include<windows.h>
#define ULONG_PTR ULONG
#include<gdiplus.h>
using namespace Gdiplus;
#pragma comment(lib,"gdiplus.lib")
int main()
{
GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR pGdiToken;
GdiplusStartup(&pGdiToken,&gdiplusStartupInput,NULL);//初始化GDI+
HWND hWnd=::FindWindow(NULL,"無標題.txt - 記事本");
HDC hDC=::GetDC(hWnd);
Graphics graphics(hDC);
SolidBrush newBrush(Color(40,0,0,255));
while(true)
{
graphics.FillRectangle(&newBrush,0,0,120,120);//重復畫
Sleep(2000);
}
//死循環,下面這句不會調用,只是想把那個意思表明。
GdiplusShutdown(pGdiToken);//關閉GDI+
return 0;
}
漸變畫刷
這里我就復制原文了,事實上對於幾個參數,我只有一個固定的了解。
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
由於在前面的示例中,對這種簡單的畫刷的使用已介紹過,因而這里着重討論漸變畫刷
的創建和使用。
GDI+提供了 LinearGradientBrush和 PathGradientBrush 類分別用來創建一個直線漸變和
路徑漸變畫刷。
直線漸變是指在一個矩形區域使用兩種顏色進行過渡(漸變),過渡方向可以是水平、垂
直以及對角線方向。LinearGradientBrush 構造函數的原型如下:
LinearGradientBrush(Point & point1, Point & point2,
Color & color1, Color & color2);
LinearGradientBrush(Rect & rect, Color & color1, Color & color2,
REAL angle, BOOL isAngleScalable);
LinearGradientBrush(Rect & rect, Color & color1, Color & color2,
LinearGradientMode mode);
其中, point1和point2分別用來指定矩形區域的左上角和右下角點坐標, color1和color2
分別用來指定漸變起始和終止的顏色。rect 用來指定一個矩形區域的大小和位置,angle 用
來指定漸變的方向角度,正值為順時針。isAngleScalable 是一個即將廢除的參數。mode
用來指定漸變的方法,它可以是 LinearGradientModeHorizontal(水平方向)、
LinearGradientModeVertical (垂直方向)、LinearGradientModeForwardDiagonal(從左下到
右上的對角線方向)和 LinearGradientModeBackwardDiagonal(從左上到右下的對角線方
向)。
需要說明的是,Point 和 Rect是GDI+新的數據類型,它們和 MFC的 CPoint 和 CRect
類的功能基本一樣,但它們相互之間不能混用。
路徑漸變畫刷是用漸變顏色來填充一個封閉的路徑。 一個路徑既可以由一系列的直線和
曲線構成,也可以由其它對象來構造。路徑漸變是一種中心顏色漸變模式,它從路徑的中心
點向四周進行顏色漸變。PathGradientBrush 構造函數的原型如下:
PathGradientBrush(const GraphicsPath* path);
PathGradientBrush(const Point * points, INT count, WrapMode wrapMode);
其中,path用來指定一個路徑指針,points 和 count 分別用來指定組成路徑的一系列
直線端點的數組及其大小,wrapMode 是一個可選項,用來指定填充的包圍模式。一個包圍
模式用來決定是否在區域內部、在區域外部以及所有區域都填充。默認時,其值為
WrapModeClamp,即在區域內部填充。
下面的代碼說明了上述兩種漸變畫刷的使用方法:
Graphics graphics( pDC->m_hDC );
GraphicsPath path; // 構造一個路徑
path.AddEllipse(50, 50, 200, 100);
// 使用路徑構造一個畫刷
PathGradientBrush pthGrBrush(&path);
// 將路徑中心顏色設為藍色
pthGrBrush.SetCenterColor(Color(255, 0, 0, 255));
// 設置路徑周圍的顏色為藍芭,但alpha 值為0
Color colors[] = {Color(0, 0, 0, 255)};
INT count = 1;
pthGrBrush.SetSurroundColors(colors, &count);
graphics.FillRectangle(&pthGrBrush, 50, 50, 200, 100);
LinearGradientBrush linGrBrush(
Point(300, 50),
Point(500, 150),
Color(255, 255, 0, 0), // 紅色
Color(255, 0, 0, 255)); // 藍色
graphics.FillRectangle(&linGrBrush, 300, 50, 200, 100);
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
反鋸齒
不管是畫圓,還是直線,線條給人的感覺很粗糙,不怎么平滑,怎么解決呢,對了,就像標題說的那樣,反鋸齒,其實就是函數的調用。
Graphics類的SetSmoothingMode函數可以設置,根據函數字面上的意思,就是設置平滑模式。這里我舉一個例子,關於這個函數的可選參數,自己可以到網上找找。
例子:(對比兩條線有什么區別)單文檔程序 OnDraw函數代碼如下:
void CShowView::OnDraw(CDC* pDC)
{
Graphics graphics( pDC->m_hDC );
Pen myPen(Color(255,0,0,0),1);
graphics.SetSmoothingMode(SmoothingModeHighSpeed);//要速度不要質量
graphics.DrawLine(&myPen,0,0,50,200);
//還有一個參數SmoothingModeAntiAlias,估計是折中的意思。速度也要,質量也不能落下。
graphics.SetSmoothingMode(SmoothingModeHighQuality);//高質量
graphics.DrawLine(&myPen, 50, 0 ,130,200);
// TODO: add draw code for native data here
}
效果如下圖:
文字也可以反鋸齒Graphics類里的SetTextRenderingHint函數可以做到,具體用法,參考百度吧。。。
顯示圖片(直接從教程上復制的)
用Image類可以做到,可識別的圖片有gif,bmp,jpg,png等。先說一下幾種加載圖片的方式,通過構造函數。如:
Image img(L"d:\\test.jpg");//定義時加載。
還有一種是通過FromFile函數。如:
Image *pImg=Image::FromFile(L"d:\\abc.bmp");
Graphics類里的DrawImage可以繪制圖片,兩個常用DrawImage重載函數:
Status DrawImage( Image* image, INT x, INT y);
Status DrawImage( Image* image, const Rect& rect);
DrawImage有幾個重載函數,這里不列出它們的區別了,有興趣可以自己去看一下,或者其它的。如旋轉圖片。。。。。
格式轉換
獲取圖片的CLSID采用了一個自定義函數GetEncoderClsid,這個函數是我從網上找的,具體怎么實現的有興趣的朋友可以去了解,反正我只是把它復制過來直接使用了,沒看過代碼。。
圖片格式轉換代碼如下,假設D盤有一個名為abc的位圖,把它轉換為JPEG文件。。
#include<windows.h>
#define ULONG_PTR ULONG
#include<gdiplus.h>
using namespace Gdiplus;
#pragma comment(lib,"gdiplus.lib")
//獲取圖片格式CLSID的自定義函數
int GetEncoderClsid(const WCHAR* format, CLSID* pClsid);
int main()
{
GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR pGdiToken;
GdiplusStartup(&pGdiToken,&gdiplusStartupInput,NULL);//初始GDI+
Image image(L"d:\\abc.bmp");//加載圖片
CLSID encoderClsid;
GetEncoderClsid(L"image/jpeg",&encoderClsid);
image.Save(L"d:\\Jpegabc.jpg",&encoderClsid);
//如果不注釋掉下面的語句,就會出錯,之前也有過錯誤,代碼沒任何錯誤,但運行的時候,不知道怎么,內存不可讀取
//上次是加載圖片的時候,就會出現這個錯誤,這些未知錯誤,只能重建個工程,把代碼再打一遍,看還有問題么
//問題依舊,不過卻是出現在程序結束的時候,我想問題會不會出現在GdiplusShutdown這個函數上,這個函數釋放掉內存,可能系統並沒有
//發現,等程序結束的時候,不是會自動清理沒有釋放掉的內存么,那么就會起沖突,然后我把這這個函數的調用注釋掉,問題果然沒有了
//但也不知道我的猜想對不對,我想最大的問題可能出現在編譯器上。。。。
//GdiplusShutdown(pGdiToken);//關閉GDI+
}
int GetEncoderClsid(const WCHAR* format, CLSID* pClsid)
{
UINT num= 0;
UINT size= 0;
ImageCodecInfo* pImageCodecInfo= NULL;
GetImageEncodersSize(&num, &size);
if(size== 0)
{
return -1;
}
pImageCodecInfo= (ImageCodecInfo*)(malloc(size));
if(pImageCodecInfo== NULL)
{
return -1;
}
GetImageEncoders(num, size, pImageCodecInfo);
for(UINT j=0; j< num; ++j)
{
if(wcscmp(pImageCodecInfo[j].MimeType, format)== 0)
{
*pClsid= pImageCodecInfo[j].Clsid;
free(pImageCodecInfo);
return j;
}
}
free(pImageCodecInfo);
return -1;
}
在內存中轉換圖片格式
//了解下面這個例子,就可以通過GDI+實現把bmp圖片轉換JPEG格式(在內存中),然后通過網絡發送到另一端,
//另一端接收再顯示,
//大概步驟是,先用Image加載圖片,然后創建流,通過Image類的Save函數以JPEG格式把圖片數據保存到
//流中,之后讀取數據,再用Image類的FromStream從流中加載(還原)
#include<windows.h>
#define ULONG_PTR ULONG
#include<gdiplus.h>
using namespace Gdiplus;
#pragma comment(lib,"gdiplus.lib")
//獲取圖片格式CLSID的自定義函數
int GetEncoderClsid(const WCHAR* format, CLSID* pClsid);
int main()
{
GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR pGdiToken;
GdiplusStartup(&pGdiToken,&gdiplusStartupInput,NULL);//初始GDI+
Image image(L"d:\\abc.bmp");//加載圖片
CLSID encoderClsid;
//獲取JPEG圖片格式CLSID
GetEncoderClsid(L"image/jpeg",&encoderClsid);
//創建流
IStream *pStream;
CreateStreamOnHGlobal(NULL,TRUE,&pStream);
//以JPEG圖片格式儲存數據到流中
image.Save(pStream,&encoderClsid);
//獲得與流對應的內存句柄
HGLOBAL hMem;
GetHGlobalFromStream(pStream,&hMem);
//獲得內存塊大小
DWORD dwSize=GlobalSize(hMem);
//再創建一塊內存句柄,用於目標流
HGLOBAL hDesMem=GlobalAlloc(GMEM_MOVEABLE,dwSize);
IStream *pDesStream;
CreateStreamOnHGlobal(hDesMem,TRUE,&pDesStream);
//獲得內存塊首地址
BYTE *pImgData=(BYTE *)GlobalLock(hMem);
BYTE *pDesData=(BYTE *)GlobalLock(hDesMem);
//復制內存,如果通過網絡,就把pImgData里的數據發送過去。
CopyMemory(pDesData,pImgData,dwSize);
::GlobalUnlock(hMem);
GlobalUnlock(hDesMem);
Image *pImg=Image::FromStream(pDesStream);
HWND hWnd=FindWindow(NULL,"無標題.txt - 記事本");
HDC hDC=GetDC(hWnd);
Graphics graphics(hDC);
while(TRUE)
{
//繪制圖片,測試是否正確
graphics.DrawImage(pImg,0,0,300,300);
Sleep(500);
}
//GdiplusShutdown(pGdiToken);//關閉GDI+
}
int GetEncoderClsid(const WCHAR* format, CLSID* pClsid)
{
UINT num= 0;
UINT size= 0;
ImageCodecInfo* pImageCodecInfo= NULL;
GetImageEncodersSize(&num, &size);
if(size== 0)
{
return -1;
}
pImageCodecInfo= (ImageCodecInfo*)(malloc(size));
if(pImageCodecInfo== NULL)
{
return -1;
}
GetImageEncoders(num, size, pImageCodecInfo);
for(UINT j=0; j< num; ++j)
{
if(wcscmp(pImageCodecInfo[j].MimeType, format)== 0)
{
*pClsid= pImageCodecInfo[j].Clsid;
free(pImageCodecInfo);
return j;
}
}
free(pImageCodecInfo);
return -1;
}
//通過HBITMAP加載圖片,Bitmap類可以做到,而Bitmap類是從Image派生出來的,那么Image類里的函數,它都可以使用。
//為什么提到從HBITMAP加載函數呢,看VC API常用函數第八十八和第八十九個函數,屏幕截圖。那里面是以HBITMAP形式
//保存屏幕圖片的。而我前面說過了,打算做一個簡單的屏幕監控。雖然不知道最終效果怎么樣,但我想,應該比上次要好,
//希望是我想象的那樣。直接看代碼了,(我相信有了上面的基礎)有什么比直接看代碼讓人明白的呢,況且只有幾句。。
#include<windows.h>
#define ULONG_PTR ULONG
#include<gdiplus.h>
using namespace Gdiplus;
#pragma comment(lib,"gdiplus.lib")
int main()
{
GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR pGdiToken;
GdiplusStartup(&pGdiToken,&gdiplusStartupInput,NULL);//初始GDI+
//加載圖片
HBITMAP hBmp=(HBITMAP)LoadImage(NULL,"d:\\abc.bmp",IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
Bitmap bmp(hBmp,NULL);//還可通過FromHBITMAP函數
HWND hWnd=FindWindow(NULL,"無標題.txt - 記事本");
HDC hDC=GetDC(hWnd);
Graphics graphics(hDC);
while(TRUE)
{
graphics.DrawImage(&bmp,10,10);
Sleep(500);
}
//GdiplusShutdown(pGdiToken);//關閉GDI+
}
參考鏈接:點擊打開鏈接
http://blog.csdn.net/dingxz105090/article/details/41476645