C# 图片盖章功能实现,支持拖拽-旋转-放缩-保存

实现图片盖章功能,在图片上点击,增加“图章”小图片,可以拖拽“图章”到任意位置,也可以点击图章右下角园框,令图片跟着鼠标旋转和放缩。

操作方法:1.点击增加“图章”2.选中移动图标3.点中右下角放缩旋转图章。

实现代码如下:

1.  窗口Xaml代码

<Window x:Class="Lenovo.YogaPaster.ImageEditWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"Title="ImageEditWindow" Height="300" Width="300"><Grid><Grid.RowDefinitions><RowDefinition Height="20*"/><RowDefinition  Height="*"/></Grid.RowDefinitions><Canvas x:Name="canvas" Background="Yellow" /><Button Content="保存成图片" Click="Button_Click_1" Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center"/></Grid>
</Window>

2.  窗口后台代码:

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using Lenovo.YP.Utils;
using Microsoft.Win32;
using Point = System.Windows.Point;namespace Lenovo.YogaPaster
{/// <summary>/// ImageEditWindow.xaml 的交互逻辑/// </summary>public partial class ImageEditWindow : Window{public ImageEditWindow(){InitializeComponent();this.Loaded += (sender, e) =>{canvas.MouseLeftButtonDown += canvas_MouseLeftButtonDown;};}private void canvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e){PhotoEditHelper.CommomMaxZIndex++;var image = new MoveImage { ContainerCanvas = canvas };Point point = e.GetPosition(canvas);image.CreateImage(point);}/// <summary>/// 保存方法/// </summary>public void SavePicture(){//TODO: openFile对话框 SaveFileDialog saveFileDialog = new SaveFileDialog();saveFileDialog.FileName = "图片"; // Default file namesaveFileDialog.DefaultExt = ".bmp"; // Default file extensionsaveFileDialog.Filter = "图片文件 (.bmp)|*.bmp"; // Filter files by extension// Show save file dialog boxNullable<bool> result = saveFileDialog.ShowDialog();// Process save file dialog box resultsif (result == true){// Save documentstring filename = saveFileDialog.FileName;if (File.Exists(filename)){File.Delete(filename);}BitmapSource bitmapSource = PictureMergeHelper.CreateNotRanderElementScreenshot(canvas, 1800, 1080);BitmapEncoder bitmapEncoder = new BmpBitmapEncoder();bitmapEncoder.Frames.Add(BitmapFrame.Create(bitmapSource));FileStream fileStream = new FileStream(filename, FileMode.Create);bitmapEncoder.Save(fileStream);fileStream.Dispose();}}private void Button_Click_1(object sender, RoutedEventArgs e){SavePicture();}}
}

 3. MoveImage类文件如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;namespace Lenovo.YP.Utils
{/// <summary>/// 添加一个image控件,并实现拖动效果/// </summary>public class MoveImage{#region 字段private int m_ZIndex;/// <summary>/// 当前图章的位置/// </summary>/// /// <summary>/// 旋转图标的起始位置/// </summary>private Point m_ImageRoundStartOffset;/// <summary>/// 旋转图标的当前位置/// </summary>private Point m_ImageRoundOffset;/// <summary>/// 标识图章是否被拖拽/// </summary>private bool m_IsDragging;/// <summary>/// 标识旋转图标是否被是否被拖拽/// </summary>private bool m_IsimageRoundDragging;/// <summary>/// 图章的父容器/// </summary>public Canvas ContainerCanvas { get; set; }/// <summary>/// 图章图片/// </summary>private Image m_FlogImage;/// <summary>/// 旋转按钮图片/// </summary>private Image m_RotateImage;/// <summary>/// 图章和旋转图片的容器/// </summary>private Grid m_MoveImageGrid;/// <summary>/// 选转/// </summary>private RotateTransform m_ImageRotate;/// <summary>/// 缩放/// </summary>private ScaleTransform m_ImageScale;/// <summary>/// 上次位置/// </summary>private Point m_OldPos;#endregionpublic MoveImage(){ }/// <summary>/// 创建一个图标/// </summary>/// <param name="position">图标的位置</param>public void CreateImage(Point position){#region 设置布局m_FlogImage = new Image{//Width = 100,//Height = 100,Source = new BitmapImage(new Uri("/Images/shuzi.jpg", UriKind.RelativeOrAbsolute))};m_RotateImage = new Image{Width = 20,Height = 20,Source = new BitmapImage(new Uri("/Images/round.jpg", UriKind.RelativeOrAbsolute))};m_RotateImage.HorizontalAlignment = HorizontalAlignment.Right;m_RotateImage.VerticalAlignment = VerticalAlignment.Bottom;m_RotateImage.Visibility = Visibility.Hidden;m_MoveImageGrid = new Grid();m_MoveImageGrid.Width = 110;m_MoveImageGrid.Height = 110;m_MoveImageGrid.Children.Add(m_FlogImage);m_MoveImageGrid.Children.Add(m_RotateImage);m_MoveImageGrid.MouseEnter += RootGridMouseEnter;m_MoveImageGrid.MouseLeave += RootGridMouseLeave;m_RotateImage.MouseLeftButtonDown += imageRound_MouseLeftButtonDown;m_RotateImage.MouseMove += imageRound_MouseMove;m_RotateImage.MouseLeftButtonUp += imageRound_MouseLeftButtonUp;// Image in den Vordergrund bringenCanvas.SetZIndex(m_MoveImageGrid, m_ZIndex++);#endregion// Event Handler für das Image installierenm_MoveImageGrid.MouseLeftButtonDown += RootGridMouseLeftButtonDown;m_MoveImageGrid.MouseLeftButtonUp += RootGridMouseLeftButtonUp;m_MoveImageGrid.MouseMove += RootGridMouseMove;// Image leicht transparent machenm_MoveImageGrid.Opacity = 0.8;m_ImageRotate = new RotateTransform(0, 0, 0);m_ImageScale = new ScaleTransform();//m_ImageScale.ScaleX = 1;//m_ImageScale.ScaleY = 1;TransformGroup transformGroup = new TransformGroup();transformGroup.Children.Add(m_ImageRotate);transformGroup.Children.Add(m_ImageScale);m_MoveImageGrid.RenderTransform = transformGroup;//m_ImageScale111 = new ScaleTransform();//m_ImageScale111.ScaleX = 0.5;//m_ImageScale111.ScaleY = 0.5;//imageRound.RenderTransform = m_ImageScale111;m_MoveImageGrid.RenderTransformOrigin = new Point(0.5, 0.5);// Image positionierenvar pos = position;Canvas.SetLeft(m_MoveImageGrid, pos.X - (m_MoveImageGrid.Width / 2));Canvas.SetTop(m_MoveImageGrid, pos.Y - (m_MoveImageGrid.Height / 2));// Image zum Canvas hinzufügenContainerCanvas.Children.Add(m_MoveImageGrid);}/// <summary>/// 控制旋转图标隐藏/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void RootGridMouseLeave(object sender, MouseEventArgs e){m_RotateImage.Visibility = Visibility.Hidden;}/// <summary>/// 控制选择图标显示/// </summary>/// <param name="sender"></param>/// <param name="e"></param>private void RootGridMouseEnter(object sender, MouseEventArgs e){m_RotateImage.Visibility = Visibility.Visible;}#region 控制盖章的移动private void RootGridMouseMove(object sender, MouseEventArgs e){if (m_IsDragging){var pos = e.GetPosition(ContainerCanvas);Canvas.SetLeft(m_MoveImageGrid, Canvas.GetLeft(m_MoveImageGrid) + pos.X - m_OldPos.X);Canvas.SetTop(m_MoveImageGrid, Canvas.GetTop(m_MoveImageGrid) + pos.Y - m_OldPos.Y);m_OldPos = pos;}}private void RootGridMouseLeftButtonUp(object sender, MouseButtonEventArgs e){var grid = sender as Grid;// Canvas.SetZIndex(image, m_ZIndex++);// Bild wieder leicht transparent machengrid.Opacity = 0.8;grid.ReleaseMouseCapture();m_IsDragging = false;}private void RootGridMouseLeftButtonDown(object sender, MouseButtonEventArgs e){var grid = sender as Grid;// auf "nicht"-transparent setzengrid.Opacity = 1;// Position des Pointers relativ zum Bild speichernm_OldPos = e.GetPosition(ContainerCanvas);// isDragging auf true setzen für MouseMovem_IsDragging = true;// Image in den Vordergrund bringenCanvas.SetZIndex(grid, PhotoEditHelper.CommomMaxZIndex++);// Den Pointer einfangen. Bei schnellen Bewegungen kann der// Pointer aus dem Image bewegt werden. Damit die Pointer-// Events weiterhin stattfinden, wird der Pointer eingefangen.  grid.CaptureMouse();// als behandelt markieren, damit nicht noch der// PointerPressed-Event Handler des Canvas aufgerufen wird.e.Handled = true;}#endregion#region 控制图章的旋转private void imageRound_MouseLeftButtonUp(object sender, MouseButtonEventArgs e){var image = sender as Image;m_MoveImageGrid.Opacity = 1;image.ReleaseMouseCapture();m_IsimageRoundDragging = false;}private void imageRound_MouseMove(object sender, MouseEventArgs e){if (m_IsimageRoundDragging){//鼠标当前点的坐标m_ImageRoundOffset = e.GetPosition(ContainerCanvas);m_ImageScale.ScaleX =m_ImageScale.ScaleY = GetLength(currCenter, m_ImageRoundStartOffset, m_ImageRoundOffset);m_ImageRotate.Angle = GetAngle(currCenter, m_ImageRoundStartOffset, m_ImageRoundOffset) - 45;}}private Point currCenter;private void imageRound_MouseLeftButtonDown(object sender, MouseButtonEventArgs e){var image = sender as Image;m_MoveImageGrid.Opacity = 1;//中心点坐标currCenter = new Point(Canvas.GetLeft(m_MoveImageGrid) + m_MoveImageGrid.Width / 2, Canvas.GetTop(m_MoveImageGrid) + m_MoveImageGrid.Height / 2);m_ImageRoundStartOffset = new Point(currCenter.X + m_MoveImageGrid.Width / 2, currCenter.Y);m_IsimageRoundDragging = true;Canvas.SetZIndex(m_MoveImageGrid, PhotoEditHelper.CommomMaxZIndex++);image.CaptureMouse();e.Handled = true;}/// 根据余弦定理求两个线段夹角/// </summary>  /// <param name="origin">原点</param>  /// <param name="start">start点</param>  /// <param name="end">end点</param>  /// <returns></returns>  private double GetAngle(Point origin, Point start, Point end){double cosfi = 0, fi = 0, norm = 0;double dsx = start.X - origin.X;double dsy = start.Y - origin.Y;double dex = end.X - origin.X;double dey = end.Y - origin.Y;cosfi = dsx * dex + dsy * dey;norm = (dsx * dsx + dsy * dsy) * (dex * dex + dey * dey);if (norm == 0) return 0; // origin和end坐标一样cosfi /= Math.Sqrt(norm);if (cosfi >= 1.0) return 0;if (cosfi <= -1.0) return 180;fi = Math.Acos(cosfi);double angle = 180 * fi / Math.PI;if (dey > 0){return angle;}return -angle;}private double GetLength(Point origin, Point start, Point end){double dex = end.X - origin.X;double dey = end.Y - origin.Y;double dsx = start.X - origin.X;double dsy = start.Y - origin.Y;double startLength = Math.Sqrt(Math.Pow(dsx, 2) + Math.Pow(dsy, 2));double endLength = Math.Sqrt(Math.Pow(dex, 2) + Math.Pow(dey, 2));return endLength / startLength;}#endregion}

效果图:

转载于:https://www.cnblogs.com/shanranlei/p/3635412.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/460473.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【一周一算法】算法2:邻居好说话——冒泡排序

【啊哈&#xff01;算法】    简化版的桶排序不仅仅有上一节所遗留的问题&#xff0c;更要命的是&#xff1a;它非常浪费空间&#xff01;例如需要排序数的范围是0~2100000000之间&#xff0c;那你则需要申请2100000001个变量&#xff0c;也就是说要写成int a[2100000001]。…

用TextPaint来绘制文字

TextPaint是paint的子类&#xff0c;用它可以很方便的进行文字的绘制&#xff0c;一般情况下遇到绘制文字的需求时&#xff0c;我们一般用TextPaint所提供的方法。开始学习如何绘制文字之前&#xff0c;我们必须要先了解下android中文字是怎么绘制到屏幕上的&#xff0c;文字的…

存储过程——介绍(一)

由于工作缘故&#xff0c;在工作中用到储存过程较少&#xff0c;在下班之余出于对学习的热情&#xff0c;以下分享下学习储存过程心得&#xff0c;往大牛们指点迷津&#xff1a; 储存过程&#xff1a;官方解释为可以将一些预先编译的sql语句集中起来有sql service数据库服务器来…

第二季5:配置视频捕获模块(step3:VI模块)

以下内容源于朱有鹏嵌入式课程的学习与整理&#xff0c;如有侵权请告知删除。 前言 本文将详细介绍博文第二季3&#xff1a;sample_venc.c的整体分析提及的“配置视频捕获模块”。 分析方法上&#xff0c;我们首先介绍VI模块相关的宽动态、设备、通道等概念&#xff0c;然后…

简化Java中的异常处理

为什么80%的码农都做不了架构师&#xff1f;>>> #1. 不需要Checked异常 Java中的Checked异常&#xff0c;可以说有弊无利&#xff0c;它除了能带来一系列的麻烦&#xff0c;能干的事情Unchecked异常都能干。 ##1.1. 代码污染 首先&#xff0c;当一个方法声明抛出一…

Linux常用命令之wget

wget&#xff1a;从网络上下载文件到当前目录。 转载于:https://www.cnblogs.com/nufangrensheng/p/3646055.html

Serv-U搭建FTP服务器

1、打开软件&#xff0c;勾选start automatically 2、点击domain&#xff0c;新建domain 3、依次输入IP、端口号、域名、域名类型 完成后的样子 4、右键单击Users&#xff0c;新建用户。依次输入用户名、Home目录、用户密码。 如果需要创建匿名账户&#xff0c;则用户名用Anony…

第二季7:创建配置编码通道(step5:VENC部分)

以下内容源于朱有鹏嵌入式课程的学习与整理&#xff0c;如有侵权请告知删除。 前言 本文将详细介绍博文第二季3&#xff1a;sample_venc.c的整体分析提及的“创建配置编码通道”。 我们首先介绍VENC模块相关的概念&#xff0c;然后绘制该模块的函数调用关系图谱&#xff0c;…

hdu 1176 馅饼

略微简单的动态规划 只是简单贴代码就好了。 #include <stdio.h> #include <string.h>int dp[100007][11]; int ans[100007][11]; int n,N;inline int Max(int x,int c){return x>c?x:c; } int v[16]; void DP() {int i,j;memset(v,0,sizeof(v));memset(ans,0,…

iOS开发-Get请求,Post请求,同步请求和异步请求

标题中的Get和Post是请求的两种方式&#xff0c;同步和异步属于实现的方法&#xff0c;Get方式有同步和异步两种方法&#xff0c;Post同理也有两种。稍微有点Web知识的&#xff0c;对Get和Post应该不会陌生&#xff0c;常说的请求处理响应&#xff0c;基本上请求的是都是这两个…

新浪微博之XSS蠕虫脚本源码讲解

主要是因为新浪的广场页面有几个链接对输入参数过滤不严导致的反射性XSS。 微博XSS漏洞点 weibo.com/pub/star/g/xyyyd%22%3e%3cscript%20src//www.****.com/images/t.js%3e%3c/script%3e?typeupdate 微博XSS脚本内容(XSS源码)function createXHR(){ return window.XMLHttpRe…

Wireshark下载安装和使用教程

本文转载于Wireshark下载安装和使用教程。 Wireshark&#xff08;前身 Ethereal&#xff09;是一个网络包分析工具。该工具主要是用来捕获网络数据包&#xff0c;并自动解析数据包&#xff0c;为用户显示数据包的详细信息&#xff0c;供用户对数据包进行分析。它可以运行在 Wi…

Cortex-M3 动态加载一(地址无关代码实现)

这篇文章是自己疑惑究竟地址无关性是如何实现&#xff0c;然后查看汇编和CPU指令手册&#xff0c;最后分析解除自己疑惑的&#xff0c;高手不要鄙视&#xff0c;哈哈。 编译C代码时候需要制定--acps/ropi选项&#xff0c;如下例子&#xff1a; 1 void SystemInit(void)2 {3 }4 …

C#使用Log4Net记录日志【转】

第一步&#xff1a;下载Log4Net 下载地址&#xff1a;http://logging.apache.org/log4net/download_log4net.cgi 把下载的 log4net-1.2.11-bin-newkey解压后&#xff0c;如下图所示&#xff1a; 双击bin文件夹 双击net文件夹&#xff0c;选择针对.NET FramerWork的不同版本 找…

Map实现之HashMap(结构及原理)(转)

java.util包中的集合类包含 Java 中某些最常用的类。最常用的集合类是 List 和 Map。List 的具体实现包括 ArrayList 和 Vector&#xff0c;它们是可变大小的列表&#xff0c;比较适合构建、存储和操作任何类型对象元素列表。List 适用于按数值索引访问元素的情形。 Map 则提供…

mysql对表中添加属性_菜鸟笔记—数据分析师MySQL篇(一)

简单说一下我写这份学习笔记的原因&#xff0c;由于工作的原因&#xff0c;想换一份工作&#xff0c;对于毕业已经快6年了&#xff0c;再次重新学习就需要付出很大的勇气和努力&#xff0c;如果态度还不能及时调整&#xff0c;最近找工作遇到的窘境就不言而喻了。去年底报了一个…

matlab打开笔记本摄像头_如何解决笔记本电脑摄像头异常问题

如果您遇到笔记本电脑相机异常问题(无法侦测视讯装置、视讯无画面、视讯画面异常、视讯画面颠倒等等)&#xff0c;请参考以下疑难解答方式依序尝试。提供应用程序权限 / 检查防病毒软件/ 更新Windows Update / 更新相机驱动程序/透过系统还原点还原系统/ 系统还原1. 提供应用程…

边框颜色为 tintColor 的 UIButton

创建一个 UIButton 的子类&#xff0c;重写其方法&#xff1a; - (void)drawRect:(CGRect)rect {[[self layer] setCornerRadius:CORNER_RADIUS];[[self layer] setMasksToBounds:YES]; [[self layer] setBorderWidth:1];[[self layer] setBorderColor:self.tintColor.CGColo…

netty SimpleChannelInboundHandler类继承使用

2019独角兽企业重金招聘Python工程师标准>>> 继承一个SimpleChannelInboundHandler来实现我们的Client&#xff0c;我们需要重写其中的三个方法&#xff1a; package NettyDemo.echo.handler;import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; …

高中关于人工智能方面的课题_如何看待计算机专业开始设置人工智能课程

首先&#xff0c;当前计算机专业当中设置与人工智能相关的课程是一个必然的趋势&#xff0c;随着人工智能技术开始逐渐实现落地应用&#xff0c;未来计算机相关专业的课程当中&#xff0c;人工智能课程的比重也会逐渐提升&#xff0c;而且一定要重视这些课程&#xff0c;这对于…