【问题标题】:Throws an exception when cropping an image if window is maximized WPF如果窗口最大化 WPF 裁剪图像时抛出异常
【发布时间】:2015-04-13 22:34:03
【问题描述】:

我对 WPF 非常陌生,我正在尝试创建一个图片裁剪应用程序。该程序有一个可以拖动的矩形来裁剪图片(就像在 Microsoft Paint 中一样)。它的设置方式是保存矩形的图像和画布都是网格容器的子级。 Grid 有 mousemove、mouseleftbuttondown 和 up 事件来计算裁剪的图像。我的程序可以很好地裁剪图像,但是当窗口最大化时会出现问题,这会引发以下异常错误:

PresentationCore.dll 中出现“System.ArgumentException”类型的未处理异常

附加信息:值不在预期范围内。

这个异常是由我的 Go_Click 方法中的一行引起的:

BitmapSource bs = new CroppedBitmap(LoadedImage.Source as BitmapSource, rcFrom);

进入程序发现一开始是把Image的宽高(LoadedImage.Width和LoadedImage.Height)设置为auto或者NAN造成的。这使得值 NAN 搞砸了计算并抛出异常。我将它更改为 ActualWidth(LoadedImage.ActualWidth 和 ActualHeight),但我只让它部分工作,因为每当我在窗口最大化时裁剪图像时它仍然会引发异常。

以下是我的项目的源代码。

XAML:

<Window x:Class="WpfApplication2.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow">
<Grid ShowGridLines="True">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="2*"/>
        <ColumnDefinition/>
    </Grid.ColumnDefinitions>
    <GroupBox Header="Loaded Image:" Grid.Column="0">
    <Grid x:Name="LoadedImage" MouseLeftButtonDown="image1_MouseLeftButtonDown" MouseMove="image1_MouseMove" MouseLeftButtonUp="image1_MouseLeftButtonUp" ShowGridLines="True">
        <Image x:Name="loaded" Margin="10" Stretch="Fill"/>
        <Canvas  x:Name="BackPanel" Margin="10">
            <Rectangle x:Name="selectionRectangle" Stroke="LightBlue" Fill="#220000FF" Visibility="Collapsed"/>
        </Canvas>
    </Grid>
    </GroupBox>
    <StackPanel Grid.Column="1" x:Name="MyPanel" HorizontalAlignment="Left" Orientation="Vertical" Height="340" Width="262">
        <GroupBox x:Name="Box2" Header="Preview Box:">
            <Image x:Name="PreviewImage" MaxWidth="240" MaxHeight="240" Stretch="Fill" MinWidth="240" MinHeight="240"/>
        </GroupBox>
        <StackPanel Height="61" Orientation="Horizontal" HorizontalAlignment="Center">
                <Button MinWidth="93" Height="32"  Click="Import_Click">Import</Button>
                <Button Name="Crop" MinWidth="93" Height="32" Margin="10,0,0,0" Click="Go_Click">Crop</Button>
        </StackPanel>
    </StackPanel>
</Grid>

这是背后的代码:

using System;
using System.Collections.Generic;
using System.Linq;
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.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.Win32;
using System.IO;

namespace WpfApplication2
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
public partial class MainWindow : Window
{
    private bool isDragging = false;
    private Point anchorPoint = new Point();
    public MainWindow()
    {
        InitializeComponent();
    }

