当前位置: 代码网 > it编程>编程语言>Asp.net > WPF 基础绘图 创建和加工图片

WPF 基础绘图 创建和加工图片

2024年05月12日 Asp.net 我要评论
本文将从控制台开始,告诉大家一个非常简单的 WPF 基础绘图方法,通过本文的方法可以调用 WPF 上层人类友好的方法,充分利用 GPU 资源,创建或加工图片,最终结果可以输出到本地文件,可支持编码出多种不同的图片格式 本文仅用到 WPF 的多媒体渲染层,在 WPF 的这一层上的 API 是人类友好的 ...

本文将从控制台开始,告诉大家一个非常简单的 wpf 基础绘图方法,通过本文的方法可以调用 wpf 上层人类友好的方法,充分利用 gpu 资源,创建或加工图片,最终结果可以输出到本地文件,可支持编码出多种不同的图片格式

本文仅用到 wpf 的多媒体渲染层,在 wpf 的这一层上的 api 是人类友好的,直接咱使用的是就是熟悉的 drawingcontext 类型。通过 drawingcontext 进行画线、画矩形、画几何、画图片、画文字,进行裁剪、变换、加特效等等,即可绘制出绚酷的界面效果。经由 rendertargetbitmap 和 bitmapencoder 即可将界面编码为图片输出到文件里面

从本质上讲,本文的方法里面只是将 wpf 当成一个对 wic (windows imaging component) 层以及 directx 层的高级封装库,没有用到 wpf 更多好用的功能

回到主题,先创建一个控制台项目,在控制台项目里面打上 wpf 的负载,加上之后的 csproj 项目文件的代码如下

<project sdk="microsoft.net.sdk">

  <propertygroup>
    <outputtype>exe</outputtype>
    <targetframework>net8.0-windows</targetframework>
    <implicitusings>enable</implicitusings>
    <nullable>enable</nullable>
    <usewpf>true</usewpf>
  </propertygroup>

</project>

在控制台里面要么在 main 函数标记 stathread 特性,要么自己新建一个 sta 线程,由于我之前的博客大量介绍的都是在 main 函数上标记 stathread 特性,于是我准备在这篇博客换一个玩法,就是自己新建一个 sta 线程。相对来说新建一个线程的代码会稍微多一点点

var thread = new thread(() =>
{
    ... // 等待添加更多代码
});

thread.setapartmentstate(apartmentstate.sta);
thread.start();

完成线程创建之后,即可在以上的 等待添加更多代码 里面加上 wpf 应用的初始化,在 wpf 应用的初始化里面自动将包含大量的初始化工作,简单的代码如下

var thread = new thread(() =>
{
    var application = new application();
    application.startup += application_startup;
    application.run();
});

在 startup 事件里面执行真正的处理绘图相关逻辑,以上代码的 application_startup 的基础实现逻辑如下

先创建 drawingvisual 对象,通过此对象即可获取到 drawingcontext 以执行绘图逻辑

void application_startup(object sender, startupeventargs e)
{
    var drawingvisual = new drawingvisual();
    ... // 等待添加更多代码
}

从 drawingvisual 里面获取 drawingcontext 的代码如下

    var drawingvisual = new drawingvisual();
    using (drawingcontext drawingcontext = drawingvisual.renderopen())
    {
        ... // 等待添加更多代码
    }

通过 drawingcontext 的 drawxxx 系列方法即可绘制出有趣的界面效果,比如本文例子中绘制简单的矩形的代码

    using (var drawingcontext = drawingvisual.renderopen())
    {
        drawingcontext.drawrectangle(brushes.black, pen: null, new rect(0, 0, 1024, 768));
    }

实际使用中,可以在此替换为你所需的各种代码,包括先绘制图片,再绘制文本,从而制作文本水印等等。也可以加上更多复杂的编程控制逻辑,绘制更复杂的图片。如绘制从本地文件读取出来的图片,请参阅 wpf 通过 drawingcontext drawimage 绘制图片 以及更复杂的绘制逻辑请看 博客导航

完成绘制之后,可使用 rendertargetbitmap 与 bitmapencoder 配合,将绘制的内容写入到本地图片文件里面

