using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; namespace XP.Camera.Calibration.Controls; /// /// 图像画布控件 - 提供图像显示、缩放、平移功能 /// public partial class ImageCanvasControl : UserControl { private Point mouseDownPoint = new Point(); #region Dependency Properties public static readonly DependencyProperty ZoomScaleProperty = DependencyProperty.Register("ZoomScale", typeof(double), typeof(ImageCanvasControl), new PropertyMetadata(1.0)); public static readonly DependencyProperty ZoomCenterProperty = DependencyProperty.Register("ZoomCenter", typeof(Point), typeof(ImageCanvasControl), new PropertyMetadata(new Point())); public static readonly DependencyProperty PanningOffsetXProperty = DependencyProperty.Register("PanningOffsetX", typeof(double), typeof(ImageCanvasControl), new PropertyMetadata(0.0)); public static readonly DependencyProperty PanningOffsetYProperty = DependencyProperty.Register("PanningOffsetY", typeof(double), typeof(ImageCanvasControl), new PropertyMetadata(0.0)); public static readonly DependencyProperty ReferenceImageProperty = DependencyProperty.Register("ReferenceImage", typeof(BitmapSource), typeof(ImageCanvasControl), new UIPropertyMetadata(null, ReferenceImageChanged)); public static readonly DependencyProperty ImageScaleFactorProperty = DependencyProperty.Register("ImageScaleFactor", typeof(double), typeof(ImageCanvasControl), new PropertyMetadata(1.0)); public static readonly DependencyProperty MaxImageWidthProperty = DependencyProperty.Register("MaxImageWidth", typeof(int), typeof(ImageCanvasControl), new PropertyMetadata(0)); public static readonly DependencyProperty MaxImageHeightProperty = DependencyProperty.Register("MaxImageHeight", typeof(int), typeof(ImageCanvasControl), new PropertyMetadata(0)); public static readonly DependencyProperty EnablePanningProperty = DependencyProperty.Register("EnablePanning", typeof(bool), typeof(ImageCanvasControl), new PropertyMetadata(true)); #endregion #region Properties public double ZoomScale { get => (double)GetValue(ZoomScaleProperty); set => SetValue(ZoomScaleProperty, value); } public Point ZoomCenter { get => (Point)GetValue(ZoomCenterProperty); set => SetValue(ZoomCenterProperty, value); } public double PanningOffsetX { get => (double)GetValue(PanningOffsetXProperty); set => SetValue(PanningOffsetXProperty, value); } public double PanningOffsetY { get => (double)GetValue(PanningOffsetYProperty); set => SetValue(PanningOffsetYProperty, value); } public BitmapSource? ReferenceImage { get => (BitmapSource?)GetValue(ReferenceImageProperty); set => SetValue(ReferenceImageProperty, value); } public double ImageScaleFactor { get => (double)GetValue(ImageScaleFactorProperty); set => SetValue(ImageScaleFactorProperty, value); } public int MaxImageWidth { get => (int)GetValue(MaxImageWidthProperty); set => SetValue(MaxImageWidthProperty, value); } public int MaxImageHeight { get => (int)GetValue(MaxImageHeightProperty); set => SetValue(MaxImageHeightProperty, value); } public bool EnablePanning { get => (bool)GetValue(EnablePanningProperty); set => SetValue(EnablePanningProperty, value); } private Canvas roiCanvas = new Canvas(); public Canvas RoiCanvas { get => roiCanvas; set => roiCanvas = value; } #endregion #region Events public event EventHandler? CanvasRightMouseUp; public event EventHandler? CanvasRightMouseDown; public event EventHandler? CanvasLeftMouseDown; public event EventHandler? CanvasMouseMove; public event EventHandler? CanvasMouseWheel; #endregion public ImageCanvasControl() { InitializeComponent(); } #region Private Methods private static void ReferenceImageChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { (d as ImageCanvasControl)?.OnReferenceImageChanged(e.NewValue as BitmapSource); } private void OnReferenceImageChanged(BitmapSource? bitmapSource) { if (bitmapSource != null) { ImageBrush brush = new ImageBrush { ImageSource = bitmapSource, Stretch = Stretch.Uniform }; RoiCanvas.Background = brush; RoiCanvas.Height = bitmapSource.Height; RoiCanvas.Width = bitmapSource.Width; } else { RoiCanvas.Height = MaxImageHeight > 0 ? MaxImageHeight : 600; RoiCanvas.Width = MaxImageWidth > 0 ? MaxImageWidth : 800; RoiCanvas.Background = Brushes.LightGray; } } private double CalculateScaleFactor() { if (ActualWidth <= 0) return 1; double scaleFactor = Math.Max(RoiCanvas.Width / ActualWidth, RoiCanvas.Height / ActualHeight); if (scaleFactor < 0) scaleFactor = Math.Min(RoiCanvas.Width / ActualWidth, RoiCanvas.Height / ActualHeight); return scaleFactor; } #endregion #region Event Handlers private void Canvas_MouseEnter(object sender, MouseEventArgs e) { if (e.LeftButton == MouseButtonState.Pressed) mouseDownPoint = e.GetPosition(RoiCanvas); } private void Canvas_MouseMove(object sender, MouseEventArgs e) { CanvasMouseMove?.Invoke(sender, e); if (EnablePanning && e.LeftButton == MouseButtonState.Pressed) { Point mousePoint = e.GetPosition(RoiCanvas); double mouseMoveLength = Point.Subtract(mousePoint, mouseDownPoint).Length; if (mouseMoveLength > (10 * CalculateScaleFactor()) / ZoomScale) { PanningOffsetX += mousePoint.X - mouseDownPoint.X; PanningOffsetY += mousePoint.Y - mouseDownPoint.Y; } } } private void Canvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) { } private void Canvas_MouseRightButtonUp(object sender, MouseButtonEventArgs e) { CanvasRightMouseUp?.Invoke(sender, e); } private void Canvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { mouseDownPoint = e.GetPosition(RoiCanvas); CanvasLeftMouseDown?.Invoke(sender, e); if (EnablePanning && e.ClickCount == 2) { ResetView(); e.Handled = true; } } private void Canvas_MouseRightButtonDown(object sender, MouseButtonEventArgs e) { CanvasRightMouseDown?.Invoke(sender, e); e.Handled = true; } private void Adorner_MouseWheel(object sender, MouseWheelEventArgs e) { CanvasMouseWheel?.Invoke(sender, e); } private void ContentPresenter_SizeChanged(object sender, SizeChangedEventArgs e) { ImageScaleFactor = CalculateScaleFactor(); } private void ResetView() { ZoomScale = 1.0; PanningOffsetX = 0.0; PanningOffsetY = 0.0; ZoomCenter = new Point(0, 0); } #endregion }