制作一个用户头像选择器仿 WeGame

 制作一个用户头像选择器仿 WeGame

CropAvatar

作者:WPFDevelopersOrg - 驚鏵

原文链接:https://github.com/WPFDevelopersOrg/WPFDevelopers

  • 框架使用.NET40

  • Visual Studio 2019;

  • 制作一个用户头像选择Canvas为父控件所实现,展示图片使用ImagePath当作上方的蒙版;

  • Canvas:主要用途方便移动Image,设置ClipToBounds="True"裁剪为一个正方形200x200做为主要展示区域;

  • Image:展示需要裁剪的图片;

c9b07db74e5383aeeabc61af6135cfa7.png
  • Path:CombinedGeometry[1]绘制蒙版大小200x200效果如下;

bf0fe795785019aa7512bdf50942cf13.png
  • 当选择一个本地图片的时候判断宽与高谁更大,谁小就将它更改为200 ,另一边做等比缩放后给到DrawingVisual绘制一个新的BitmapFrame[2]Image控件做展示;

  • 当移动图片的时候右侧展示当前区域使用CroppedBitmap[3]进行裁剪并显示;

  • 源码Github[4]Gitee[5]

cd67c09d9712dfb1349e510628b4379c.gif1)CropAvatar.xaml 代码如下;

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:controls="clr-namespace:WPFDevelopers.Controls"><ResourceDictionary.MergedDictionaries><ResourceDictionary Source="Basic/ControlBasic.xaml"/></ResourceDictionary.MergedDictionaries><Style TargetType="controls:CropAvatar" BasedOn="{StaticResource ControlBasicStyle}"><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="{x:Type controls:CropAvatar}"><Canvas x:Name="PART_Canvas" ClipToBounds="True"><Image x:Name="PART_Image" Cursor="SizeAll" ></Image><Path x:Name="PART_Layout" Fill="{DynamicResource BlackSolidColorBrush}" Width="200" Height="200" Opacity=".5"><Path.Data><CombinedGeometry GeometryCombineMode="Xor"><CombinedGeometry.Geometry1><RectangleGeometry Rect="0,0,200,200"/></CombinedGeometry.Geometry1><CombinedGeometry.Geometry2><EllipseGeometry Center="100,100" RadiusX="100" RadiusY="100"/></CombinedGeometry.Geometry2></CombinedGeometry></Path.Data></Path><Grid x:Name="PART_Grid" Width="200" Height="200"><Button x:Name="PART_ReplaceButton" Style="{StaticResource PathButton}"HorizontalAlignment="Right"VerticalAlignment="Top"Width="40" Height="40" ToolTip="更换图片"Visibility="Collapsed"><Button.Content><Path Data="{StaticResource PathReplace}"Fill="{StaticResource PrimaryNormalSolidColorBrush}"Height="15"Width="15"Stretch="Fill" /></Button.Content></Button><Button x:Name="PART_AddButton" Style="{StaticResource PathButton}"Width="40" Height="40" ToolTip="选择图片"><Button.Content><Path Data="{StaticResource PathAdd}"Fill="{StaticResource PrimaryNormalSolidColorBrush}"Height="20"Width="20"Stretch="Fill" RenderTransformOrigin="0.5,0.5" IsHitTestVisible="False"><Path.RenderTransform><RotateTransform Angle="45"/></Path.RenderTransform></Path></Button.Content></Button></Grid></Canvas></ControlTemplate></Setter.Value></Setter></Style></ResourceDictionary>