创建 rendertargetbitmap 对象,给定尺寸,代码如下

    // 画布大小
    var drawingbounds = drawingvisual.drawing.bounds;
    // 修改为固定的尺寸
    drawingbounds = new rect(0, 0, 1024, 768);
    var rendertargetbitmap = new rendertargetbitmap((int) drawingbounds.width, (int) drawingbounds.height, 96, 96, pixelformats.pbgra32);

以上代码里面的画布大小有多个选项,一个就是使用绘制的范围,绘制的范围里面可能控制性比较差,因为会受到本身绘制的影响,可能存在绘制范围超过了预期画布尺寸,导致了输出的图片偏差。设置固定的尺寸大小,可以固定画布的尺寸,相对来说比较常用

以上代码里面的 rendertargetbitmap 的 96 指的是图片的 dpi 值,默认情况下给 96 是比较符合视觉预期的。这里的 dpi 不是屏幕的 dpi 值,一般不应该根据当前的显示设备的 dpi 值赋值给到图片上,应该一直保持是 96 的 dpi 值。这部分有一些前置的知识,更多还请自行查阅 dpi 相关知识

将刚才绘制完成的 drawingvisual 在 rendertargetbitmap 渲染出来,代码如下

    rendertargetbitmap.render(drawingvisual);

现在已经拿到了 rendertargetbitmap 对象,由于 rendertargetbitmap 类型继承自 bitmapsource 类型,因此这里可以认为已经拿到了 bitmapsource 对象

现在的 bitmapsource 对象还在内存里面,想要将 bitmapsource 存放为图片文件需要经过图片编码步骤,将编码之后的数据写入到文件才能完成保存图片文件的保存

图片编码可使用 bitmapencoder 类型的对象进行编码,常用的继承自 bitmapencoder 的 pngbitmapencoder 或 jpegbitmapencoder 等等类型。本文这里通过 pngbitmapencoder 编码出 png 文件,代码如下

    var pngbitmapencoder = new pngbitmapencoder();
    pngbitmapencoder.frames.add(bitmapframe.create(rendertargetbitmap));

    var file = "1.png";

    using (var filestream = file.create(file))
    {
        pngbitmapencoder.save(filestream);
    }

通过以上方法即可将图片编码保存到 1.png 文件

使用本文以上的方法即可简单从控制台开始,使用 wpf 辅助绘制内容,将绘制的内容编码为图片文件保存到本地文件

本文以上代码都写在一个 program.cs 文件里,代码非常简单

using system.io;
using system.windows;
using system.windows.media;
using system.windows.media.imaging;
var thread = new thread(() =>
{
    var application = new application();
    application.startup += application_startup;
    application.run();
});

void application_startup(object sender, startupeventargs e)
{
    var drawingvisual = new drawingvisual();
    using (var drawingcontext = drawingvisual.renderopen())
    {
        drawingcontext.drawrectangle(brushes.black, pen: null, new rect(0, 0, 1024, 768));
    }

    // 画布大小
    var drawingbounds = drawingvisual.drawing.bounds;
    // 修改为固定的尺寸
    drawingbounds = new rect(0, 0, 1024, 768);
    var rendertargetbitmap = new rendertargetbitmap((int) drawingbounds.width, (int) drawingbounds.height, 96, 96, pixelformats.pbgra32);
    rendertargetbitmap.render(drawingvisual);

    var pngbitmapencoder = new pngbitmapencoder();
    pngbitmapencoder.frames.add(bitmapframe.create(rendertargetbitmap));

    var file = "1.png";

    using (var filestream = file.create(file))
    {
        pngbitmapencoder.save(filestream);
    }
}

thread.setapartmentstate(apartmentstate.sta);
thread.start();

本文代码放在 githubgitee 上,可以使用如下命令行拉取代码

先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码

git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin 1b8661bdbea21fbef432856ddc26999505144ba2

以上使用的是 gitee 的源,如果 gitee 不能访问,请替换为 github 的源。请在命令行继续输入以下代码,将 gitee 源换成 github 源进行拉取代码

git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git
git pull origin 1b8661bdbea21fbef432856ddc26999505144ba2

获取代码之后,进入 bayheelearchachearjobarhearne 文件夹,即可获取到源代码

更多 wpf 基础绘图请参阅 博客导航

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com