Gdi+实用入门
大部分是参照其它资料,然后加以自己的理解,那是什么,总结。算不得什么教程。。。。。。。汗,自己看着就行了。。如果别人能看那就更好了。
首先下载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
Gdi+实用入门的更多相关文章
- JsRender实用入门教程
这篇文章主要介绍了JsRender实用入门实例,包含了tag else使用.循环嵌套访问父级数据等知识点,并提供了完整的实例下载,非常具有实用价值,需要的朋友可以参考下 本文是一篇JsRend ...
- GDI+_入门教程【一】
GDI For VisualBasic6.0 [一]文件下载:GDI+ For VB6[一] 简单绘图实例演示百度网盘 1 '以下为作者[vIsiaswx]的教程 '(该教程发布的原地址已无法访问,此 ...
- PM2实用入门指南
简介 PM2是node进程管理工具,可以利用它来简化很多node应用管理的繁琐任务,如性能监控.自动重启.负载均衡等,而且使用非常简单. 下面就对PM2进行入门性的介绍,基本涵盖了PM2的常用的功能和 ...
- Koa2实用入门
koa2已发布了一段时间,可以考虑入手,参见Node.js最新Web技术栈(2016年4月) 本文主要是koa 2的文档解读和runkoa介绍,让大家对koa 2有一个更简单直接的理解 一.依赖Nod ...
- 15 道 Spring Boot 高频面试题,看完直接当面霸【入门实用】
前言 本文转自松哥(网名:江南一点雨)的一篇实用入门文章,写的挺好的,希望对各位有所帮助. 什么是面霸?就是在面试中,神挡杀神佛挡杀佛,见招拆招,面到面试官自惭形秽自叹不如!松哥希望本文能成为你面霸路 ...
- Photoshop入门教程(一):文本新建与概念解析
写在开头 <Photoshop实用入门>系列教程可能对于一点都没有接触过Photoshop的人来说不太容易接受,因为本教程并没有细致到教你如何使用画笔工具等一系列很基础的东西,有些地方的讲 ...
- 【Linux】-NO.87.Assembly.1.滴水逆向.1.001-【介绍】-
1.0.0 Summary Tittle:[Linux]-NO.87.Assembly.1.滴水逆向.1.001-[基础]- Style:Java Series:Log4j Since:2017-04 ...
- windows下VC界面 DIY系列1----写给想要写界面的C++程序猿的话
非常早就想写关于C++ UI开发的一系列博文,博客专栏刚审核通过,就立即開始刷博文,不能辜负自己的一番热血,我并非写界面的高手,仅仅想通过写博文提高我自己的技术积累,也顺便帮助大家解决界面开发的瓶颈. ...
- Yapi部署说明
1.环境搭建 确保 node 版本=> 7.6,请运行 node -v 查看版本号 确保 mongodb 版本 => 2.6,请运行 mongo --version 查看版本号 确保安装了 ...
随机推荐
- C# 自定义排序
/// <summary> /// 实体 /// </summary> public class Product { public int ID { get; set; } p ...
- Solr4.8.1与Tomcat7整合
Solr4.8.1和Tomcat7都可以到官方网站去下载,我这里就不多说了,如下图. 这里我们首先解压Solr-4.8.1.zip,再解压Tomcat,解压后,再在当前文件夹下建2个文件夹,一个用来放 ...
- 经历:sybase的sql查询,当传递的参数中包含全角空格(\u00a0),查询慢
今天,我遇到了一个sybase数据库查询的问题.一句简单的sql,但是不知道为什么查询不出来,导致生产生产服务器频频挂掉.吓得我的小心脏砰砰啊. select DISTINCT A.FCIL_CDE ...
- oracle linux下oracle 10g启动EM、isqlplus及相关命令语法
转载:http://hancang2000.blog.sohu.com/139239421.html ORACLE_HOME/bin/emctl start dbconsole $ORACLE_HOM ...
- Emgu CV的一个异常的解决方法
今年组里有大项目落我头上了,并不能像去年一样回家还能搞搞Cocos2dX,一把老泪流了下来... 回到正题,由于组里需要做一个显示板的自动测试项目,涉及到Computer Vision.不得不说,这才 ...
- vi 或 vim 常用命令(简单够用了)
1.vi filename :打开或新建文件,并将光标置于第一行首 2.按下i键:编辑或插入数据3.按下shit+: ->表示可以进行命令输入 4.q! ->表示不保存退出.5.w -&g ...
- 淘宝可以传照片搜索商品,verygood.雅客VC多味水果糖
奶奶喜欢吃点硬糖.在当地买了些说是不好.到是一个亲戚买的一种糖比较满意(好久了都快融化了). 但是我只有照片,能知道品牌,在jd没这样一样的商品了. 还好借助淘宝的传照片功能,找到了.
- ASP.NET设计模式(一)、适配器模式、依赖注入依赖倒置、空对象模式
鸟随凤鸾,人伴贤良,得以共之,我之幸也.说的是鸟随着鸾凤可以飞的更高远,人和比自己境界高的相处,自己也会得到熏染进步. 一.概述 分享出来简单的心得,望探讨 依赖倒置 依赖注入 Adapter模式 N ...
- 疯狂学习java web
因工作需要,疯狂学习java web,只是这么多年一直从事C++开发,突然之间要接手同事的那么一大堆代码,真有无从下手的感觉,首先是要学习html,然后是js, 然后是jsp,当然还有各种框架,想想就 ...
- 【实习记】2014-09-01从复杂到简单:一行命令区间查重+长整型在awk中的bug
9月1号,导出sql文件后,想到了awk,但很复杂.想到了用sed前期处理+python排序比较的区间查重法.编写加调试用了约3小时. 9月2号,编写C代码的sql语句过程中,发现排序可以交m ...