JMK*_*JMK 19 wpf image-processing
我已经整理了一个简单的WPF应用程序来演示我遇到的问题.我的XAML如下:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="427" Width="467" Loaded="MainWindow_OnLoaded">
<Grid>
<ScrollViewer Name="MyScrollViewer" CanContentScroll="True">
<Image Name="MyImage" HorizontalAlignment="Left" VerticalAlignment="Top" MouseWheel="UIElement_OnMouseWheel" MouseDown="MyImage_OnMouseDown" MouseUp="MyImage_OnMouseUp"/>
</ScrollViewer>
</Grid>
</Window>
Run Code Online (Sandbox Code Playgroud)
代码隐藏如下:
using System;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void UIElement_OnMouseWheel(object sender, MouseWheelEventArgs e)
{
var matrix = MyImage.RenderTransform.Value;
if (e.Delta > 0)
{
matrix.ScaleAt(1.5, 1.5, e.GetPosition(this).X, e.GetPosition(this).Y);
}
else
{
matrix.ScaleAt(1.0 / 1.5, 1.0 / 1.5, e.GetPosition(this).X, e.GetPosition(this).Y);
}
MyImage.RenderTransform = new MatrixTransform(matrix);
}
private WriteableBitmap writeableBitmap;
private void MainWindow_OnLoaded(object sender, RoutedEventArgs e)
{
var image = new WriteableBitmap(new BitmapImage(new Uri(@"C:\myImage.png", UriKind.Absolute)));
MyImage.Width = image.Width;
MyImage.Height = image.Height;
image = BitmapFactory.ConvertToPbgra32Format(image);
writeableBitmap = image;
MyImage.Source = image;
}
private Point downPoint;
private Point upPoint;
private void MyImage_OnMouseDown(object sender, MouseButtonEventArgs e)
{
downPoint = e.GetPosition(MyImage);
}
private void MyImage_OnMouseUp(object sender, MouseButtonEventArgs e)
{
upPoint = e.GetPosition(MyImage);
writeableBitmap.DrawRectangle(Convert.ToInt32(downPoint.X), Convert.ToInt32(downPoint.Y), Convert.ToInt32(upPoint.X), Convert.ToInt32(upPoint.Y), Colors.Red);
MyImage.Source = writeableBitmap;
}
}
}
Run Code Online (Sandbox Code Playgroud)
我已经使用Nuget添加了WriteableBitmapEx.如果你运行它,并将myImage.png替换为计算机上实际图像的位置,你会发现一个如下所示的应用程序:

您可以通过点击您要框的左上角去拖动到您想要的盒子走的右下角绘制图像上的框,你会得到一个红色矩形.您甚至可以使用鼠标中键放大,并向上绘制一个矩形以获得更高的精度,这可以按预期工作.
问题是,当你用鼠标滚动,滚动条不会重新调整,这是我创建的程序的要求.我的问题是当图像放大时,如何强制滚动查看器上的滚动条重新调整?
我确信它与ScrollViewer的RenderTransform属性有关,我需要在更新图像的RenderTransform属性的同时更新它(在UIElement_OnMouseWheel上)但我不确定如何去做这个.
Joh*_*wen 21
你应该使用LayoutTransform而不是RenderTransform你的形象.
RenderTransform布局完成后发生,仅视觉.LayoutTransform在布局传递之前完成,因此可以通知ScrollViewer新的大小.
有关详细信息,请参阅此处:http://msdn.microsoft.com/en-us/library/system.windows.frameworkelement.layouttransform.aspx
对于纯滚动,我宁愿使用ScaleTransform,它应该相应地调整滚动条.如果它解决了您的问题,您可以尝试下面的代码.
private double _zoomValue = 1.0;
private void UIElement_OnMouseWheel(object sender, MouseWheelEventArgs e)
{
if (e.Delta > 0)
{
_zoomValue += 0.1;
}
else
{
_zoomValue -= 0.1;
}
ScaleTransform scale = new ScaleTransform(_zoomValue, _zoomValue);
MyImage.LayoutTransform = scale;
e.Handled = true;
}
Run Code Online (Sandbox Code Playgroud)
假设您在 ViewBox_CanvasMain 中有一个 Canvas_Main,而后者又在 ScrollViewer_CanvasMain 中。您想通过转动鼠标滚轮放大,ScrollViewer 将自动调整偏移量,以便在放大/缩小期间保持该特征(由鼠标在 Canvas_Main 中指向)。它很复杂,但这里是鼠标滚轮事件处理程序调用的代码:
private void MouseWheelZoom(MouseWheelEventArgs e)
{
if(Canvas_Main.IsMouseOver)
{
Point mouseAtImage = e.GetPosition(Canvas_Main); // ScrollViewer_CanvasMain.TranslatePoint(middleOfScrollViewer, Canvas_Main);
Point mouseAtScrollViewer = e.GetPosition(ScrollViewer_CanvasMain);
ScaleTransform st = ViewBox_CanvasMain.LayoutTransform as ScaleTransform;
if (st == null)
{
st = new ScaleTransform();
ViewBox_CanvasMain.LayoutTransform = st;
}
if (e.Delta > 0)
{
st.ScaleX = st.ScaleY = st.ScaleX * 1.25;
if (st.ScaleX > 64) st.ScaleX = st.ScaleY = 64;
}
else
{
st.ScaleX = st.ScaleY = st.ScaleX / 1.25;
if (st.ScaleX < 1) st.ScaleX = st.ScaleY = 1;
}
#region [this step is critical for offset]
ScrollViewer_CanvasMain.ScrollToHorizontalOffset(0);
ScrollViewer_CanvasMain.ScrollToVerticalOffset(0);
this.UpdateLayout();
#endregion
Vector offset = Canvas_Main.TranslatePoint(mouseAtImage, ScrollViewer_CanvasMain) - mouseAtScrollViewer; // (Vector)middleOfScrollViewer;
ScrollViewer_CanvasMain.ScrollToHorizontalOffset(offset.X);
ScrollViewer_CanvasMain.ScrollToVerticalOffset(offset.Y);
this.UpdateLayout();
e.Handled = true;
}
}
Run Code Online (Sandbox Code Playgroud)