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);

                    // 将照片解码为BitmapSource
                    SoftwareBitmap 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线程上创建BitmapSource
            await 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,案例及知识分享专栏,wpf)