title author date CreateTime categories
WPF 使用 Direct2D1 画图 绘制基本图形
lindexi
2018-08-10 19:16:53 +0800
2018-04-19 09:41:10 +0800
WPF D2D DirectX 渲染

本文来告诉大家如何在 Direct2D1 绘制基本图形,包括线段、矩形、椭圆

本文是一个系列

本文的组织参考Direct2D,对大神表示感谢。

在开始前先告诉大家为何需要使用 Direct2D ,虽然 WPF 也是基于 DX 进行渲染,但是 WPF 做了很多兼容处理,所以没有比直接使用 Direct2D 的性能高。经过测试,在使用下面的所有代码,占用 CPU 几乎都是 0% ,因为没有布局、透明和事件处理,所以速度是很快。

在 Direct2D 使用的 点是 Point2F ,传入的是两个 float ,和 Point 差不多。

Point2F 也是一个结构体,所以和 Point 类型差不多

线段

线段需要使用 DrawLine ,方法的签名

    public void DrawLine(Point2F firstPoint 起始点 , Point2F secondPoint 终点, Brush brush 笔刷, float strokeWidth 线段宽度)

 public unsafe void DrawLine(Point2F firstPoint, Point2F secondPoint, Brush brush, float strokeWidth, StrokeStyle strokeStyle 线段样式)

所以使用下面的方法就可以在 (10,10) (100,10) 画出一条宽度为 2 的红线

            _renderTarget.DrawLine(new D2D.Point2F(10, 10), new D2D.Point2F(100, 10),
_renderTarget.CreateSolidColorBrush(new D2D.ColorF(1, 0, 0, 1)), 2);

上面的代码运行在WPF 使用 Direct2D1 画图入门文章的 OnRendering 方法,为了让大家也可以试试下面的代码,建议大家先去看这篇博客。

关于笔刷会在后面说

StrokeStyle

可以看到上面线段的最后一个参数是 StrokeStyle 那么这个参数是如何创建?在 Direct2D 有很多类都不能直接直接创建需要使用 D2DFactory 或 RenderTarget 才能创建。StrokeStyle 就需要使用 D2DFactory 进行创建。

创建 StrokeStyle 需要参数 StrokeStyleProperties,这个类的构造有两个重载,一个是不需要参数,另一个是需要很多参数。代码请看下面。

public StrokeStyleProperties(CapStyle startCap, CapStyle endCap, CapStyle dashCap, LineJoin lineJoin, float miterLimit, DashStyle dashStyle, float dashOffset)

从代码的命名大概大家也可以知道 StrokeStyleProperties 参数的意思,下面先创建一个没有构造函数的来创建 StrokeStyle ,请看下面代码

            var strokeStyleProperties = new D2D.StrokeStyleProperties();

            var strokeStyle = d2DFactory.CreateStrokeStyle(strokeStyleProperties);

            _renderTarget.BeginDraw();

            _renderTarget.DrawLine(new D2D.Point2F(10,10),new D2D.Point2F(100,10), _renderTarget.CreateSolidColorBrush(new D2D.ColorF(1, 0, 0, 1)),2, strokeStyle);

            _renderTarget.EndDraw();

需要注意,创建 strokeStyle 的工厂需要和创建 RenderTarget 一样,如果使用不一样的工厂就会出现下面异常。

Microsoft.WindowsAPICodePack.DirectX.Direct2D1.Direct2DException:“EndDraw has failed with error: 一起使用的对象必须创建自相同的工厂实例。 (异常来自 HRESULT:0x88990012) Tags=(0,0).”

所以需要修改WPF 使用 Direct2D1 画图入门文章的代码,把 D2DFactory 写为字段

   public MainWindow()
{
InitializeComponent(); CompositionTarget.Rendering += OnRendering; Loaded += (s, e) =>
{
var d2DFactory = D2D.D2DFactory.CreateFactory(D2D.D2DFactoryType.Multithreaded); var windowHandle = new WindowInteropHelper(this).Handle;
var renderTarget = d2DFactory.CreateHwndRenderTarget(new D2D.RenderTargetProperties(),
new D2D.HwndRenderTargetProperties(windowHandle,
new D2D.SizeU((uint) ActualWidth, (uint) ActualHeight),
D2D.PresentOptions.RetainContents)); _redBrush = renderTarget.CreateSolidColorBrush(new D2D.ColorF(1, 0, 0, 1)); _greenBrush = renderTarget.CreateSolidColorBrush(new D2D.ColorF(0, 1, 0, 1)); _blueBrush = renderTarget.CreateSolidColorBrush(new D2D.ColorF(0, 0, 1, 1)); _renderTarget = renderTarget; _d2DFactory = d2DFactory;
};
}

