原文:WPF 自定义图片剪切器 - 头像剪切(扩展与完善、实时截图)

一、说明:上一次写的WPF
自定义图片剪切器 - 头像剪切。你懂得
存在明显的缺陷,由于篇幅较长。重新写了一篇新的。

问题的原因:由于是对图片文件进行剪切处理,当图片加载后变形的话,处理起来明显的有错误!

解决办法:重新计算比例。但是有个问题就是在原来的基础上重新计算,计算量会相当复杂。因为整个截图区域就那么大,是固          定的,而图片可大可小,你要是想正确获取加载后的图片与截图区域的比例将会变得相当麻烦。

所以,本次采用一个最基本的设计技巧,就是 截图区域 = 图片加载后的区域 !将截图控件ImageDealerUnsafe按照大小可变化的情况封装在自定义控件ImageDealer里,通过自定义控件ImageDealer封装截图控件的调用接口,而ImageDealerUnsafe。

二、关于截图控件(ImageDealerUnsafe)  用户不应调用该控件的任何方法、仅供ImageDealer调用

1、截图控件 ImageDealerUnsafe XAML

  1. <UserControl x:Class="DialogEx.Controls.Unsafe.ImageDealerUnsafe"
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  5. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  6. mc:Ignorable="d"
  7. d:DesignHeight="300" d:DesignWidth="300" Background="Transparent"
  8. SnapsToDevicePixels="True"
  9. PreviewMouseDown="UserControl_MouseDown" PreviewMouseUp="UserControl_MouseUp" MouseLeave="UserControl_MouseLeave" PreviewMouseMove="UserControl_MouseMove"
  10. >
  11. <Grid Name="MainGrid" >
  12. <Image Name="SoureceImage" Stretch="Uniform"></Image>
  13. <Border Name="ImageArea" BorderBrush="Red" BorderThickness="1,1,1,1" Panel.ZIndex="5" Margin="50" SizeChanged="ImageArea_SizeChanged">
  14. <Grid >
  15. <Rectangle Name="R_LeftUp" Width="5" Height="5" Margin="-3" VerticalAlignment="Top" HorizontalAlignment="Left" Fill="White" Panel.ZIndex="0" Cursor="SizeNWSE"/>
  16. <Rectangle Name="R_Up" Width="5" Height="5" Margin="-3" VerticalAlignment="Top" HorizontalAlignment="Center" Fill="White" Panel.ZIndex="0" Cursor="SizeNS"/>
  17. <Rectangle Name="R_RightUp" Width="5" Height="5" Margin="-3" VerticalAlignment="Top" HorizontalAlignment="Right" Fill="White" Panel.ZIndex="0" Cursor="SizeNESW"/>
  18. <Rectangle Name="R_Right" Width="5" Height="5" Margin="-3" VerticalAlignment="Center" HorizontalAlignment="Right" Fill="White" Panel.ZIndex="0" Cursor="SizeWE"/>
  19. <Rectangle Name="R_RightDown" Width="5" Height="5" Margin="-3" VerticalAlignment="Bottom" HorizontalAlignment="Right" Fill="White" Panel.ZIndex="0" Cursor="SizeNWSE"/>
  20. <Rectangle Name="R_Down" Width="5" Height="5" Margin="-3" VerticalAlignment="Bottom" HorizontalAlignment="Center" Fill="White" Panel.ZIndex="0" Cursor="SizeNS"/>
  21. <Rectangle Name="R_LeftDown" Width="5" Height="5" Margin="-3" VerticalAlignment="Bottom" HorizontalAlignment="Left" Fill="White" Panel.ZIndex="0" Cursor="SizeNESW"/>
  22. <Rectangle Name="R_Left" Width="5" Height="5" Margin="-3" VerticalAlignment="Center" HorizontalAlignment="Left" Fill="White" Panel.ZIndex="0" Cursor="SizeWE"/>
  23. <!--<GridSplitter Height="5" Width="5" VerticalAlignment="Bottom" HorizontalAlignment="Stretch"></GridSplitter>-->
  24. </Grid>
  25. </Border>
  26. </Grid>
  27. </UserControl>