2)CropAvatar.cs 代码如下;

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using WPFDevelopers.Helpers;namespace WPFDevelopers.Controls
{[TemplatePart(Name = CanvasTemplateName, Type = typeof(Canvas))][TemplatePart(Name = ImageTemplateName, Type = typeof(Image))][TemplatePart(Name = PathTemplateName, Type = typeof(Path))][TemplatePart(Name = GridTemplateName, Type = typeof(Grid))][TemplatePart(Name = ReplaceButtonTemplateName, Type = typeof(Button))][TemplatePart(Name = AddButtonTemplateName, Type = typeof(Button))]public partial class CropAvatar : Control{private const string CanvasTemplateName = "PART_Canvas";private const string ImageTemplateName = "PART_Image";private const string PathTemplateName = "PART_Layout";private const string GridTemplateName = "PART_Grid";private const string ReplaceButtonTemplateName = "PART_ReplaceButton";private const string AddButtonTemplateName = "PART_AddButton";private Point point;private const int _size = 200;private bool isDown;private bool isLeft;private CroppedBitmap crop;private Canvas canvas;private Image image;private Path path;private Grid grid;private Button replaceButton, addButton;private int initialX, initialY, voffsetX, voffsetY;private double vNewStartX, vNewStartY, _StartX, _StartY, centerX, centerY;private BitmapFrame bitmapFrame;public ImageSource OutImageSource{get { return (ImageSource)GetValue(OutImageSourceProperty); }set { SetValue(OutImageSourceProperty, value); }}public static readonly DependencyProperty OutImageSourceProperty =DependencyProperty.Register("OutImageSource", typeof(ImageSource), typeof(CropAvatar), new PropertyMetadata(null));static CropAvatar(){DefaultStyleKeyProperty.OverrideMetadata(typeof(CropAvatar), new FrameworkPropertyMetadata(typeof(CropAvatar)));}public override void OnApplyTemplate(){base.OnApplyTemplate();canvas = GetTemplateChild(CanvasTemplateName) as Canvas;canvas.Loaded += Canvas_Loaded;grid = GetTemplateChild(GridTemplateName) as Grid;image = GetTemplateChild(ImageTemplateName) as Image;image.MouseDown += Image_MouseDown;image.MouseMove += Image_MouseMove;image.MouseUp += Image_MouseUp;image.MouseLeave += Image_MouseLeave;path = GetTemplateChild(PathTemplateName) as Path;replaceButton = GetTemplateChild(ReplaceButtonTemplateName) as Button;replaceButton.Click += ReplaceButton_Click;addButton = GetTemplateChild(AddButtonTemplateName) as Button;addButton.Click += AddButton_Click;}private void Canvas_Loaded(object sender, RoutedEventArgs e){if (sender is Canvas canvas){var width = canvas.ActualWidth;var height = canvas.ActualHeight;centerX = (width - path.Width) / 2.0d;centerY = (height - path.Height) / 2.0d;canvas.Clip = new RectangleGeometry(new Rect(centerX, centerY, 200, 200)); Canvas.SetLeft(path, centerX);Canvas.SetTop(path, centerY);Canvas.SetLeft(grid, centerX);Canvas.SetTop(grid, centerY);}}private void Image_MouseLeave(object sender, MouseEventArgs e){isDown = false;if (isLeft)_StartX = Canvas.GetLeft(image);else_StartY = Canvas.GetTop(image);}private void Image_MouseUp(object sender, MouseButtonEventArgs e){if (isDown){var vPoint = e.GetPosition(this);if (isLeft){_StartX = Canvas.GetLeft(image);initialX = voffsetX;}else{_StartY = Canvas.GetTop(image);initialY = voffsetY;}}}private void Image_MouseMove(object sender, MouseEventArgs e){if (e.LeftButton == MouseButtonState.Pressed && isDown){var vPoint = e.GetPosition(this);if (isLeft){var voffset = vPoint.X - point.X;vNewStartX = _StartX + voffset;var xPath = Canvas.GetLeft(path);if (vNewStartX <= xPath && vNewStartX >= -(bitmapFrame.Width - 200 - xPath)){Canvas.SetLeft(image, vNewStartX);voffsetX = initialX - (int)voffset;voffsetX = voffsetX < 0 ? 0 : voffsetX;crop = new CroppedBitmap(bitmapFrame, new Int32Rect(voffsetX, 0, _size, _size));}}else{var voffset = vPoint.Y - point.Y;vNewStartY = _StartY + voffset;var yPath = Canvas.GetTop(path);if (vNewStartY <= yPath && vNewStartY >= -(bitmapFrame.Height - 200 - yPath)){Canvas.SetTop(image, vNewStartY);voffsetY = initialY - (int)voffset;voffsetY = voffsetY < 0 ? 0 : voffsetY;crop = new CroppedBitmap(bitmapFrame, new Int32Rect(0, voffsetY, _size, _size));}}OutImageSource = crop;}}private void Image_MouseDown(object sender, MouseButtonEventArgs e){isDown = true;point = e.GetPosition(this);}private void ReplaceButton_Click(object sender, RoutedEventArgs e){InitialImage();}private void AddButton_Click(object sender, RoutedEventArgs e){InitialImage();}void InitialImage(){vNewStartX = 0;vNewStartY = 0;var uri = ControlsHelper.ImageUri();if (uri == null) return;var bitmap = new BitmapImage(uri);if (bitmap.Height > bitmap.Width){double scale = (double)bitmap.Width / (double)path.Width;image.Width = _size;image.Height = (double)bitmap.Height / scale;isLeft = false;}else if (bitmap.Width > bitmap.Height){double scale = (double)bitmap.Height / (double)path.Height;image.Width = (double)bitmap.Width / scale;image.Height = _size;isLeft = true;}bitmapFrame = ControlsHelper.CreateResizedImage(bitmap, (int)image.Width, (int)image.Height, 0);image.Source = bitmapFrame;if (image.Source != null){replaceButton.Visibility = Visibility.Visible;addButton.Visibility = Visibility.Collapsed;}Canvas.SetLeft(grid, centerX);Canvas.SetTop(grid, centerY);_StartX = (canvas.ActualWidth - image.Width) / 2.0d;_StartY = (canvas.ActualHeight - image.Height) / 2.0d;Canvas.SetLeft(image, _StartX);Canvas.SetTop(image, _StartY);        if (isLeft){initialX = (int)(image.Width - 200) / 2;initialY = 0;crop = new CroppedBitmap(bitmapFrame, new Int32Rect(initialX, 0, _size, _size));}else{initialY = (int)(image.Height - 200) / 2;initialX = 0;crop = new CroppedBitmap(bitmapFrame, new Int32Rect(0, initialY, _size, _size));}OutImageSource = crop;}}
}