StrokeStyleProperties

关于 StrokeStyleProperties 需要说一下,就是各个参数。

从名字可以看到 StartCap 和 EndCap 就是线段的两端的图形,可以选的参数

  • Flat
  • Square
  • Round
  • Triangle

具体表示是什么,我会使用下面的例子

Flat

平的

            var strokeStyleProperties = new D2D.StrokeStyleProperties();

            strokeStyleProperties.StartCap = D2D.CapStyle.Flat;
strokeStyleProperties.EndCap = D2D.CapStyle.Flat; var strokeStyle = _d2DFactory.CreateStrokeStyle(strokeStyleProperties); _renderTarget.BeginDraw(); _renderTarget.DrawLine(new D2D.Point2F(10,10),new D2D.Point2F(100,10), _renderTarget.CreateSolidColorBrush(new D2D.ColorF(1, 0, 0, 1)),2, strokeStyle); _renderTarget.EndDraw();

Round

圆的

       float h = 10;

            strokeStyleProperties.StartCap = D2D.CapStyle.Round;
strokeStyleProperties.EndCap = D2D.CapStyle.Round;
strokeStyle = _d2DFactory.CreateStrokeStyle(strokeStyleProperties); h += 20; _renderTarget.BeginDraw(); _renderTarget.DrawLine(new D2D.Point2F(10, h), new D2D.Point2F(100, h), _renderTarget.CreateSolidColorBrush(new D2D.ColorF(1, 0, 0, 1)), 5, strokeStyle); _renderTarget.EndDraw();

Square

方形

  strokeStyleProperties.StartCap = D2D.CapStyle.Square;
strokeStyleProperties.EndCap = D2D.CapStyle.Square;
strokeStyle = _d2DFactory.CreateStrokeStyle(strokeStyleProperties); h += 20; _renderTarget.BeginDraw(); _renderTarget.DrawLine(new D2D.Point2F(10, h), new D2D.Point2F(100, h), _renderTarget.CreateSolidColorBrush(new D2D.ColorF(1, 0, 0, 1)), 5, strokeStyle); _renderTarget.EndDraw();

Triangle

三角形

            strokeStyleProperties.StartCap = D2D.CapStyle.Triangle;
strokeStyleProperties.EndCap = D2D.CapStyle.Triangle;
strokeStyle = _d2DFactory.CreateStrokeStyle(strokeStyleProperties); h += 20; _renderTarget.BeginDraw(); _renderTarget.DrawLine(new D2D.Point2F(10, h), new D2D.Point2F(100, h), _renderTarget.CreateSolidColorBrush(new D2D.ColorF(1, 0, 0, 1)), 5, strokeStyle); _renderTarget.EndDraw();

DashStyle

如果需要画虚线就可以使用 DashStyle ,虚线显示就是使用 CapStyle

            strokeStyleProperties.DashStyle = D2D.DashStyle.DashDot;
strokeStyleProperties.DashCap = D2D.CapStyle.Square;
strokeStyleProperties.DashOffset = 2; h += 20; strokeStyle = _d2DFactory.CreateStrokeStyle(strokeStyleProperties); _renderTarget.BeginDraw(); _renderTarget.DrawLine(new D2D.Point2F(10, h), new D2D.Point2F(100, h),
_renderTarget.CreateSolidColorBrush(new D2D.ColorF(1, 0, 0, 1)), 5, strokeStyle); _renderTarget.EndDraw();

大家自己试一试就知道

里面还有属性 LineJoin 这个不是线段可以做的,是折线才可以使用,表示两个线段如何链接

矩形

画矩形使用 DrawRectangle ,参数需要传入 RectF 需要传入上下左右的浮点数。

            _renderTarget.DrawRectangle(new D2D.RectF(10, 10, 100, 100), brush, 10);

矩形有两个重载

    public void DrawRectangle(RectF rect, Brush brush, float strokeWidth)
    public unsafe void DrawRectangle(RectF rect, Brush brush, float strokeWidth, StrokeStyle strokeStyle)

矩形的 StrokeStyle 和线段一样。

椭圆

