在WPF中如何使用scrollviewer放大图片并通过鼠标画出选区,保存这个选区到一张图片?

howze 2020-08-31 02:03:22
需求是这样的,我在做一个图片查看器
其中,使用了scrollviewer来放大或者缩小图片
这一步我已经实现了
然后在图片上,绘制矩形选取,这一步我也实现了
但是接下来遇到两个问题:
1、因为我的矩形选区是放在scrollviewer里的,导致随着图片放大缩小,矩形的边框会变粗或者变细。(不是我想把矩形选区是放在scrollviewer里,而是不放在里面就无法在图片上画选区)
2、我无法截取矩形选取内的图片,截取后是空白的,
以下是代码,请问该如何解决,谢谢!

xaml:

<Window x:Class="截图.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:截图"
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>

<Image x:Name="img" Source="C:\Users\howze\Desktop\20200728104010.png" />

<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.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 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);

//MessageBox.Show(startPoint.ToString());

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)
{

RenderTargetBitmap targetBitmap = new RenderTargetBitmap(
(int)canvas.ActualWidth,
(int)canvas.ActualHeight,
96,
96,
PixelFormats.Default);

targetBitmap.Render(canvas);

using (FileStream tFileStream = new FileStream(@"C:\Users\howze\Desktop\test.jpg",
FileMode.Create, FileAccess.Write))
{

PngBitmapEncoder tPngBitmapEncoder = new PngBitmapEncoder();
tPngBitmapEncoder.Interlace = PngInterlaceOption.On;
tPngBitmapEncoder.Frames.Add(BitmapFrame.Create(targetBitmap));
tPngBitmapEncoder.Save(tFileStream);
tFileStream.Close();
}

}
}
...全文
619 2 打赏 收藏 举报
写回复
用AI写文章
2 条回复
切换为时间正序
请发表友善的回复…
发表回复
howze 2020-08-31
  • 打赏
  • 举报
回复
引用 1 楼 耗子哭死猫 的回复:
可以放在Canvas里面,Canvas嵌套Canvas
嵌套也试过了,还是一样的不行
耗子哭死猫 2020-08-31
  • 打赏
  • 举报
回复
可以放在Canvas里面,Canvas嵌套Canvas
源码直接下载地址: https://pan.quark.cn/s/387d7c8f6289 在使用IE浏览器的过程中,偶尔会出现重置为默认配置操作未能顺利完成的现象。这种情况的发生可能源于多种因素,包括注册表项出现偏差、浏览器附加组件之间存在不兼容、操作系统授权设置不当或受到恶意程序影响等。针对这一挑战,我们可以通过一系列系统性的方法来逐一诊断和纠正。首先需要验证当前用户是否具备管理员级别的操作权限。在执行重置配置的操作时,必须确保IE浏览器是以管理员身份启动的。具体操作方式为,使用鼠标右键单击IE程序图标,并从弹出的菜单中选择“以管理员身份运行”这一选项。其次,应当检查是否存在恶意软件。恶意程序有时会非法修改浏览器的配置信息,从而阻碍重置过程的正常进行。用户可以借助Windows系统自带的Microsoft Safety Scanner进行检测,或者选择安装并使用第三方安全防护软件执行全面的系统扫描。紧接着,需要对浏览器的缓存数据以及Cookies文件进行清理。在IE浏览器界面中,通过访问“工具”菜单并选择“Internet选项”,然后在弹出的设置界面中,切换至“常规”标签页,并执行清除浏览历史记录的操作,此过程应包含Cookies和临时互联网文件。倘若上述步骤均未能解决问题,那么可以考虑禁用或移除那些可能引发冲突的浏览器附加组件。相关操作需要在“工具”菜单下找到并打开“管理加载项”,对可疑的插件进行禁用处理,并在浏览器重新启动后再次尝试执行重置操作。再者,修复IE浏览器相关的注册表配置也是至关重要的环节。注册表编辑器是一个功能强大的系统工具,任何不当的操作都可能导致严重的系统问题,因此在进行修改前必须创建系统还原点作为安全备份。用户可以通过按下“Win+R”组合...
内容概要:本文详细介绍了光伏储能虚拟同步发电机(VSG)并网仿真模型的Simulink实现方法,系统研究了光伏发电与储能系统融合VSG技术并入电网的动态特性与控制策略。通过构建完整的VSG控制模块,模拟其在并网过程中的虚拟惯性响应、频率调节能力和有功无功功率支撑特性,验证了该系统在增强电网稳定性、提升新能源并网适应性方面的有效性。模型全面涵盖光伏出力特性、储能系统充放电管理、VSG有功-无功解耦控制、下垂控制机制以及并网点动态响应等关键环节,并通过多种工况下的仿真分析,评估系统在不同运行条件下的动态性能与鲁棒性。; 适合人群:具备电力系统、新能源发电、自动控制等相关专业背景,熟悉Matlab/Simulink仿真环境,从事新能源并网、微电网控制或电力电子系统研究的科研人员、工程技术人员及研究生。; 使用场景及目标:①深入理解光伏储能系统如何通过VSG技术模拟同步发电机的惯性和阻尼特性以支持电网稳定;②掌握虚拟惯量控制、下垂控制等VSG核心控制策略在Simulink中的建模、参数设计与实现方法;③为新型电力系统中新能源并网的动态仿真、稳定性分析及控制策略优化提供可靠的模型基础和技术参考。; 阅读建议:建议结合所提供的仿真模型进行逐步操作与参数调试,重点关注VSG控制环路的结构设计、控制器参数整定及其对系统动态性能的影响,同时可将该模型拓展应用于多机并联、微电网孤岛/并网切换、多能源协同控制等更复杂的系统场景中进行进阶研究。

111,128

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Creator Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