3)CropAvatarWindow.xaml使用如下;

<ws:Window x:Class="WPFDevelopers.Samples.ExampleViews.CropAvatarWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:wpfdev="https://github.com/WPFDevelopersOrg/WPFDevelopers"xmlns:ws="https://github.com/WPFDevelopersOrg.WPFDevelopers.Minimal"mc:Ignorable="d"  WindowStyle="ToolWindow" ResizeMode="NoResize"WindowStartupLocation="CenterScreen"Title="WPF 开发者-头像选择器" Height="450" Width="800"><Grid><Grid.ColumnDefinitions><ColumnDefinition/><ColumnDefinition/></Grid.ColumnDefinitions><Grid.RowDefinitions><RowDefinition/><RowDefinition Height="Auto"/></Grid.RowDefinitions><wpfdev:CropAvatar x:Name="MyCropAvatar"/><Image Grid.Column="1" Name="CropAvatarImage" Source="{Binding ElementName=MyCropAvatar,Path=OutImageSource}" Stretch="Fill" Width="200" Height="200"><Image.Clip><EllipseGeometry Center="100,100" RadiusX="100" RadiusY="100"/></Image.Clip></Image><UniformGrid Grid.Row="1" Grid.ColumnSpan="2" HorizontalAlignment="Center" VerticalAlignment="Center"><Button  Content="保存" Click="btnSave_Click" Style="{StaticResource PrimaryButton}" Margin="4,0"/><Button  Content="关闭" Click="btnClose_Click" Margin="4,0"/></UniformGrid></Grid>
</ws:Window>

4) CropAvatarWindow.xaml.cs 代码如下;

using System.Windows;namespace WPFDevelopers.Samples.ExampleViews
{/// <summary>/// CropAvatarWindow.xaml 的交互逻辑/// </summary>public partial class CropAvatarWindow {public CropAvatarWindow(){InitializeComponent();}private void btnSave_Click(object sender, RoutedEventArgs e){DialogResult = true;}private void btnClose_Click(object sender, RoutedEventArgs e){DialogResult = false;}}
}

5) CropAvatarExample.xaml 使用如下;

<UserControl x:Class="WPFDevelopers.Samples.ExampleViews.CropAvatarExample"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:wpfdev="https://github.com/WPFDevelopersOrg/WPFDevelopers"xmlns:local="clr-namespace:WPFDevelopers.Samples.ExampleViews"mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800"><Grid><Grid.ColumnDefinitions><ColumnDefinition/><ColumnDefinition/></Grid.ColumnDefinitions><Button Content="图像选择器" VerticalAlignment="Center" HorizontalAlignment="Center" Click="Button_Click"/><Image Grid.Column="1" Name="MyImage"Stretch="Fill" Width="200" Height="200"><Image.Clip><EllipseGeometry Center="100,100" RadiusX="100" RadiusY="100"/></Image.Clip></Image></Grid>
</UserControl>