实际上画圆和椭圆是一样的,画圆的函数有两个重载

    public void DrawEllipse(Ellipse ellipse, Brush brush, float strokeWidth)
 public unsafe void DrawEllipse(Ellipse ellipse, Brush brush, float strokeWidth, StrokeStyle strokeStyle)

需要先创建 Ellipse 和笔刷。

创建 Ellipse 需要给圆心和两个轴,下面创建一个圆心在 (100,100) ,两个轴都是50的椭圆。实际上就是半径是50的圆形。

            var ellipse = new D2D.Ellipse(new D2D.Point2F(100, 100), 50, 50);

这就是绘制基本的图形。

那么如何填充图形?实际上所有 Draw 都有对应的 Fill 函数,除了线段。所以填充就是调用对应的 Fill 函数。

尝试运行程序,看看这时的 CPU ,实际上是几乎不会动,因为所有的计算都在 GPU 计算。不过程序里的代码包括创建图形,实际上是在 CPU 创建,但是因为速度很快,几乎不需要计算,所以需要的时间很短。

文字

最后就是告诉大家如何绘制文字。

绘制文字需要使用 DirectWrite ,需要先创建 DWriteFactory 然后才可以绘制文本。

绘制文本有多个方式,因为需要的很多参数都不能直接创建需要使用 DWriteFactory 创建,所以这里需要先使用下面代码

            var dWriteFactory = DWriteFactory.CreateFactory();

创建文字有多个方法

public void DrawText(string text, TextFormat textFormat, RectF layoutRect, Brush defaultForegroundBrush)

public void DrawText(string text, TextFormat textFormat, RectF layoutRect, Brush defaultForegroundBrush, MeasuringMode measuringMode)

public void DrawText(string text, TextFormat textFormat, RectF layoutRect, Brush defaultForegroundBrush, DrawTextOptions options)

public unsafe void DrawText(string text, TextFormat textFormat, RectF layoutRect, Brush defaultForegroundBrush, DrawTextOptions options, MeasuringMode measuringMode)

 public unsafe void DrawTextLayout(Point2F origin, TextLayout textLayout, Brush defaultForegroundBrush)

 public unsafe void DrawTextLayout(Point2F origin, TextLayout textLayout, Brush defaultForegroundBrush, DrawTextOptions options)

因为有很多个参数,需要大家自己去试试

下面来写出简单文字

需要先创建 textFormat 需要告诉使用哪个字形,和字体大小

            var textFormat = dWriteFactory.CreateTextFormat("宋体", 20);

下面就是画出文字,文字换行可以使用\n,复杂的换行请使用文字重载方法,这里我就不说了

            _renderTarget.BeginDraw();

            _renderTarget.DrawText("lindexi 本文所有博客放在 lindexi.oschina.io \n欢迎大家来访问\n\n这是系列博客,告诉大家如何在 WPF 使用Direct2D1", textFormat, new D2D.RectF(10, 10, 1000, 1000), brush);

            _renderTarget.EndDraw();

需要说的是 Windows API Code Pack 1.1 已经很久没更新,而且有错误,所以建议使用 SharpDX

参见:Using Direct2D with WPF - CodeProject

https://jeremiahmorrill.wordpress.com/2011/02/14/a-critical-deep-dive-into-the-wpf-rendering-system/

