c# - 如何从 ScrollViewer 中的图像中捕获画布区域
问题描述
我用scrollviewer放大或者缩小图片,已经成功了。现在我希望在图片上绘制一个区域并将该区域捕获到图像中。但是我得到的图像除了边框之外是空白的。这是我的代码。
XAML:</p>
<Window x:Class="Capture.MainWindow"
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:Capture"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Slider Grid.Column="0" Orientation="Vertical"
HorizontalAlignment="Left" Minimum="1" x:Name="slider"/>
<ScrollViewer Name="scrollViewer" Grid.Column="1"
VerticalScrollBarVisibility="Visible"
HorizontalScrollBarVisibility="Visible" Margin="0,0,0,40">
<Grid Name="grid" Width="400" Height="400" >
<Grid.LayoutTransform>
<TransformGroup x:Name="TfGroup">
<ScaleTransform x:Name="scaleTransform"/>
</TransformGroup>
</Grid.LayoutTransform>
<Viewbox Grid.Column="0" Grid.Row="0">
<Image x:Name="img" Source="C:\Users\citic\Desktop\微信截图_20200728104010.png" />
</Viewbox>
<Canvas x:Name="canvas" MouseDown="Canvas_MouseDown" MouseMove="Canvas_MouseMove" MouseUp="Canvas_MouseUp" Background="Transparent"/>
</Grid>
</ScrollViewer>
<Button Grid.Column="1" Content="Capture" Margin="338,381,337.333,9.667" Click="Button_Click"/>
</Grid>
</Window>
public partial class MainWindow : Window
{
Point? lastCenterPositionOnTarget;
Point? lastMousePositionOnTarget;
Point? lastDragPoint;
private System.Windows.Point startPoint;
private System.Windows.Shapes.Rectangle rect;
private int w1;
private int h1;
public MainWindow()
{
InitializeComponent();
scrollViewer.ScrollChanged += OnScrollViewerScrollChanged;
scrollViewer.PreviewMouseLeftButtonUp += OnMouseLeftButtonUp;
scrollViewer.PreviewMouseWheel += OnPreviewMouseWheel;
slider.ValueChanged += OnSliderValueChanged;
}
void OnScrollViewerScrollChanged(object sender, ScrollChangedEventArgs e)
{
if (e.ExtentHeightChange != 0 || e.ExtentWidthChange != 0)
{
Point? targetBefore = null;
Point? targetNow = null;
if (!lastMousePositionOnTarget.HasValue)
{
if (lastCenterPositionOnTarget.HasValue)
{
var centerOfViewport = new Point(scrollViewer.ViewportWidth / 2,
scrollViewer.ViewportHeight / 2);
Point centerOfTargetNow =
scrollViewer.TranslatePoint(centerOfViewport, grid);
targetBefore = lastCenterPositionOnTarget;
targetNow = centerOfTargetNow;
}
}
else
{
targetBefore = lastMousePositionOnTarget;
targetNow = Mouse.GetPosition(grid);
lastMousePositionOnTarget = null;
}
if (targetBefore.HasValue)
{
double dXInTargetPixels = targetNow.Value.X - targetBefore.Value.X;
double dYInTargetPixels = targetNow.Value.Y - targetBefore.Value.Y;
double multiplicatorX = e.ExtentWidth / grid.Width;
double multiplicatorY = e.ExtentHeight / grid.Height;
double newOffsetX = scrollViewer.HorizontalOffset -
dXInTargetPixels * multiplicatorX;
double newOffsetY = scrollViewer.VerticalOffset -
dYInTargetPixels * multiplicatorY;
if (double.IsNaN(newOffsetX) || double.IsNaN(newOffsetY))
{
return;
}
scrollViewer.ScrollToHorizontalOffset(newOffsetX);
scrollViewer.ScrollToVerticalOffset(newOffsetY);
}
}
}
private void OnMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
scrollViewer.Cursor = Cursors.Arrow;
scrollViewer.ReleaseMouseCapture();
lastDragPoint = null;
}
private void OnPreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
lastMousePositionOnTarget = Mouse.GetPosition(grid);
System.Windows.Point centerPoint = e.GetPosition(img);
var val = e.Delta * 0.01; //描述鼠标滑轮滚动
if (scaleTransform.ScaleX + val < 0.1) return;
if (scaleTransform.ScaleX + val > 100) return;
scaleTransform.CenterX = centerPoint.X;
scaleTransform.CenterY = centerPoint.Y;
scaleTransform.ScaleX += val;
scaleTransform.ScaleY += val;
if (e.Delta > 0)
{
slider.Value += 1;
}
if (e.Delta < 0)
{
slider.Value -= 1;
}
e.Handled = true;
}
private void OnSliderValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
scaleTransform.ScaleX = e.NewValue;
scaleTransform.ScaleY = e.NewValue;
var centerOfViewport = new System.Windows.Point(scrollViewer.ViewportWidth / 2, scrollViewer.ViewportHeight / 2);
lastCenterPositionOnTarget = scrollViewer.TranslatePoint(centerOfViewport, grid);
}
private void Canvas_MouseDown(object sender, MouseButtonEventArgs e)
{
canvas.Children.Clear();
startPoint = e.GetPosition(canvas);
rect = new System.Windows.Shapes.Rectangle
{
Stroke = System.Windows.Media.Brushes.IndianRed,
StrokeThickness = 0.2,
StrokeDashArray = new DoubleCollection { 2 }
};
Canvas.SetLeft(rect, startPoint.X);
Canvas.SetTop(rect, startPoint.Y);
canvas.Children.Add(rect);
}
private void Canvas_MouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Released || rect == null)
return;
var pos = e.GetPosition(canvas);
var x = Math.Min(pos.X, startPoint.X);
var y = Math.Min(pos.Y, startPoint.Y);
var w = Math.Max(pos.X, startPoint.X) - x;
var h = Math.Max(pos.Y, startPoint.Y) - y;
w1 = (int)w;
h1 = (int)h;
rect.Width = w;
rect.Height = h;
Canvas.SetLeft(rect, x);
Canvas.SetTop(rect, y);
}
private void Canvas_MouseUp(object sender, MouseButtonEventArgs e)
{
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var rect = new Rect(canvas.RenderSize);
var visual = new DrawingVisual();
using (var dc = visual.RenderOpen())
{
dc.DrawRectangle(new VisualBrush(canvas), null, rect);
}
var bitmap = new RenderTargetBitmap(
(int)rect.Width, (int)rect.Height, 96, 96, PixelFormats.Default);
bitmap.Render(visual);
var encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bitmap));
using (var file = File.OpenWrite(@"C:\Users\citic\Desktop\test.jpg"))
{
encoder.Save(file);
}
}
}
我是WPF新手,很多内容还在学习中。请帮帮我,谢谢!
解决方案
它不起作用的原因是因为您只是捕获 Canvas 并将其转换为位图。如果您查看布局,则图像位于另一层。它没有放置在画布上。
<Grid>
<Viewbox>
<Image /> <!-- This is on a separate layer of the layout -->
</Viewbox>
<Canvas /> <!-- You're only capturing this -->
</Grid>
与其捕获 Canvas,不如尝试使用 Grid。
推荐阅读
- python - 中央目录损坏部署 Python Azure 功能
- javascript - 移动到ankers找不到真正的位置
- command-line - 在 nbconvert 之前保存 Jupyter 笔记本
- python - 在 Python 中提取值
- sql - 与 sum() 一起选择列
- c# - 这个 for 循环不止一次地循环遍历相同的值吗?
- c - 定义一个接受多种类型的 API,每种类型都有自己的可能值范围
- php - Laravel LDAP 身份验证不起作用 - LdapRecord 包
- powershell - 如果 Outlook 已在运行,则使用 powershell 在 Outlook 中发送电子邮件而不锁定
- mongodb - 猫鼬在数组列表中按_id查找集合