此功能用了WPF的InkCanvas,鼠标画矩形,沟是确定,后台多余的代码可以不看,可以取四个角的坐标
1.MainWindow.xaml
<Window x:Class="WPF_InkCanvas.ROI_InkCanvas"
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:local="clr-namespace:WPF_InkCanvas"
mc:Ignorable="d"
Title="ROI_InkCanvas" Height="450" Width="800" KeyDown="Window_KeyDown" KeyUp="Window_KeyUp" Background="Transparent" >
<Window.Resources>
<Style x:Key="BaseButton" TargetType="{x:Type Button}" >
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="FrameworkElement.OverridesDefaultStyle" Value="True" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="Padding" Value="20,10" />
<Setter Property="Cursor" Value="Hand"/>
</Style>
<Style x:Key="PathButton" TargetType="{x:Type Button}" BasedOn="{StaticResource BaseButton}">
<Setter Property="Padding" Value="8"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="Transparent">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
Margin="{TemplateBinding Padding}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
x:Name="PART_ContentPresenter" Opacity=".8"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Opacity" TargetName="PART_ContentPresenter" Value="1"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid x:Name="grid" KeyUp="Window_KeyUp" Background="#FF313030" MouseLeftButtonUp="inkCanvasMeasure_MouseLeftButtonUp">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Image Name="imgMeasure" HorizontalAlignment="Center" Stretch="Uniform" />
<InkCanvas Name="inkCanvasMeasure" EditingMode="None" Background="Transparent" Strokes="{Binding InkStrokes, Mode=TwoWay}" HorizontalAlignment="Center"
Width="{Binding ElementName=imgMeasure, Path=ActualWidth}" Height="{Binding ElementName=imgMeasure, Path=ActualHeight}"
MouseDown="InkCanvasMeasure_MouseDown" MouseMove="InkCanvasMeasure_MouseMove" MouseLeftButtonUp="inkCanvasMeasure_MouseLeftButtonUp">
<StackPanel x:Name="sp" Background="White" Width="50" Height="30" Visibility="Collapsed">
<Button x:Name="PART_ButtonComplete" Style="{DynamicResource PathButton}" ToolTip="完成" Margin="3,0" Click="PART_ButtonComplete_Click">
<Button.Content>
<Path Fill="#67C23A" Width="20" Height="15" Stretch="Fill" Data="M384 690l452-452 60 60-512 512-238-238 60-60z"/>
</Button.Content>
</Button>
</StackPanel>
</InkCanvas>
<StackPanel Grid.Row="1" Orientation="Horizontal" Name="st">
<Button Content="OpenFile" Margin="5" HorizontalAlignment="Left" FontSize="20" Click="OpenFile_Click"/>
<ToggleButton Name="btnSquare" Content="Draw Square" Margin="5" HorizontalAlignment="Left" FontSize="20" Click="DrawSquare_Click"/>
<ToggleButton Name="btnEllipse" Content="Draw Ellipse" Margin="5" HorizontalAlignment="Left" FontSize="20" Click="DrawEllipse_Click"/>
</StackPanel>
</Grid>
</Window>
2.MainWindow.xaml.cs
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
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.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using Tend.UAC.Controls;
namespace WPF_InkCanvas
{
/// <summary>
/// ROI_InkCanvas.xaml 的交互逻辑
/// </summary>
public partial class ROI_InkCanvas : Window
{
private ViewModel viewModel;
private System.Windows.Point iniP;
private System.Windows.Point endP;
public ROI_InkCanvas()
{
InitializeComponent();
this.WindowStyle = WindowStyle.None;
this.AllowsTransparency = true;
//grid.Opacity = 0.7;
imgMeasure.Opacity = 1;
this.Background = new SolidColorBrush(Colors.Gray);// new SolidColorBrush(Colors.Transparent);
grid.Background = new SolidColorBrush(Colors.Transparent);
btnSquare.IsChecked = true;
//设置画笔属性
DrawingAttributes drawingAttributes = new DrawingAttributes
{
Color = Colors.LightGreen,
Width = 1,
Height = 1,
StylusTip = StylusTip.Rectangle,//设置墨迹触笔的形状
//FitToCurve = true,
IsHighlighter = false,
IgnorePressure = true,
};
inkCanvasMeasure.DefaultDrawingAttributes = drawingAttributes;
inkCanvasMeasure.AllowDrop = true;
viewModel = new ViewModel
{
//MeaInfo = "测试······",
InkStrokes = new StrokeCollection(),
};
DataContext = viewModel;
}
private void OpenFile_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog openDialog = new OpenFileDialog
{
Filter = "Image Files (*.bmp)|*.bmp|Image Files (*.jpg)|*.jpg|Image Files (*.png)|*.png",
Title = "Open Image File"
};
if (openDialog.ShowDialog() == true)
{
BitmapImage image = new BitmapImage();
image.BeginInit();
image.UriSource = new Uri(openDialog.FileName, UriKind.RelativeOrAbsolute);
image.EndInit();
imgMeasure.Source = image;
this.image = image;
}
}
private BitmapImage image;
private void DrawSquare_Click(object sender, RoutedEventArgs e)
{
if (btnSquare.IsChecked == true)
{
btnEllipse.IsChecked = false;
}
}
public Byte[] ByteFromImage(System.Windows.Media.Imaging.BitmapImage imageSource)
{
Stream stream = imageSource.StreamSource;
Byte[] imagebyte = null;
if (stream != null && stream.Length > 0)
{
using (BinaryReader br = new BinaryReader(stream))
{
imagebyte = br.ReadBytes((Int32)stream.Length);
}
}
return imagebyte;
}
public byte[] getImgByte(System.Drawing.Image image) //调用方法转字节
{
MemoryStream ms = new MemoryStream();
try
{
image.Save(ms, ImageFormat.Bmp);
byte[] bt = ms.GetBuffer();
return bt;
}
catch (Exception ex)
{
throw ex;
}
finally
{
ms.Close();
}
}
#region BitmapImage 转为byte[]
/// <summary>
/// BitmapImage 转为byte[]
/// </summary>
/// <param name="bitmapImage">BitmapImage 对象</param>
/// <returns>byte[] 数组</returns>
public byte[] BitmapImageToByteArray(BitmapImage bitmapImage)
{
byte[] buffer = new byte[] { };
try
{
Stream stream = bitmapImage.StreamSource;
if (stream != null && stream.Length > 0)
{
stream.Position = 0;
using (BinaryReader binary = new BinaryReader(stream))
{
buffer = binary.ReadBytes((int)stream.Length);
}
}
}
catch (Exception ex)
{
}
return buffer;
}
#endregion
private void DrawEllipse_Click(object sender, RoutedEventArgs e)
{
var r = "";
System.Drawing.Bitmap b = new System.Drawing.Bitmap(image.UriSource.LocalPath);
MemoryStream ms = new MemoryStream();
b.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
byte[] bytes = ms.GetBuffer(); //byte[] bytes= ms.ToArray(); 这两句都可以,至于区别么,下面有解释
ms.Close();
var w = new ImgCut(bytes);
if (w.ShowDialog()==false) {
MessageBox.Show(w.rate?.ToString());
}
//if (btnEllipse.IsChecked == true)
//{
// btnSquare.IsChecked = false;
//}
}
private List<System.Windows.Point> GenerateEclipseGeometry(System.Windows.Point st, System.Windows.Point ed)
{
double a = 0.5 * (ed.X - st.X);
double b = 0.5 * (ed.Y - st.Y);
List<System.Windows.Point> pointList = new List<System.Windows.Point>();
for (double r = 0; r <= 2 * Math.PI; r = r + 0.01)
{
pointList.Add(new System.Windows.Point(0.5 * (st.X + ed.X) + a * Math.Cos(r), 0.5 * (st.Y + ed.Y) + b * Math.Sin(r)));
}
return pointList;
}
private void InkCanvasMeasure_MouseDown(object sender, MouseButtonEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
iniP = e.GetPosition(inkCanvasMeasure);
}
}
private void InkCanvasMeasure_MouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
// Draw square
if (btnSquare.IsChecked == true)
{
endP = e.GetPosition(inkCanvasMeasure);
List<System.Windows.Point> pointList = new List<System.Windows.Point>
{
new System.Windows.Point(iniP.X, iniP.Y),
new System.Windows.Point(iniP.X, endP.Y),
new System.Windows.Point(endP.X, endP.Y),
new System.Windows.Point(endP.X, iniP.Y),
new System.Windows.Point(iniP.X, iniP.Y),
};
StylusPointCollection point = new StylusPointCollection(pointList);
Stroke stroke = new Stroke(point)
{
DrawingAttributes = inkCanvasMeasure.DefaultDrawingAttributes.Clone()
};
viewModel.InkStrokes.Clear();
viewModel.InkStrokes.Add(stroke);
}
// Draw Eclipse
else if (btnEllipse.IsChecked == true)
{
endP = e.GetPosition(inkCanvasMeasure);
List<System.Windows.Point> pointList = GenerateEclipseGeometry(iniP, endP);
StylusPointCollection point = new StylusPointCollection(pointList);
Stroke stroke = new Stroke(point)
{
DrawingAttributes = inkCanvasMeasure.DefaultDrawingAttributes.Clone()
};
viewModel.InkStrokes.Clear();
viewModel.InkStrokes.Add(stroke);
}
}
}
public WindowState SaveWindowState { get; set; }
public WindowStyle SaveWindowStyle { get; set; }
public ResizeMode SaveResizeMode { get; set; }
public bool SaveTopmost { get; set; }
public double SaveLeft { get; set; }
public double SaveTop { get; set; }
public double SaveWidth { get; set; }
public double SaveHeight { get; set; }
private void Window_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
{
//记录当前窗口状态
this.SaveWindowState = this.WindowState;
this.SaveWindowStyle = this.WindowStyle;
this.SaveResizeMode = this.ResizeMode;
this.SaveTopmost = this.Topmost;
this.SaveLeft = this.Left;
this.SaveTop = this.Top;
this.SaveWidth = this.Width;
this.SaveHeight = this.Height;
if (e.KeyboardDevice.Modifiers == ModifierKeys.Control && e.Key == Key.H)
{
st.Visibility = Visibility.Collapsed;
//同时按下了Ctrl + H键(H要最后按,因为判断了此次事件的e.Key)
//修饰键只能按下Ctrl,如果还同时按下了其他修饰键,则不会进入
// 设置全屏
this.WindowState = System.Windows.WindowState.Normal;//还原窗口(非最小化和最大化)
this.WindowStyle = System.Windows.WindowStyle.None;//仅工作区可见,不显示标题栏和边框
this.ResizeMode = System.Windows.ResizeMode.NoResize;//不显示最大化和最小化按钮
//this.Topmost = true;
this.Left = 0.0;
this.Top = 0.0;
this.Width = System.Windows.SystemParameters.PrimaryScreenWidth;
this.Height = System.Windows.SystemParameters.PrimaryScreenHeight;
}
else if (e.Key == Key.Escape)
{
st.Visibility = Visibility.Visible;
this.WindowState = this.SaveWindowState;
this.WindowStyle = this.SaveWindowStyle;
this.ResizeMode = this.SaveResizeMode;
this.Topmost = this.SaveTopmost;
this.Left = this.SaveLeft;
this.Top = this.SaveTop;
this.Width = this.SaveWidth;
this.Height = this.SaveHeight;
}
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
this.WindowState = System.Windows.WindowState.Normal;//还原窗口(非最小化和最大化)
this.WindowStyle = System.Windows.WindowStyle.None; //仅工作区可见,不显示标题栏和边框
this.ResizeMode = System.Windows.ResizeMode.NoResize;//不显示最大化和最小化按钮
this.Topmost = true; //窗口在最前
this.Left = 0.0;
this.Top = 0.0;
this.Width = System.Windows.SystemParameters.PrimaryScreenWidth;
this.Height = System.Windows.SystemParameters.PrimaryScreenHeight;
}
private void Window_KeyUp(object sender, KeyEventArgs e)
{
if (e.Key == Key.Escape)
{
st.Visibility = Visibility.Visible;
this.WindowState = this.SaveWindowState;
this.WindowStyle = this.SaveWindowStyle;
this.ResizeMode = this.SaveResizeMode;
this.Topmost = this.SaveTopmost;
this.Left = this.SaveLeft;
this.Top = this.SaveTop;
this.Width = this.SaveWidth;
this.Height = this.SaveHeight;
}
}
private void inkCanvasMeasure_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
Point zs;//左上点
Point yx;//右下点
if (endP.X > iniP.X)
{
zs = iniP;
yx = endP;
}
else
{
zs = endP;
yx = iniP;
}
var pw = imgMeasure.ActualWidth;//图片宽
var ph = imgMeasure.ActualHeight; //图片高
if (yx.Y + 34 < ph)
sp.Margin = new Thickness(yx.X - 50, yx.Y + 4, 0, 0);
else
sp.Margin = new Thickness(yx.X - 50, ph - 34, 0, 0);
sp.Visibility = Visibility.Visible;
}
private void PART_ButtonComplete_Click(object sender, RoutedEventArgs e)
{
Point zs;//左上点
Point yx;//右下点
if (endP.X > iniP.X)
{
zs = iniP;
yx = endP;
}
else
{
zs = endP;
yx = iniP;
}
var pw = imgMeasure.ActualWidth;//图片宽
var ph = imgMeasure.ActualHeight; //图片高
MessageBox.Show(Math.Round(zs.X / pw, 4) + "," + Math.Round(zs.Y / ph, 4) + "," + Math.Round(yx.X / pw, 4) + "," + Math.Round(yx.Y / ph, 4));
}
}
}
3.ViewModel.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Ink;
namespace WPF_InkCanvas
{
class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName = null)
{
if (PropertyChanged != null)
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private string meaInfo;
public string MeaInfo
{
get => meaInfo;
set
{
meaInfo = value;
OnPropertyChanged("MeaInfo");
}
}
private StrokeCollection inkStrokes;
public StrokeCollection InkStrokes
{
get { return inkStrokes; }
set
{
inkStrokes = value;
OnPropertyChanged("InkStrokes");
}
}
}
}