2018-8-10-WPF-使用-Direct2D1-画图-绘制基本图形的更多相关文章

  1. WPF 使用 Direct2D1 画图 绘制基本图形

    本文来告诉大家如何在 Direct2D1 绘制基本图形,包括线段.矩形.椭圆 本文是一个系列 WPF 使用 Direct2D1 画图入门 WPF 使用 Direct2D1 画图 绘制基本图形 本文的组 ...

  2. WPF 使用 Direct2D1 画图入门

    本文来告诉大家如何在 WPF 使用 D2D 画图. 本文是一个系列 WPF 使用 Direct2D1 画图入门 WPF 使用 Direct2D1 画图 绘制基本图形 WPF 使用 SharpDX WP ...

  3. 10 个超炫绘制图表图形的 Javascript 插件【转载+整理】

    原文地址 现在,有很多在线绘制图表和图形(Charts and Graphs)的 JavaScript 插件,这些插件还都是免费,以及图表库.这些插件大量出现的原因是基于一个事实:人们不再依赖于 Fl ...

  4. WPF中使用amCharts绘制股票K线图

    原文:WPF中使用amCharts绘制股票K线图 本想自己用GDI绘图, 通过数据直接绘制一张蜡柱图, 但觉得这样子的功能比较少, 所以到网上搜索一些能画出K线图的控件. 发现DynamicDataD ...

  5. 申请Office 365一年免费的开发者账号攻略(2018年10月份版本)

    要进行Office 365开发,当然需要有完整的Office 365环境才可以.为了便于广大开发人员快速地启动这项工作,微软官方给所有开发人员提供了免费的一年开发者账号   那么如何申请Office ...

  6. IntelliJ IDEA 最新激活码(截止到2018年10月14日)

    IntelliJ IDEA 注册码: EB101IWSWD-eyJsaWNlbnNlSWQiOiJFQjEwMUlXU1dEIiwibGljZW5zZWVOYW1lIjoibGFuIHl1IiwiYX ...

  7. 新手C#SQL Server使用记录2018.08.10

    主键(PrimaryKey):主键就是每个数据行(记录)的唯一标识,不会有重复值的列(字段)才能当做主键.一个表可以没有主键,但是这样会很难处理表,因此一般情况表都要设置主键. 主键有两张选用策略,分 ...

  8. Android画图系列(二)——自己定义View绘制基本图形

    这个系列主要是介绍下Android自己定义View和Android画图机制.自己能力有限.假设在介绍过程中有什么错误.欢迎指正 前言 在上一篇Android画图系列(一)--自己定义View基础中我们 ...

  9. 01 mybatis框架整体概况(2018.7.10)-

    01 mybatis框架整体概况(2018.7.10)- F:\廖雪峰 JavaEE 企业级分布式高级架构师课程\廖雪峰JavaEE一期\第一课(2018.7.10) maven用的是3.39的版本 ...

随机推荐

  1. MySQL数据库(三)—— 表相关操作(二)之约束条件、关联关系、复制表

    表相关操作(二)之约束条件.关联关系.复制表 一.约束条件  1.何为约束 除了数据类型以外额外添加的约束 2.约束条件的作用 为了保证数据的合法性,完整性 3.主要的约束条件 NOT NULL # ...

  2. 6个步骤,全方位掌握 Kafka

    毋庸置疑,目前 Apache Kafka 是整个消息引擎领域的执牛耳者,也是大数据生态圈中颇为重量级的一员. 从最早诞生于 LinkedIn 的"分布式消息系统",到现在集成了分发 ...

  3. EM相关两个算法 k-mean算法和混合高斯模型

    转自http://www.cnblogs.com/jerrylead/archive/2011/04/06/2006924.html http://www.cnblogs.com/jerrylead/ ...

  4. URL&HTTP协议&GET请求&POST请求

    1.什么是URL URL的全称是Uniform Resource Locator(统一资源定位符) 通过1个URL,能找到互联网上唯一的1个资源 URL就是资源的地址.位置,互联网上的每个资源都有一个 ...

  5. C语言指针变量的长度

    #include <stdio.h> int main() { /********************************************* * * 指针的长度:不同机器可 ...

  6. Spring框架4大原则和主要功能

    Spring框架4大原则: 使用POJO进行轻量级和最小侵入式开发 POJO(Plain Ordinary Java Object)简单的Java对象,实际就是普通JavaBeans,是为了避免和EJ ...

  7. ubuntu phpize 安裝

    php 版本 7.2,所以安裝 php7.2的 sudo apt-get install php7.2-dev 參考 Is is possible to install phpize for PHP7 ...

  8. Ubuntu16.04 使用PPA安装JDK8

    安装Java 8 ( 支持 Ubuntu 10.04 - Ubuntu 16.04 ) 1.如果你在 Ubuntu 软件中心安装过 OpenJDK,请先使用如下命令将其删除: sudo apt-get ...

  9. spark-sql中的分析函数的使用

    分析函数的应用场景: (1)用于分组后组内排序 (2)指定计算范围 (3)Top N (4)累加计算 (5)层次计算 分析函数的一般语法: 分析函数的语法结构一般是: 分析函数名(参数)  over  ...

  10. 通过base64实现图片下载功能(基于vue)

    1. 使用场景 当我们处理图片下载功能的时候,如果本地的图片,那么是可以通过canvas获得图片的base64的,方法如下.但是如果图片的url存在跨域问题的话,下面的方法将行不通,这时候我们可以另辟 ...