6) CropAvatarExample.xaml.cs 代码如下;

using System.Windows.Controls;namespace WPFDevelopers.Samples.ExampleViews
{/// <summary>/// CropAvatarExample.xaml 的交互逻辑/// </summary>public partial class CropAvatarExample : UserControl{public CropAvatarExample(){InitializeComponent();}private void Button_Click(object sender, System.Windows.RoutedEventArgs e){var cropAvatarWindow = new CropAvatarWindow();if (cropAvatarWindow.ShowDialog() == true){MyImage.Source = cropAvatarWindow.CropAvatarImage.Source;}}}
}

参考资料

[1]

CombinedGeometry: https://docs.microsoft.com/zh-cn/dotnet/api/system.windows.media.combinedgeometry?view=netframework-4.0

[2]

BitmapFrame: https://docs.microsoft.com/zh-cn/dotnet/api/system.windows.media.imaging.bitmapframe?view=windowsdesktop-6.0

[3]

CroppedBitmap: https://docs.microsoft.com/zh-cn/dotnet/api/system.windows.media.imaging.croppedbitmap?view=windowsdesktop-6.0

[4]

Github: https://github.com/WPFDevelopersOrg/WPFDevelopers

[5]

Gitee: https://gitee.com/WPFDevelopersOrg/WPFDevelopers

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

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

相关文章

PS2019进阶笔记(二)

云端网校笔记&#xff08;PS2015&#xff09; 一、图层混合模式 图层面板上的左上角&#xff0c;默认正常 混合下面图层&#xff0c;下面正片&#xff08;如模特&#xff09;。 最常用是&#xff1a;不透明度 溶解&#xff1a;需调节透明度 变暗组&#xff1a; 亮区域去除…

Html5里frameSet不在使用的替代方法,使用ifram

原来得使用方式&#xff1a; <frameset rows"100,*" frameborder"0"><frame name"header" src"header.aspx"></frame><frameset cols"15%, *"><frame name"menu" src"left.aspx&…

网曝南方电网搞末位淘汰和裁员,给各下属单位强制规定辞退率和降岗降级率!...

电网作为垄断性国企&#xff0c;在人们心中一向是好单位的代名词&#xff0c;但最近却有网友曝光南方电网搞末位淘汰和裁员&#xff0c;给各单位下了辞退率和降岗降级率&#xff0c;每个单位都要开除一部分人&#xff0c;或者把一部分人岗级降下来。有南方电网员工马上跑出来辟…

二维数组中的查找

2019独角兽企业重金招聘Python工程师标准>>> 题目 在一个二维数组中&#xff0c;每一行中的数都按照从左到右、从上到下的递增顺序排列。要求输入一个整数&#xff0c;判断数组中是否存在该整数 实现代码 function find($matrix, $rows, $columns, $key) {//TODO 参…

C# JObject转换JSON文件相关处理

一、JObject.Parse 1.把整个json文件字符串转化成JObject格式。 JObject jsonData JObject.Parse(jsonString); 2.逐级转换成JObject 最低级是"Device": "Windowsr"&#xff0c;字典。 jsonData JObject.Parse(jsonData[jsonName][jsonIndex].ToStr…

通过修改然后commit的方式创建自己的镜像

创建自己的镜像&#xff1a;通过现有的镜像来创建自己的镜像。1、首先拉取一个镜像到本地$ sudo docker imagesREPOSITORY TAG IMAGE ID CREATED SIZEubuntu 12.04 5b117edd0b76 11 months…

hdu6103[尺取法] 2017多校6

/*hdu6103[尺取法] 2017多校6*/ #include <bits/stdc.h> using namespace std; int T, m; char str[20005]; void solve() {int ans 0;int n strlen(str);for (int i 0; i < n; i) {int l 0, r 0, p1 i, p2 i 1, cost 0;while (p1 - r > 0 && p2 …

蓝牙追踪_如何使用蓝牙追踪器跟踪您的东西