2、截图控件ImageDealerUnsafeCS

  1. using DialogEx.Class;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Text;
  6. using System.Windows;
  7. using System.Windows.Controls;
  8. using System.Windows.Data;
  9. using System.Windows.Documents;
  10. using System.Windows.Input;
  11. using System.Windows.Media;
  12. using System.Windows.Media.Imaging;
  13. using System.Windows.Navigation;
  14. using System.Windows.Shapes;
  15. namespace DialogEx.Controls.Unsafe
  16. {
  17. /// <summary>
  18. /// ImageDealerUnsafe.xaml 的交互逻辑
  19. /// </summary>
  20. public partial class ImageDealerUnsafe : UserControl
  21. {
  22. #region 公共字段
  23. //截图回调
  24. public delegate void CutImageDelegate(BitmapSource bit);
  25. public CutImageDelegate OnCutImage;
  26. //图片原
  27. private BitmapImage _BitSource;
  28. public BitmapImage BitSource
  29. {
  30. get { return this._BitSource; }
  31. set
  32. {
  33. this._BitSource = value;
  34. this.SoureceImage.Source = value;
  35. }
  36. }
  37. #endregion
  38. #region 依赖属性
  39. /// <summary>
  40. /// 边距
  41. /// </summary>
  42. public double MaxMargin = 2;
  43. //public Brush BorderBrush;
  44. #endregion
  45. #region ==私有字段==
  46. /// <summary>
  47. /// 鼠标样式
  48. /// </summary>
  49. private Cursor MouseCursor = Cursors.Arrow;
  50. /// <summary>
  51. /// 鼠标位置
  52. /// </summary>
  53. private MouseLocationEnum MouseLocation = MouseLocationEnum.None;
  54. /// <summary>
  55. /// 鼠标行为
  56. /// </summary>
  57. private MouseActionEx Action { get; set; }
  58. /// <summary>
  59. /// 边框粗细
  60. /// </summary>
  61. private double BorderWidth = 1;
  62. /// <summary>
  63. /// 拖拽前鼠标按下位置
  64. /// </summary>
  65. private Point MouseDownPoint;
  66. /// <summary>
  67. /// 拖拽前控件位置
  68. /// </summary>
  69. private Point MouseDownLocate;
  70. #endregion
  71. #region ==方法==
  72. public ImageDealerUnsafe()
  73. {
  74. InitializeComponent();
  75. }
  76. /// <summary>
  77. /// 计算区域圆点及宽高
  78. /// </summary>
  79. /// <param name="MouseButtonLocate">鼠标相对背景MainGrid位置</param>
  80. /// <param name="IsRectangle">是否正方形</param>
  81. /// <returns>NULL 或 具体值</returns>
  82. private RectangleAreaModel CalculatedArea(Point MouseButtonLocate, bool IsRectangle)
  83. {
  84. Point Locate = this.ImageArea.TransformToAncestor((UIElement)this.MainGrid).Transform(new Point(0, 0));
  85. //边框宽度
  86. double BorderWidth = this.BorderWidth;
  87. //整体宽度
  88. double RectWidth = this.ImageArea.ActualWidth;
  89. //整体高度
  90. double RectHeight = this.ImageArea.ActualHeight;
  91. //裁剪区域
  92. Point OriginalPoint = new Point(0, 0);//圆点坐标
  93. Point TheoryPoint = new Point(0, 0); //理论坐标
  94. double TheoryWidth = 0; //理论宽度
  95. double TheoryHeight = 0; //理论高度
  96. switch (MouseLocation)
  97. {
  98. case MouseLocationEnum.Left:
  99. {
  100. this.Cursor = Cursors.SizeWE;
  101. OriginalPoint = new Point(Locate.X + RectWidth - BorderWidth / 2, Locate.Y + RectHeight / 2);//右中部位置
  102. TheoryWidth = OriginalPoint.X - MouseButtonLocate.X + BorderWidth;
  103. TheoryHeight = IsRectangle == true ? TheoryWidth : RectHeight;
  104. TheoryPoint = new Point(OriginalPoint.X + BorderWidth / 2 - TheoryWidth, OriginalPoint.Y - TheoryHeight / 2);
  105. }
  106. break;
  107. case MouseLocationEnum.LeftUp:
  108. {
  109. this.Cursor = Cursors.SizeNWSE;
  110. OriginalPoint = new Point(Locate.X + RectWidth - BorderWidth / 2, Locate.Y + RectHeight - BorderWidth / 2);//右下部位置
  111. TheoryWidth = OriginalPoint.X - MouseButtonLocate.X + BorderWidth;
  112. TheoryHeight = IsRectangle == true ? TheoryWidth : OriginalPoint.Y - MouseButtonLocate.Y + BorderWidth;
  113. TheoryPoint = new Point(OriginalPoint.X + BorderWidth / 2 - TheoryWidth, OriginalPoint.Y + BorderWidth / 2 - TheoryHeight);
  114. }
  115. break;
  116. case MouseLocationEnum.Up:
  117. {
  118. this.Cursor = Cursors.SizeNS;
  119. OriginalPoint = new Point(Locate.X + RectWidth / 2, Locate.Y + RectHeight - BorderWidth / 2);//下中部位置
  120. TheoryHeight = OriginalPoint.Y - MouseButtonLocate.Y + BorderWidth;
  121. TheoryWidth = IsRectangle == true ? TheoryHeight : RectWidth;
  122. TheoryPoint = new Point(OriginalPoint.X - TheoryWidth / 2, OriginalPoint.Y + BorderWidth / 2 - TheoryHeight);
  123. }
  124. break;
  125. case MouseLocationEnum.RightUp:
  126. {
  127. this.Cursor = Cursors.SizeNESW;
  128. OriginalPoint = new Point(Locate.X + BorderWidth / 2, Locate.Y + RectHeight - BorderWidth / 2);//左下部位置
  129. TheoryWidth = MouseButtonLocate.X - OriginalPoint.X + BorderWidth;
  130. TheoryHeight = IsRectangle == true ? TheoryWidth : MouseButtonLocate.Y - OriginalPoint.Y + BorderWidth;
  131. TheoryPoint = new Point(OriginalPoint.X - BorderWidth / 2, OriginalPoint.Y + BorderWidth / 2 - TheoryHeight);
  132. }
  133. break;
  134. case MouseLocationEnum.Right:
  135. {
  136. this.Cursor = Cursors.SizeWE;
  137. OriginalPoint = new Point(Locate.X + BorderWidth / 2, Locate.Y + RectHeight / 2);//左中部位置
  138. TheoryWidth = MouseButtonLocate.X - OriginalPoint.X + BorderWidth;
  139. TheoryHeight = IsRectangle == true ? TheoryWidth : RectHeight;
  140. TheoryPoint = new Point(OriginalPoint.X - BorderWidth / 2, OriginalPoint.Y - TheoryHeight / 2);
  141. }
  142. break;
  143. case MouseLocationEnum.RightDown:
  144. {
  145. this.Cursor = Cursors.SizeNWSE;
  146. OriginalPoint = new Point(Locate.X + BorderWidth / 2, Locate.Y + BorderWidth / 2);//左上部位置
  147. TheoryWidth = MouseButtonLocate.X - OriginalPoint.X + BorderWidth;
  148. TheoryHeight = IsRectangle == true ? TheoryWidth : MouseButtonLocate.Y - OriginalPoint.Y + BorderWidth;
  149. TheoryPoint = new Point(OriginalPoint.X - BorderWidth / 2, OriginalPoint.Y - BorderWidth / 2);
  150. }
  151. break;
  152. case MouseLocationEnum.Down:
  153. {
  154. this.Cursor = Cursors.SizeNS;
  155. OriginalPoint = new Point(Locate.X + RectWidth / 2, Locate.Y + BorderWidth / 2);//上中部位置
  156. TheoryHeight = MouseButtonLocate.Y - OriginalPoint.Y + BorderWidth;
  157. TheoryWidth = IsRectangle == true ? TheoryHeight : RectWidth;
  158. TheoryPoint = new Point(OriginalPoint.X - TheoryWidth / 2, OriginalPoint.Y - BorderWidth / 2);
  159. }
  160. break;
  161. case MouseLocationEnum.LeftDown:
  162. {
  163. this.Cursor = Cursors.SizeNESW;
  164. OriginalPoint = new Point(Locate.X + RectWidth - BorderWidth / 2, Locate.Y + BorderWidth / 2);//右上部位置
  165. TheoryWidth = OriginalPoint.X - MouseButtonLocate.X + BorderWidth;
  166. TheoryHeight = IsRectangle == true ? TheoryWidth : OriginalPoint.Y - MouseButtonLocate.Y + BorderWidth;
  167. TheoryPoint = new Point(OriginalPoint.X + BorderWidth / 2 - TheoryWidth, OriginalPoint.Y - BorderWidth / 2);
  168. }
  169. break;
  170. default:
  171. return null;
  172. }
  173. return new RectangleAreaModel()
  174. {
  175. X = TheoryPoint.X,
  176. Y = TheoryPoint.Y,
  177. Width = TheoryWidth,
  178. Height = TheoryHeight
  179. };
  180. }
  181. /// <summary>
  182. /// 图片剪切
  183. /// </summary>
  184. public void CutImage()
  185. {
  186. if (this.BitSource != null)
  187. {
  188. try
  189. {
  190. double ImageAreaWidth = this.ImageArea.ActualWidth;
  191. double ImageAreaHeight = this.ImageArea.ActualHeight;
  192. double GridWidth = this.MainGrid.ActualWidth;
  193. double GridHeight = this.MainGrid.ActualHeight;
  194. BitmapSource source = (BitmapSource)this.BitSource;
  195. //计算比例
  196. Point Locate = this.ImageArea.TransformToAncestor((UIElement)this.MainGrid).Transform(new Point(0, 0));
  197. int dWidth = (int)((ImageAreaWidth * 1.0 / GridWidth) * source.PixelWidth);
  198. int dHeight = (int)((ImageAreaHeight * 1.0 / GridHeight) * source.PixelHeight);
  199. int dLeft = (int)((Locate.X * 1.0 / GridWidth) * source.PixelWidth);
  200. int dTop = (int)((Locate.Y * 1.0 / GridHeight) * source.PixelHeight);
  201. //像素区域
  202. Int32Rect cutRect = new Int32Rect(dLeft, dTop, dWidth, dHeight);
  203. //数组字节数
  204. int stride = source.Format.BitsPerPixel * cutRect.Width / 8;
  205. byte[] data = new byte[cutRect.Height * stride];
  206. source.CopyPixels(cutRect, data, stride, 0);
  207. //创建
  208. BitmapSource bit = BitmapSource.Create(dWidth, dHeight, 0, 0, PixelFormats.Bgr32, null, data, stride);
  209. //通知订阅
  210. if (this.OnCutImage != null)
  211. {
  212. OnCutImage(bit);
  213. }
  214. }
  215. catch
  216. {
  217. }
  218. }
  219. }
  220. /// <summary>
  221. /// 视图转图片
  222. /// </summary>
  223. /// <param name="vsual"></param>
  224. /// <param name="nLeft"></param>
  225. /// <param name="nTop"></param>
  226. /// <param name="nWidth"></param>
  227. /// <param name="nHeight"></param>
  228. /// <returns></returns>
  229. private RenderTargetBitmap RenderVisaulToBitmap(Visual vsual,int nLeft, int nTop,int nWidth, int nHeight)
  230. {
  231. var rtb = new RenderTargetBitmap(nWidth, nHeight, nLeft, nTop, PixelFormats.Default);
  232. rtb.Render(vsual);
  233. return rtb;
  234. }
  235. /// <summary>
  236. /// Bitmap转图片
  237. /// </summary>
  238. /// <param name="bmp"></param>
  239. /// <returns></returns>
  240. public BitmapSource ToBitmapSource(System.Drawing.Bitmap bmp)
  241. {
  242. BitmapSource returnSource;
  243. try
  244. {
  245. returnSource = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(bmp.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
  246. }
  247. catch
  248. {
  249. returnSource = null;
  250. }
  251. return returnSource;
  252. }
  253. #endregion
  254. #region ==事件==
  255. //按下鼠标
  256. private void UserControl_MouseDown(object sender, MouseButtonEventArgs e)
  257. {
  258. this.MouseLocation = Class.MouseLocationEnum.None;
  259. if (e.OriginalSource.GetType() == typeof(Rectangle))
  260. {
  261. Rectangle Act = e.OriginalSource as Rectangle;
  262. switch (Act.Name)
  263. {
  264. case "R_Left": MouseLocation = Class.MouseLocationEnum.Left; break;
  265. case "R_LeftUp": MouseLocation = Class.MouseLocationEnum.LeftUp; break;
  266. case "R_Up": MouseLocation = Class.MouseLocationEnum.Up; break;
  267. case "R_RightUp": MouseLocation = Class.MouseLocationEnum.RightUp; break;
  268. case "R_Right": MouseLocation = Class.MouseLocationEnum.Right; break;
  269. case "R_RightDown": MouseLocation = Class.MouseLocationEnum.RightDown; break;
  270. case "R_Down": MouseLocation = Class.MouseLocationEnum.Down; break;
  271. case "R_LeftDown": MouseLocation = Class.MouseLocationEnum.LeftDown; break;
  272. default: MouseLocation = Class.MouseLocationEnum.None; break;
  273. }
  274. this.Action = MouseActionEx.Drag;
  275. }
  276. else
  277. {
  278. this.MouseDownPoint = Mouse.GetPosition(e.Source as FrameworkElement);//WPF方法
  279. this.MouseDownLocate = this.ImageArea.TransformToAncestor((UIElement)this.MainGrid).Transform(new Point(0, 0));
  280. if ((this.MouseDownLocate.X < this.MouseDownPoint.X && this.MouseDownPoint.X < this.MouseDownLocate.X + this.ImageArea.ActualWidth) &&
  281. (this.MouseDownLocate.Y < this.MouseDownPoint.Y && this.MouseDownPoint.Y < this.MouseDownLocate.Y + this.ImageArea.ActualHeight)
  282. )
  283. {
  284. this.Action = MouseActionEx.DragMove;
  285. }
  286. }
  287. }
  288. //弹起鼠标
  289. private void UserControl_MouseUp(object sender, MouseButtonEventArgs e)
  290. {
  291. this.Action = MouseActionEx.None;
  292. this.Cursor = Cursors.Arrow;
  293. }
  294. //移动鼠标
  295. private void UserControl_MouseMove(object sender, MouseEventArgs e)
  296. {
  297. //鼠标相对空间区域位置
  298. Point MousePoint = e.GetPosition((IInputElement)this.MainGrid);
  299. Point ImageLocate= this.ImageArea.TransformToAncestor((UIElement)this.MainGrid).Transform(new Point(0, 0));
  300. if (ImageLocate.X <= MousePoint.X && MousePoint.X <= ImageLocate.X + this.ImageArea.ActualWidth &&
  301. ImageLocate.Y <= MousePoint.Y && MousePoint.Y <= ImageLocate.Y + this.ImageArea.ActualHeight)
  302. {
  303. this.Cursor = Cursors.Hand;
  304. }
  305. else
  306. {
  307. this.Cursor = Cursors.Arrow;
  308. }
  309. //边框拉伸
  310. if (this.Action == MouseActionEx.Drag)
  311. {
  312. this.Cursor = this.MouseCursor;
  313. //剪辑图片区域宽高
  314. double ImageAreaWidth = this.ImageArea.ActualWidth;
  315. double ImageAreaHeight = this.ImageArea.ActualHeight;
  316. //裁剪区域理论位置
  317. RectangleAreaModel Model = this.CalculatedArea(MousePoint, true);
  318. if (Model != null)
  319. {
  320. //不能超出边界区域
  321. if (Model.X + Model.Width + MaxMargin > this.ActualWidth ||
  322. Model.Y + Model.Height + MaxMargin > this.ActualHeight ||
  323. Model.X < MaxMargin ||
  324. Model.Y < MaxMargin
  325. )
  326. {
  327. this.Cursor = Cursors.Arrow;
  328. this.Action = MouseActionEx.None;
  329. return;
  330. }
  331. this.ImageArea.Width = Model.Width;
  332. this.ImageArea.Height = Model.Height;
  333. this.ImageArea.SetValue(HorizontalAlignmentProperty, HorizontalAlignment.Left);
  334. this.ImageArea.SetValue(VerticalAlignmentProperty, VerticalAlignment.Top);
  335. this.ImageArea.SetValue(MarginProperty, new Thickness(Model.X, Model.Y, 0, 0));
  336. CutImage();
  337. }
  338. }
  339. else if (this.Action == MouseActionEx.DragMove)//拖动
  340. {
  341. double Left = this.MouseDownLocate.X + (MousePoint.X - MouseDownPoint.X);
  342. double Top = this.MouseDownLocate.Y + (MousePoint.Y - MouseDownPoint.Y);
  343. //不能超出边界区域
  344. if (Left < MaxMargin ||
  345. Top < MaxMargin ||
  346. (Left + this.ImageArea.ActualWidth + MaxMargin) > this.ActualWidth ||
  347. (Top + this.ImageArea.ActualHeight + MaxMargin) > this.ActualHeight)
  348. {
  349. this.Cursor = Cursors.Arrow;
  350. this.Action = MouseActionEx.None;
  351. return;
  352. }
  353. this.ImageArea.Width = this.ImageArea.ActualWidth;
  354. this.ImageArea.Height = this.ImageArea.ActualHeight;
  355. this.ImageArea.SetValue(HorizontalAlignmentProperty, HorizontalAlignment.Left);
  356. this.ImageArea.SetValue(VerticalAlignmentProperty, VerticalAlignment.Top);
  357. this.ImageArea.SetValue(MarginProperty, new Thickness(Left, Top, 0, 0));
  358. CutImage();
  359. }
  360. else
  361. {
  362. //this.Cursor = Cursors.Arrow;
  363. }
  364. }
  365. //鼠标离开
  366. private void UserControl_MouseLeave(object sender, MouseEventArgs e)
  367. {
  368. this.Action = MouseActionEx.None;
  369. }
  370. //加载完成后截图
  371. private void ImageArea_SizeChanged(object sender, SizeChangedEventArgs e)
  372. {
  373. this.CutImage();
  374. }
  375. #endregion
  376. }
  377. }

三、封装的截图工具 ImageDealer

1、ImageDealer XAML

  1. <UserControl x:Class="DialogEx.Controls.ImageDealer"
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4. xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  5. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  6. mc:Ignorable="d"
  7. d:DesignHeight="300" d:DesignWidth="300" Background="Transparent"
  8. SnapsToDevicePixels="True"
  9. Loaded="UserControl_Loaded"
  10. >
  11. <Grid Name="MainGrid" MinHeight="200" MinWidth="200" >
  12. </Grid>
  13. </UserControl>

2、ImageDealer CS

  1. using DialogEx.Class;
  2. using DialogEx.Controls.Unsafe;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Linq;
  6. using System.Text;
  7. using System.Threading.Tasks;
  8. using System.Windows;
  9. using System.Windows.Controls;
  10. using System.Windows.Data;
  11. using System.Windows.Documents;
  12. using System.Windows.Input;
  13. using System.Windows.Media;
  14. using System.Windows.Media.Imaging;
  15. using System.Windows.Navigation;
  16. using System.Windows.Shapes;
  17. namespace DialogEx.Controls
  18. {
  19. public partial class ImageDealer : UserControl
  20. {
  21. public static readonly RoutedEvent OnCutImagingEventHandler = EventManager.RegisterRoutedEvent("OnCutImaging", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(ImageDealer));
  22. #region 私有字段
  23. /// <summary>
  24. /// 截图控件
  25. /// </summary>
  26. private ImageDealerUnsafe _ImageDealerControl = new ImageDealerUnsafe();
  27. /// <summary>
  28. /// 图片源
  29. /// </summary>
  30. private BitmapImage _BitSource;
  31. private int _ChangeMargin = 1;
  32. #endregion
  33. #region 公共字段
  34. /// <summary>
  35. /// 图片源
  36. /// </summary>
  37. public BitmapImage BitSource
  38. {
  39. get { return this._BitSource; }
  40. set
  41. {
  42. this._BitSource = value;
  43. this._ImageDealerControl.BitSource = value;
  44. LocateInit();
  45. }
  46. }
  47. /// <summary>
  48. /// 截图事件
  49. /// </summary>
  50. public event RoutedEventHandler OnCutImaging
  51. {
  52. add { base.AddHandler(OnCutImagingEventHandler, value); }
  53. remove { base.RemoveHandler(OnCutImagingEventHandler, value); }
  54. }
  55. #endregion
  56. #region ==方法==
  57. public ImageDealer()
  58. {
  59. InitializeComponent();
  60. this._ImageDealerControl.OnCutImage += this.OnCutImage;
  61. }
  62. //外部截图
  63. public void CutImage()
  64. {
  65. if (this.IsLoaded == true || this._ImageDealerControl == null)
  66. {
  67. this._ImageDealerControl.CutImage();
  68. }
  69. else
  70. {
  71. throw new Exception("尚未创建视图时无法截图!");
  72. }
  73. }
  74. //截图控件位置初始化
  75. private void LocateInit()
  76. {
  77. double Margin = 1;
  78. if (this._BitSource != null)
  79. {
  80. double percent = 1;
  81. //根据最小倍率放大截图控件
  82. percent = (this._BitSource.PixelHeight * 1.0 / this.ActualHeight);
  83. percent = percent < (this._BitSource.PixelWidth * 1.0 / this.ActualWidth) ? (this._BitSource.PixelWidth * 1.0 / this.ActualWidth) : percent;
  84. this._ImageDealerControl.Width = this._BitSource.PixelWidth * 1.0 / percent;
  85. this._ImageDealerControl.Height = this._BitSource.PixelHeight * 1.0 / percent;
  86. //初始化截图方块
  87. this._ImageDealerControl.ImageArea.Width = this._ImageDealerControl.ImageArea.Height = 100 + _ChangeMargin ;
  88. _ChangeMargin = -_ChangeMargin;
  89. this._ImageDealerControl.ImageArea.SetValue(VerticalAlignmentProperty, VerticalAlignment.Center);
  90. this._ImageDealerControl.ImageArea.SetValue(HorizontalAlignmentProperty, HorizontalAlignment.Center);
  91. this._ImageDealerControl.ImageArea.SetValue(MarginProperty, new Thickness(0));
  92. //截图控件相对父控件Margin
  93. this._ImageDealerControl.Width -= 2 * Margin;
  94. this._ImageDealerControl.Height -= 2 * Margin;
  95. this._ImageDealerControl.SetValue(VerticalAlignmentProperty, VerticalAlignment.Center);
  96. this._ImageDealerControl.SetValue(HorizontalAlignmentProperty, HorizontalAlignment.Center);
  97. this._ImageDealerControl.SetValue(MarginProperty, new Thickness(0));
  98. }
  99. }
  100. #endregion
  101. #region ==事件==
  102. //截图回调
  103. private void OnCutImage(BitmapSource bit)
  104. {
  105. RaiseEvent(new RoutedEventArgs(OnCutImagingEventHandler, bit));
  106. }
  107. //加载完成
  108. private void UserControl_Loaded(object sender, RoutedEventArgs e)
  109. {
  110. if (this.MainGrid.Children.Contains(this._ImageDealerControl) == false)
  111. {
  112. this.MainGrid.Children.Add(this._ImageDealerControl);
  113. this._ImageDealerControl.Width = this.ActualWidth;
  114. this._ImageDealerControl.Height = this.ActualHeight;
  115. this._ImageDealerControl.SetValue(VerticalAlignmentProperty, VerticalAlignment.Center);
  116. this._ImageDealerControl.SetValue(HorizontalAlignmentProperty, HorizontalAlignment.Center);
  117. this._ImageDealerControl.SetValue(MarginProperty, new Thickness(0));
  118. }
  119. }
  120. #endregion
  121. }
  122. }

四、用户调用

1、外部调用 Windows 的 XAML

  1. xmlns:MyControls="clr-namespace:DialogEx.Controls;assembly=DialogEx"
  2. <!--图片选择区域-->
  3. <pre name="code" class="csharp" style="font-size: 14px;"><Grid Visibility="{Binding ImageVisible}">
  4. <MyControls:ImageDealer Panel.ZIndex="0" x:Name="ImageDealer" <span style="font-family: Arial, Helvetica, sans-serif;">OnCutImaging</span><span style="font-family: Arial, Helvetica, sans-serif;">="</span><span style="font-family: Arial, Helvetica, sans-serif;">OnCutImaging"></MyControls:ImageDealer></span>
  5. </Grid>

  1.  

2、Windows 的 CS

包含两个方法

1、获取截图控件的截取的图片(被动的接收通知、回调)

2、保存头像文件、(加载头像的时候请使用缓存方式

  1. private BitmapSource CurBitMap;
  2. <span style="white-space:pre"> </span>/// <summary>
  3. <span style="white-space:pre"> </span>/// 截图中
  4. <span style="white-space:pre"> </span>/// </summary>
  5. <span style="white-space:pre"> </span>/// <param name="source"></param>
  6. public void OnCutImaging(object source)
  7. {
  8. if (source != null && source.GetType() == typeof(RoutedEventArgs))
  9. {
  10. // if (((RoutedEventArgs)source).OriginalSource.GetType() == typeof(CroppedBitmap))
  11. {
  12. CurBitMap = (BitmapSource)((RoutedEventArgs)source).OriginalSource;
  13. }
  14. }
  15. }
  16. <span style="white-space:pre"> </span>/// <summary>
  17. /// 保存头像
  18. /// </summary>
  19. public void btnCutPicture_Click()
  20. {
  21. string strFilePath = "F:\\1.png";
  22. //try
  23. {
  24. if (File.Exists(strFilePath) == true)
  25. {
  26. File.Delete(strFilePath);
  27. }
  28. JpegBitmapEncoder encoder = new JpegBitmapEncoder();
  29. encoder.Frames.Add(BitmapFrame.Create(this.CurBitMap));
  30. FileStream fileStream = new FileStream(strFilePath, FileMode.Create, FileAccess.ReadWrite);
  31. encoder.Save(fileStream);
  32. fileStream.Close();
  33. }
  34. //catch
  35. {
  36. }
  37. }

WPF 自定义图片剪切器 - 头像剪切(扩展与完善、实时截图)的更多相关文章

  1. WPF 自定义图片按钮

    此文档仅仅是一个BaseCode,已做后续查阅 XAML代码: <Button x:Class="IM.UI.UC.IM_ImageButton" xmlns="h ...

  2. WPF 自定义 MessageBox (相对完善版)

    WPF 自定义 MessageBox (相对完善版)     基于WPF的自定义 MessageBox. 众所周知WPF界面美观.大多数WPF元素都可以简单的修改其样式,从而达到程序的风格统一.可是当 ...

  3. WPF 自定义 MessageBox (相对完善版 v1.0.0.6)

    基于WPF的自定义 MessageBox. 众所周知WPF界面美观.大多数WPF元素都可以简单的修改其样式,从而达到程序的风格统一.可是当你不得不弹出一个消息框通知用户消息时(虽然很不建议在程序中频繁 ...

  4. vue自定义指令clickoutside使用以及扩展用法

    vue自定义指令clickoutside使用以及扩展用法 产品使用vue+element作为前端框架.在功能开发过程中,难免遇到使用element的组件没办法满足特殊的业务需要,需要对其进行定制,例如 ...

  5. WPF自定义TextBox及ScrollViewer

    原文:WPF自定义TextBox及ScrollViewer 寒假过完,在家真心什么都做不了,可能年龄大了,再想以前那样能专心坐下来已经不行了.回来第一件事就是改了项目的一个bug,最近又新增了一个新的 ...

  6. ASP.NET实现头像剪切保存

    利用swfupload上传头像,利用Jcrop来实现头像在线选择,然后提交个ashx对原头像进行剪切.代码如下: default.aspx: <%@ Page Language="C# ...

  7. WPF 自定义ComboBox样式,自定义多选控件

    原文:WPF 自定义ComboBox样式,自定义多选控件 一.ComboBox基本样式 ComboBox有两种状态,可编辑和不可编辑状态.通过设置IsEditable属性可以切换控件状态. 先看基本样 ...

  8. WPF 自定义MenuItem样式

    原文:WPF 自定义MenuItem样式 一.前言 默认的MenuItem样式比较普通,这次自定义MenuItem的样式也只是对MenuItem的颜色风格进行变化.需要其他功能的变化,大家可以根据样式 ...

  9. 使用WPF将图片转变为灰度并加上水印并保存为文件

    原文:使用WPF将图片转变为灰度并加上水印并保存为文件 运行效果: (上图中左下角为原图的缩小显示,By:Johnson为TextBlock)保存的结果图片:上图的"Test Words.& ...

随机推荐

  1. copy 和 MutableCopy

    1:copy拷贝得到的对象都是不可变对象,MutableCopy拷贝得到的对象都是可变对象.MutableCopy拷贝得到的对象都是新的对象,会重新分配内存地址,而copy拷贝的对象既可以是新对象,也 ...

  2. Java获取文件路径的几种方法

    第一种: File f = new File(this.getClass().getResource("/").getPath()); System.out.println(f); ...

  3. [Ramda] Curry, Compose and Pipe examples

    const curry = R.curry((fns, ary) => R.ap(fns, ary)); ), R.add()]); ,,]); console.log(res); //[2, ...

  4. 6.Swift教程翻译系列——Swift集合类型

    英文版PDF下载地址http://download.csdn.net/detail/tsingheng/7480427 Swift提供数组和字典两种集合类型.用来存储很多值的情况.数组有序的存储一组同 ...

  5. ITFriend创业败局(五):创业可以停止,公司必须注销,不然后果很严重

    马上又要继续出来创业做事了,想到要注册公司,有个麻烦事. 事情得回到2014年9月. 当时,由于各种因素,决定放弃ITFriend,当然也放弃了原来了公司.先是,咨询了横德瑞的陈总,关于公司注销的事. ...

  6. HTML5物理游戏开发 - 越野山地自行车(三)粉碎自行车

    自上一章公布到如今已时隔四月,实在对不住大家.让大家久等了~话说不是我不关注我的博客,而是事情一多起来写博客的时间就少了. 待到今日有空了,回头看了看自己曾经写的文章,猛得发现已经四个月不曾写文章了. ...

  7. Javascript中eval解析的json的几种用法

    eval解析json字符串可用的三种方式都可以实现... <!DOCTYPE html> <html> <head> <meta charset=" ...

  8. 【matlab】安装 webcam 支持

    打开 matlab 命令行,输入 webcam,如果提示: 尚未安装 MATLAB Support Package for USB Webcams.打开支持包安装程序即可安装 Webcam Suppo ...

  9. 【t004】切割矩阵

    Time Limit: 1 second Memory Limit: 50 MB [问题描述] 给你一个矩阵,其边长均为整数.你想把矩阵切割成总数最少的正方形,其边长也为整数.切割工作由一台切割机器完 ...

  10. 【 D3.js 高级系列 — 2.0 】 机械图 + 人物关系图

    机械图(力路线图)结合老百姓的关系图中的生活,这是更有趣. 本文将以此为证据,所列的如何图插入外部的图像和文字的力学. 在[第 9.2 章]中制作了一个最简单的力学图.其后有非常多朋友有疑问,基本的问 ...