当前位置: 首页 > news >正文

WPF实现签名拍照功能

在这里插入图片描述

✅作者简介:2022年博客新星 第八。热爱国学的Java后端开发者,修心和技术同步精进。
🍎个人主页:Java Fans的博客
🍊个人信条:不迁怒,不贰过。小知识,大智慧。
💞当前专栏:WPF 案例及知识分享专栏
✨特色专栏:乐趣国学-心性养成之路
🥭本文内容:WPF实现签名拍照功能
  当你使用WPF(Windows Presentation Foundation)技术编写一个签名拍照软件时,需要使用C#来处理界面和相机操作。以下是一个简单示例,展示如何创建一个WPF应用程序来实现这一功能。

在这里插入图片描述

  首先,确保你已经安装了Visual Studio和.NET框架。然后,创建一个新的WPF应用程序项目,我们将称之为"SignatureCaptureApp"。

  在MainWindow.xaml中,创建界面布局,包括一个显示相机预览的区域、一个签名区域、一个按钮来拍照并保存签名。

<Window x:Class="SignatureCaptureApp.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"Title="Signature Capture App" Height="400" Width="600"><Grid><Image Name="CameraPreview" Width="400" Height="300" Stretch="UniformToFill" Margin="10"/><InkCanvas Name="SignatureCanvas" Width="400" Height="100" Margin="10"/><Button Content="拍照并保存签名" Click="CaptureSignature_Click" HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="0,0,0,10"/></Grid>
</Window>

  在MainWindow.xaml.cs中,添加相机和签名捕捉的逻辑。

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Ink;
using System.Windows.Media.Imaging;
using System.Windows.Media.Imaging;namespace SignatureCaptureApp
{public partial class MainWindow : Window{private CameraCapture _cameraCapture;public MainWindow(){InitializeComponent();_cameraCapture = new CameraCapture(CameraPreview);_cameraCapture.InitializeCamera();}private void CaptureSignature_Click(object sender, RoutedEventArgs e){// 拍照BitmapSource photo = _cameraCapture.CapturePhoto();// 保存签名if (SignatureCanvas.Strokes.Count > 0 && photo != null){SaveSignatureAndPhoto(SignatureCanvas.Strokes, photo);}}private void SaveSignatureAndPhoto(StrokeCollection strokes, BitmapSource photo){try{// 为签名创建一个独一无二的文件名string signatureFileName = $"Signature_{DateTime.Now:yyyyMMddHHmmss}.png";string photoFileName = $"Photo_{DateTime.Now:yyyyMMddHHmmss}.jpg";// 获取保存签名和照片的文件夹路径string saveFolderPath = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures);// 创建签名图片文件SaveSignatureToFile(strokes, Path.Combine(saveFolderPath, signatureFileName));// 创建照片文件SavePhotoToFile(photo, Path.Combine(saveFolderPath, photoFileName));}catch (Exception ex){// 处理错误,例如显示错误消息框MessageBox.Show($"保存签名和照片时发生错误:{ex.Message}");}}private void SaveSignatureToFile(StrokeCollection strokes, string filePath){// 创建一个RenderTargetBitmap用于绘制签名RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap(400, 100, 96, 96, PixelFormats.Default);renderTargetBitmap.Render(SignatureCanvas);// 创建一个PngBitmapEncoder保存签名PngBitmapEncoder encoder = new PngBitmapEncoder();encoder.Frames.Add(BitmapFrame.Create(renderTargetBitmap));// 将签名保存到文件using (FileStream fileStream = new FileStream(filePath, FileMode.Create)){encoder.Save(fileStream);}}private void SavePhotoToFile(BitmapSource photo, string filePath){// 创建一个JpegBitmapEncoder保存照片JpegBitmapEncoder encoder = new JpegBitmapEncoder();encoder.Frames.Add(BitmapFrame.Create(photo));// 将照片保存到文件using (FileStream fileStream = new FileStream(filePath, FileMode.Create)){encoder.Save(fileStream);}}}
}

  生成唯一的文件名,然后获取用于保存的文件夹路径(这里以"我的图片"文件夹为例)。接下来,它使用RenderTargetBitmap将签名画布渲染为位图,然后使用PngBitmapEncoder保存签名。同时,也使用JpegBitmapEncoder保存相机拍摄的照片。

  创建CameraCapture.cs类来处理相机操作。你需要使用WPF的MediaElement和System.Windows.Media.Imaging来实现相机预览和拍照功能。这里提供一个简化的示例,实际应用中需要更多的处理和错误处理。

  当你需要在WPF应用中初始化相机并进行拍照时,你可以使用MediaCapture类来实现。下面是更详细的示例,展示如何初始化相机并进行拍照:

using System;
using System.Windows.Controls;
using System.Windows.Media.Imaging;
using System.Windows.Media;
using System.Windows.Threading;
using System.Windows;
using System.IO;
using System.Threading.Tasks;
using Windows.Media.Capture;
using Windows.Media.MediaProperties;
using Windows.Storage;
using Windows.Storage.Streams;namespace SignatureCaptureApp
{public class CameraCapture{private MediaElement _cameraPreview;private MediaCapture _mediaCapture;public CameraCapture(MediaElement cameraPreview){_cameraPreview = cameraPreview;}public async void InitializeCamera(){try{// 初始化MediaCapture对象_mediaCapture = new MediaCapture();await _mediaCapture.InitializeAsync();// 将相机预览显示在MediaElement中_cameraPreview.SetMediaPlayer(_mediaCapture);// 启动相机预览await _mediaCapture.StartPreviewAsync();}catch (Exception ex){// 处理错误,例如显示错误消息框MessageBox.Show($"初始化相机时发生错误:{ex.Message}");}}public async Task<BitmapSource> CapturePhoto(){try{// 创建一个临时文件来保存照片StorageFile photoFile = await ApplicationData.Current.TemporaryFolder.CreateFileAsync("TempPhoto.jpg", CreationCollisionOption.GenerateUniqueName);// 拍照并保存到临时文件ImageEncodingProperties imageProperties = ImageEncodingProperties.CreateJpeg();await _mediaCapture.CapturePhotoToStorageFileAsync(imageProperties, photoFile);// 从临时文件中读取照片数据using (IRandomAccessStream photoStream = await photoFile.OpenReadAsync()){// 创建一个BitmapDecoder来解码照片数据BitmapDecoder decoder = await BitmapDecoder.CreateAsync(photoStream);// 将照片解码为BitmapSourceSoftwareBitmap softwareBitmap = await decoder.GetSoftwareBitmapAsync();SoftwareBitmap softwareBitmapBGR8 = SoftwareBitmap.Convert(softwareBitmap, BitmapPixelFormat.Bgra8, BitmapAlphaMode.Premultiplied);BitmapSource photo = await ConvertToBitmapSource(softwareBitmapBGR8);// 删除临时文件await photoFile.DeleteAsync();// 返回照片return photo;}}catch (Exception ex){// 处理错误,例如显示错误消息框MessageBox.Show($"拍照时发生错误:{ex.Message}");return null;}}private async Task<BitmapSource> ConvertToBitmapSource(SoftwareBitmap softwareBitmap){// 创建一个WriteableBitmap来保存照片数据WriteableBitmap bitmap = new WriteableBitmap(softwareBitmap.PixelWidth, softwareBitmap.PixelHeight);softwareBitmap.CopyToBuffer(bitmap.PixelBuffer);// 等待UI线程空闲,然后在UI线程上创建BitmapSourceawait Application.Current.Dispatcher.BeginInvoke(new Action(() =>{bitmap.Invalidate();}), DispatcherPriority.ApplicationIdle);return bitmap;}}
}

  在InitializeCamera方法中,我们使用MediaCapture类来初始化相机,并将相机预览显示在MediaElement中。在CapturePhoto方法中,我们使用CapturePhotoToStorageFileAsync方法拍照并将照片保存到临时文件中。然后,我们使用BitmapDecoder类解码照片数据,并将其转换为BitmapSource对象。最后,我们删除临时文件并返回照片。

  请注意,这段代码使用了异步方法,因此需要在方法前面加上async关键字,并使用await关键字来等待异步操作完成。此外,我们还使用了SoftwareBitmap和WriteableBitmap来处理照片数据。


  码文不易,本篇文章就介绍到这里,如果想要学习更多Java系列知识点击关注博主,博主带你零基础学习Java知识。与此同时,对于日常生活有困扰的朋友,欢迎阅读我的第四栏目:《国学周更—心性养成之路》,学习技术的同时,我们也注重了心性的养成。

在这里插入图片描述

相关文章:

WPF实现签名拍照功能

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…...

基于RuoYi-Flowable-Plus的若依ruoyi-nbcio支持自定义业务表单流程的集成方法与步骤(二)

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码&#xff1a; https://gitee.com/nbacheng/ruoyi-nbcio 演示地址&#xff1a;RuoYi-Nbcio后台管理系统 前面讲了集成的后端部分内容&#xff0c;下面简单介绍一下前端的内容 1、前端生成的页面需要进行修改&…...

【Qt控件之微调框、进度条】QSpinBox、QDoubleSpinBox、QDial、QProgressBar介绍及使用

概述 QSpinBox类提供了一个微调框小部件。 QSpinBox适用于处理整数和离散的值集&#xff08;例如&#xff0c;月份名称&#xff09;&#xff1b;对于浮点数值&#xff0c;请使用QDoubleSpinBox。 QSpinBox允许用户通过点击上下按钮或按键盘上的上下箭头来增加/减少当前显示的值…...

Python学习-----Day09

一、利用装饰器来获取函数运行的时间、 #导入time模块 import timedef decorated(fn):def inner():#time.time获取函数执行的时间a time.time() # func开始的时间fn()b time.time() # func结束的时间print(f"{fn.__name__}程序运行的总数时间:{b - a}秒")return…...

世界国家/地区行驶方向数据

Part1数据背景 道路通行方向规则是交通规则的重要部分之一。不同国家及地区通行方向并不一样&#xff0c;受风俗、习惯、风潮因素等影响。 最近也在学道路行驶&#xff0c;结果差强人意&#xff0c;继续努力吧。祝学车的小伙伴们一次过~ Part2数据详情 今天分享的国家/地区行…...

idgen导入Android11源码

文章目录 配置下载AS编译源码依赖导入玩一下andorid.iml 注意&#xff1a; 有些时候发现为啥自己编译就这么难呢&#xff1f;不是卡死就无数次重启虚拟机&#xff0c;一切的原罪在配置过低&#xff0c;换句话说就是穷。关于导入源码的下载参考 Android Studio for Platform (AS…...

大同小异!如何在苹果不同类型设备上更改AirDrop的名称

你可以更改你的AirDrop ID&#xff0c;让其他人看到你名字之外的东西。本文介绍了如何在iPhone、iPad和Mac上更改AirDrop名称。 如何在iPhone上更改AirDrop名称 在iPhone上更改AirDrop名称涉及到你可能不想做的更改。幸运的是&#xff0c;这在iPad和Mac上不是真的&#xff0c…...

sqlmap --os-shell选项原理解析

文章目录 sqlmap --os-shell选项原理解析原理解析总结 sqlmap --os-shell选项原理解析 以sqli第一关为例。 --os-shell 是 SQLMap 工具的一个参数&#xff0c;用于在成功注入数据库后&#xff0c;执行操作系统命令并获取其输出。 sqlmap -u "http://192.168.188.199/sq…...

谈谈 Redis 持久化机制,RDB、AOF

谈谈 Redis 持久化机制&#xff0c;RDB&#xff0c;AOF RDB&#xff1a;相当于对内存中的数据&#xff0c;拍一张数据快照。存储的是数据。 AOF&#xff1a;存储的是具体的命令。 企业实践中&#xff0c;实际是使用RDB结合AOF。 这个方法是在 Redis 4.0 提出的&#xff0c;该方…...

并发编程——2.基础概念及其它相关的概述

这篇文章我们来讲一下并发编程中的线程及其相关的概述内容。 目录 1.J.U.C 2.进程、线程、协程 2.1进程 2.2线程 2.3纤程&#xff08;协程&#xff09; 2.4概念小结 3.并发、并行、串行 3.1并发 3.2并行 3.3串行 3.4概念小结 4.CPU核心数和线程数的关系 5.上下文…...

20231019 filezilla 配置 Windows与Ubuntu文件传输

SFTP协议&#xff0c;传文件&#xff0c;否则会报无权限错...

一个.Net开发的轻量级SQLite数据库ORM

SQLite是一种流行的开源关系型数据库&#xff0c;它的设计目标是提供轻量级、高效、可靠和易用的数据存储服务。由于SQLite无需单独的服务器进程&#xff0c;它通常被用于嵌入式系统和单机应用程序中&#xff0c;也可以用于网络应用程序的辅助数据库。 今天给大家推荐一个.NET开…...

gRPC通信

1. gRPC简介 gRPC是一种高性能、开源和通用的远程过程调用&#xff08;RPC&#xff09;框架&#xff0c;由Google开源并维护。它使用Protocol Buffers&#xff08;protobuf&#xff09;作为接口定义语言&#xff08;IDL&#xff09;&#xff0c;提供跨平台、跨语言的RPC调用支…...

湖仓一体架构的特性

湖仓一体架构是一种数据架构模式&#xff0c;具有以下特性&#xff1a; 统一存储&#xff1a;湖仓一体架构将数据湖和数据仓库合并为一个整体&#xff0c;将结构化数据和非结构化数据存储在同一个存储系统中&#xff0c;如Hadoop分布式文件系统&#xff08;HDFS&#xff09;或云…...

Python中使用包含_和__的变量名之间的区别

_:单下划线 例子&#xff1a;_count、_temp 含义&#xff1a;成员的私有成员变量&#xff0c;就像Java中用private关键字修饰一样。 作用&#xff1a;只允许当前类创建的对象和子类对象访问此变量。外部无法访问此变量。 __:双下划线 例子&#xff1a;__count、__temp 含义&am…...

019-第三代软件开发-Git提交规范

第三代软件开发-Git提交规范 文章目录 第三代软件开发-Git提交规范项目介绍Git提交规范分支规范Commit Message FormatHeaderBodyFooterRevert 总结一下 关键字&#xff1a; Qt、 Qml、 git、 Commit、 release 项目介绍 欢迎来到我们的 QML & C 项目&#xff01;这个…...

MTK APP实现动态修改logo和开机动画

MTK APP实现动态修改logo和开机动画 前言一、修改对新分区的权限1.修改开机动画对新分区的权限2.修改系统APP对新分区的权限3.修改SE权限,不然编译会报错4.修改开机动画文件&#xff0c;让其加载新分区中的文件 二、系统APP代码使用1.系统app修改开机logo2.系统app修改开机动画…...

Spring核心扩展点BeanDefinitionRegistryPostProcessor源码分析

我们知道&#xff0c;只要在一个Java类上加上Component、Service、Controller等注解&#xff0c;就可以被加载到Spring容器中&#xff0c;除了以上方式&#xff0c;加了Bean和Import好像也可以将对象添加到Spring容器中&#xff0c;究竟Spring是如何实现这些功能的呢&#xff1…...

C++实现AC自动机,剪枝、双数组压缩字典树!详解双数组前缀树(Double-Array Trie)剪枝字典树(Patricia Trie)

代码在&#xff1a;github.com/becomequantum 最近研究了一下字典树&#xff0c;什么AC自动机&#xff0c;双数组压缩字典树&#xff0c;剪枝字典树都自己写代码实现了一下。这本该是本科学数据结构时该玩明白的东西&#xff0c;我到现在才会玩。本视频主要介绍一下双数组和剪…...

防火墙规则顺序解决方案

防火墙是保护网络免受攻击的第一道防线&#xff0c;防火墙对互联网和公司IT网络之间的流量拥有绝对控制权&#xff0c;防火墙规则的配置处理调节流量的关键任务。 这些规则会仔细检查传入和传出流量&#xff0c;并根据规则中提到的条件允许或阻止它&#xff0c;防火墙规则越严…...

本地部署DeepSeek并搭建量化交易系统:完整指南

本地部署DeepSeek并搭建量化交易系统:完整指南 1. 引言 随着大语言模型(LLM)的快速发展,其在金融领域的应用潜力日益凸显。DeepSeek作为一款高性能、开源的大模型,能够为量化交易系统提供强大的自然语言理解和生成能力,例如从新闻、研报中提取信号,辅助生成交易策略,…...

python-langchain框架(1-8-2 缓存机制——验证缓存的效果)

当用户提出一个常见问题时&#xff0c;首次调用大模型需要经历网络传输、排队等待、模型推理等完整链路&#xff0c;响应时间通常在1至3秒。这个时长已超过人类对“流畅交互”的心理阈值&#xff08;200毫秒&#xff09;&#xff0c;用户会明显感知到“卡顿”和“等待焦虑”。而…...

深圳地铁大数据客流分析系统:如何用开源技术栈破解千万级乘客的交通治理难题

深圳地铁大数据客流分析系统&#xff1a;如何用开源技术栈破解千万级乘客的交通治理难题 【免费下载链接】SZT-bigdata 深圳地铁大数据客流分析系统&#x1f687;&#x1f684;&#x1f31f; 项目地址: https://gitcode.com/gh_mirrors/sz/SZT-bigdata 深圳地铁作为中国…...

2025最权威的十大AI辅助写作助手推荐

Ai论文网站排名&#xff08;开题报告、文献综述、降aigc率、降重综合对比&#xff09; TOP1. 千笔AI TOP2. aipasspaper TOP3. 清北论文 TOP4. 豆包 TOP5. kimi TOP6. deepseek 当今之时&#xff0c;人工智能技术已然深度介入至毕业论文的写作进程里面&#xff0c;于文献…...

告别硬编码!用Rule-Engine 1.0.0重构你的Java业务逻辑(附订单折扣实战)

告别硬编码&#xff01;用Rule-Engine 1.0.0重构你的Java业务逻辑&#xff08;附订单折扣实战&#xff09; 每次电商大促前夜&#xff0c;技术团队最怕听到的一句话是什么&#xff1f;"折扣规则又改了&#xff01;"——这往往意味着通宵修改代码、紧急测试和冒着风险…...

DeepSeek总结的 PostgreSQL 19:为 UPDATE/DELETE 添加 FOR PORTION OF 子句

原文地址&#xff1a;https://www.depesz.com/2026/04/02/waiting-for-postgresql-19-add-update-delete-for-portion-of/ 等待 PostgreSQL 19&#xff1a;为 UPDATE/DELETE 添加 FOR PORTION OF 子句 2026 年 4 月 1 日&#xff0c;Peter Eisentraut 提交了一个补丁&#xf…...

10个高效技巧解决RVC变声器常见故障

10个高效技巧解决RVC变声器常见故障 【免费下载链接】Retrieval-based-Voice-Conversion-WebUI Easily train a good VC model with voice data < 10 mins! 项目地址: https://gitcode.com/GitHub_Trending/re/Retrieval-based-Voice-Conversion-WebUI Retrieval-bas…...

根据应用场景TongWeb版本选购指南

TongWeb7.0.4企业版TongWeb8.0/7.0.8企业版&#xff08;主推&#xff09;TongWeb7.0.E/8.0.E嵌入版TongHttpServer(THS)应用开发语言JavaEE应用JavaEE/JakartaEE应用JavaEE/JakartaEE应用PHP应用、vue前端应用说明&#xff1a;1. PHP应用直接推荐THS。2. .NET Core应用不需要中…...

奥尔特云智慧武装系统上线!基层武装管理从此“智”在必得!

随着国防动员与基层武装工作不断升级&#xff0c;传统管理模式存在信息化覆盖不全、数据归集粗放、智能化水平不足等问题&#xff0c;已难以适配高效管理与应急应战需求&#xff0c;数字化转型成为必然趋势。智慧武装系统是奥尔特云&#xff08;深圳&#xff09;智慧科技打造的…...

ai生成代码如何管理?快马结合gitbash实现智能开发工作流

今天想和大家分享一个高效的工作流&#xff1a;如何用AI生成代码后&#xff0c;通过GitBash进行规范的版本管理。最近在InsCode(快马)平台实践了这个方法&#xff0c;整个过程非常流畅。 AI生成代码阶段 在快马的AI对话区输入需求&#xff1a;“创建一个带有深色模式切换功能的…...