zoukankan      html  css  js  c++  java
  • 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里的文件就复制到VC98include文件夹里,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

  • 相关阅读:
    天下没有不会这么回事!不会就学——北漂18年(28)
    Python Module_sys/random
    Python Module_sys/random
    redis 主从切换
    第一章 数据引用与匿名存储
    第12章 对象上
    zabbix 发送邮件配置
    第10章 包 名字空间,变量和函数
    perl 类 对象 方法
    perl数据结构输出 Data::Dumper
  • 原文地址:https://www.cnblogs.com/findumars/p/5928685.html
Copyright © 2011-2022 走看看