蓝牙追踪We’ve all done it: you misplace something important and you spend a lot of time (with a lot of stress) backtracking to locate it again. With Bluetooth tracking devices you can make the hunt a lot easier, less stressful, and even avoid losing the t…

远程访问CENTOS的MYSQL数据库设置

远程访问CENTOS的MYSQL数据库设置 mysql -u root grant all privileges on *.* to root%identified by root; 后面的root是root用户的密码 grant all privileges on *.* to rootlocalhostidentified by root; mysql -u root -p

ShardingCore 7.0 版本发布

NCC ShardingCore 是一款 EntityFramework Core based 高性能、轻量级、分表分库、读写分离解决方案&#xff0c;具有零依赖、零学习成本、零业务代码入侵等特点。ShardingCore 7.0 已于近期发布。从 ShardingCore 7.0 开始&#xff0c;启用版本号第二位来对应不同的 EFCore 版…

搬运 centos7.2 apache 绑定二级目录 访问依然是apache页面

<VirtualHost *:80>ServerName xx.comDocumentRoot /var/www/html/xx</VirtualHost> 转载于:https://www.cnblogs.com/kiimi/p/8662490.html

django09: ORM以及CSRF(旧笔记)

ORM相当于程序里的数据库操作 ORM(一) https://www.cnblogs.com/liwenzhou/p/8688919.html ORM(二) https://www.cnblogs.com/liwenzhou/p/8660826.html CSRF:防止网站请求伪造&#xff0c;即钓鱼网 在Form表达添加&#xff1a;{% csrf_toker %}

vba发送邮件 签名_如何更改“从Windows 10的邮件发送”签名

vba发送邮件 签名The Windows 10 Mail app is a decent email client that allows you to add other email accounts in addition to your Microsoft accounts. You’ll notice, though, that any emails you write in the Mail app have a default signature. Windows 10 Mail…

JAVA_SE基础——24.面向对象的内存分析

黑马程序猿入学blog ... 接着上一章的代码&#xff1a; //车类 class Car{//事物的公共属性使用成员变量描写叙述。String name; //名字的属性 String color; //颜色属性 int wheel; //轮子数 //事物的公共行为使用函数描写叙述。 public void run(){ System.out.println(name&…

煮茶社区AVR开发板第二版[转]

原图:http://blossom.cnblogs.com/gallery/image/21891.html

[Kogel.Subscribe.Mssql]SQL Server增量订阅,数据库变更监听

此框架是SQL Server增量订阅&#xff0c;用来监听增删改数据库数据变更目前仅支持SQL Server&#xff0c;后续会支持MySQL和Oracle&#xff0c;Nuget上可以下载安装或者使用Nuget命令添加包dotnet add package Kogel.Subscribe.Mssql --version 0.0.0.1可以用来处理DB主从同步&…

java instanceof运算符

instanceof 运算符 该运算符用于操作对象实例&#xff0c;检查该对象是否是一个特定类型&#xff08;类类型或接口类型&#xff09;。 instanceof运算符使用格式如下&#xff1a; ( Object reference variable ) instanceof (class/interface type) 如果运算符左侧变量所指的对…

C# XML添加删除/SelectNodes/xpath

SelectNodes中的XPath //从当前节点的儿子节点中选择名称为 item 的节点。 SelectNodes("item")//从根节点的儿子节点中选择名称为 item 的节点。 SelectNodes("/item")// 从任意位置的节点上选择名称为 item 的节点。要重点突出这个任意位置&#xff0c;…

Python中*args 和**kwargs的用法

http://blog.csdn.net/chenjinyu_tang/article/details/8136841 好久没有学习python了&#xff0c;应为工作的需要&#xff0c;再次拾起python&#xff0c;唤起记忆。 当函数的参数不确定时&#xff0c;可以使用*args 和**kwargs&#xff0c;*args 没有key值&#xff0c;**kwar…

MFC载入JPG图片

## 1.定义画图函数 HRESULT CIPCamDlg::draw(char *lpImageFile, HWND hWnd, int nScrWidth, int nScrHeight) {HDC hDC_Temp::GetDC(hWnd);IPicture *pPic; IStream *pStm;BOOL bResult;HANDLE hFileNULL; DWORD dwFileSize,dwByteRead;hFileCreateFile(lpImageFile,GENERIC_R…