    //Import Button event handler which opens an open file dialog
    //to choose an image file. If the return value from ShowDialog
    //is true (user choose image and click's OK)it will store the image to file,
    //else it would exit open file dialog.
    private void Go_Click(object sender, RoutedEventArgs e)
    {
        if (loaded.Source != null)
        {
         Rect rect1 = new Rect(Canvas.GetLeft(selectionRectangle),      Canvas.GetTop(selectionRectangle), selectionRectangle.Width, selectionRectangle.Height);
            Int32Rect rcFrom = new Int32Rect();
            rcFrom.X = (int)((rect1.X) * (loaded.Source.Width) /           `enter code here`(loaded.ActualWidth));
            rcFrom.Y = (int)((rect1.Y) * (loaded.Source.Height) / (loaded.ActualHeight));
            rcFrom.Width = (int)((rect1.Width) * (loaded.Source.Width) / (loaded.ActualWidth));
            rcFrom.Height = (int)((rect1.Height) * (loaded.Source.Height) / (loaded.ActualHeight));
            BitmapSource bs = new CroppedBitmap(loaded.Source as BitmapSource, rcFrom);
            PreviewImage.Source = bs;
        }
    }
    private void image1_MouseMove(object sender, MouseEventArgs e)
    {
        if (isDragging)
        {
            double x = e.GetPosition(BackPanel).X;
            double y = e.GetPosition(BackPanel).Y;
            selectionRectangle.SetValue(Canvas.LeftProperty, Math.Min(x, anchorPoint.X));
            selectionRectangle.SetValue(Canvas.TopProperty, Math.Min(y, anchorPoint.Y));
            selectionRectangle.Width = Math.Abs(x - anchorPoint.X);
            selectionRectangle.Height = Math.Abs(y - anchorPoint.Y);

            if (selectionRectangle.Visibility != Visibility.Visible)
              selectionRectangle.Visibility = Visibility.Visible;
        }
    }
    private void image1_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        if (isDragging == false)
        {
            anchorPoint.X = e.GetPosition(BackPanel).X;
            anchorPoint.Y = e.GetPosition(BackPanel).Y;
            isDragging = true;
        }

    }
    private void image1_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        if (isDragging)
        {
            isDragging = false;
            if (selectionRectangle.Width > 0)
            {
                Crop.Visibility = System.Windows.Visibility.Visible;
                Crop.IsEnabled = true;
            }
            if (selectionRectangle.Visibility != Visibility.Visible)
                selectionRectangle.Visibility = Visibility.Visible;
        }
    }
    private void RestRect()
    {
        selectionRectangle.Visibility = Visibility.Collapsed;
        isDragging = false;
    }
    private void Import_Click(object sender, RoutedEventArgs e)
    {
        OpenFileDialog dlg = new OpenFileDialog();
        dlg.FileName = "Picture";
        dlg.Filter = "All Pictures (*.jpeg)|*.jpg";

        if (dlg.ShowDialog() == true)
        {
            loaded.Source = new BitmapImage(new Uri(dlg.FileName));
        }
    }

 }
}

就像我说的,我是 WPF 编程新手,如果我编写代码的方式可能不是最好的,我深表歉意。但是任何建议都会对我应该如何处理这个问题有所帮助。

提前致谢。

【问题讨论】:

  • 如果您可以将其归结为minimal, complete and verifyabe example,将会有很大帮助。大多数人不喜欢通读您的所有代码。
  • 按照 Clemens 的建议,我在示例中删除了所有不必要的代码,我希望剩下的代码足够短。当我重组我的代码时,它似乎工作正常,我不知道我做了什么改变来触发它。但是我注意到,如果选择图像的一部分进行裁剪并且我将其从原始更改为最大化矩形会向左移动一定程度。这往往会引发一个异常,该异常是由要移出范围的矩形引起的。处理这个问题的最佳方法是什么?创建异常处理程序或更改我的编码。

标签: c# wpf xaml


【解决方案1】:

你需要获取LoadedImage相对于GridLoadedImage的位置,并在创建crop时使用:

private void Go_Click(object sender, RoutedEventArgs e)
    {
        if (LoadedImage.Source != null)
        {
            var imagePosition = loaded.TransformToAncestor(LoadedImage).Transform(new Point(0, 0));
            Rect rect1 = new Rect(Math.Max(Canvas.GetLeft(selectionRectangle) - imagePosition.X, 0), Canvas.GetTop(selectionRectangle), selectionRectangle.Width, selectionRectangle.Height);
            Int32Rect rcFrom = new Int32Rect();
            rcFrom.X = (int)((rect1.X) * (LoadedImage.Source.Width) / (LoadedImage.ActualWidth));
            rcFrom.Y = (int)((rect1.Y) * (LoadedImage.Source.Height) / (LoadedImage.ActualHeight));
            rcFrom.Width = (int)((rect1.Width) * (LoadedImage.Source.Width) / (LoadedImage.ActualWidth));
            rcFrom.Height = (int)((rect1.Height) * (LoadedImage.Source.Height) / (LoadedImage.ActualHeight));
            BitmapSource bs = new CroppedBitmap(LoadedImage.Source as BitmapSource, rcFrom);
            PreviewImage.Source = bs;
        }
    }

【讨论】:

  • 感谢 Anka 的回复,我对 WPF 比较陌生,所以您介意我问一下您应用的更改是做什么的吗?我应用了更改我的代码,但与使用我的编码相比,没有发现任何行为差异。
  • 您试图裁剪超过 LoadedImage 大小的矩形。
  • 在不进行此更改的情况下调试并检查 rect1 和图像大小 - 例如,当您最大化时,rect1.X 为 667,则 rcFrom.X 为 1049,图像宽度约为 400。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-31
相关资源
最近更新 更多