【问题标题】:Rotating image in WPF not respecting screen sizeWPF中的旋转图像不考虑屏幕尺寸
【发布时间】:2020-05-30 09:35:29
【问题描述】:

我目前在使用 RotateTransformLayoutTransform 在 WPF 中旋转图像时遇到问题。当图像的像素高度大于显示器高度并旋转 90º 或 270º 时,窗口大小将高于显示器屏幕分辨率大小。

示例截图: Application running with image at 90º Application running with image at 0º

我正在使用下面的代码(简化),其中 mainWindow.imgSystem.Windows.Control.Image:

static void Rotate(int degrees)
{
    var rt = new RotateTransform { Angle = degrees };
    mainWindow.img.LayoutTransform = rt;
}

这是一个图片查看器项目,完整的源代码可以在https://github.com/Ruben2776/PicView获得

我已经尝试改变图像的宽度和高度值,但它会产生不希望的结果(倾斜的比例)。

图像尺寸的尺寸计算是根据用户的屏幕高度进行的,使用以下修剪代码:

int interfaceHeight = 90;
double maxWidth = Math.Min(MonitorInfo.Width, width);
double maxHeight = Math.Min((MonitorInfo.Height - interfaceHeight), height);
double AspectRatio = Math.Min((maxWidth / width), (maxHeight / height));
mainWindow.img.Width = (width * AspectRatio);
mainWindow.img.Height = (height * AspectRatio);

heightwidth 是图像的尺寸,MonitorInfo 是检索当前显示器分辨率的类。

更新

以下是说明问题的示例 WPF 应用程序的最少代码:

MainWindow.xaml

<Window x:Class="RotateTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        SizeToContent="WidthAndHeight"
        Title="MainWindow" >
    <Grid>
        <Image x:Name="img" Stretch="Fill" Source="https://w.wallhaven.cc/full/nk/wallhaven-nkrwz1.jpg"/>
    </Grid>
</Window>

MainWindow.xaml.cs

using System;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;

namespace RotateTest
{
    public partial class MainWindow : Window
    {
        int Degrees;

        public MainWindow()
        {
            InitializeComponent();
            ContentRendered += MainWindow_ContentRendered;
            KeyDown += MainWindow_KeyDown;
        }

        private void MainWindow_KeyDown(object sender, KeyEventArgs e)
        {
            switch (e.Key)
            {                
                case Key.Up:
                    Rotate(true);
                    break;
                case Key.Down:
                    Rotate(false);
                    break;

            }
        }

        private void MainWindow_ContentRendered(object sender, EventArgs e)
        {
            int interfaceHeight = 90;
            double maxWidth = Math.Min(SystemParameters.PrimaryScreenWidth, img.Source.Width);
            double maxHeight = Math.Min(SystemParameters.PrimaryScreenHeight - interfaceHeight, img.Source.Height);
            double AspectRatio = Math.Min((maxWidth / img.Source.Width), (maxHeight / img.Source.Height));
            img.Width = (img.Source.Width * AspectRatio);
            img.Height = (img.Source.Height * AspectRatio);
        }

        void Rotate(int degrees)
        {
            var rt = new RotateTransform { Angle = Degrees = degrees };
            img.LayoutTransform = rt;
        }

        void Rotate(bool right)
        {
            switch (Degrees)
            {
                case 0:
                    if (right)
                    {
                        Rotate(270);
                    }
                    else
                    {
                        Rotate(90);
                    }

                    break;

                case 90:
                    if (right)
                    {
                        Rotate(0);
                    }
                    else
                    {
                        Rotate(180);
                    }

                    break;

                case 180:
                    if (right)
                    {
                        Rotate(90);
                    }
                    else
                    {
                        Rotate(270);
                    }

                    break;

                case 270:
                    if (right)
                    {
                        Rotate(180);
                    }
                    else
                    {
                        Rotate(0);
                    }

                    break;
            }
        }
    }
}

【问题讨论】:

    标签: c# wpf image-rotation


    【解决方案1】:

    问题的根源在于您只是在图像未旋转时根据图像的大小计算缩放比例。旋转图像后,img.ActualHeight 有效地变为其宽度,img.ActualWidth 有效地变为其高度,并且您从图像未旋转时的计算不再正确。

    以下是我对您的代码所做的更改和添加:

    private double normalRatio;
    private double rotatedRatio;
    
    private void MainWindow_ContentRendered(object sender, EventArgs e)
    {
        double interfaceHeight = this.ActualHeight - img.ActualHeight;
    
        normalRatio = Math.Min(SystemParameters.WorkArea.Width / img.Source.Width, (SystemParameters.WorkArea.Height - interfaceHeight) / img.Source.Height);
        rotatedRatio = Math.Min(SystemParameters.WorkArea.Width / img.Source.Height, (SystemParameters.WorkArea.Height - interfaceHeight) / img.Source.Width);
    
        ScaleImage();
    }
    
    private void ScaleImage()
    {
        double ratio = Degrees == 0 || Degrees == 180 ? normalRatio : rotatedRatio;
        img.Width = (img.Source.Width * ratio);
        img.Height = (img.Source.Height * ratio);
    }
    
    void Rotate(bool right)
    {
        if (right)
        {
            Degrees -= 90;
            if (Degrees < 0) { Degrees += 360; }
        }
        else
        {
            Degrees += 90;
            if (Degrees >= 360) { Degrees -= 360; }
        }
    
        ScaleImage();
        Rotate(Degrees);
    }
    
    //I left the other methods, including Rotate(int degrees), the same as in your question
    

    以下是对我所做更改的说明:

    • interfaceHeight 的计算方法是从窗口的高度减去图像的高度,差值就是其他所有内容的总大小。
    • 我不使用MonitorInfo,而是使用SystemParameters.WorkArea,因为它考虑了Windows 任务栏的大小和位置。
    • 我计算两个缩放比例:normalRatio,当图像不旋转或垂直翻转(180°)时,rotatedRatio,当图像旋转90°时任一方向。我通过交换 img.Source.Heightimg.Source.Width 来计算后者。
    • 我添加了一个ScaleImage() 方法来根据预期的旋转进行实际的图像缩放,因此我可以从两个不同的地方调用它。
    • 我简化了 Rotate(bool right) 以使用数学计算新角度,而不是列出每个可能的旋转。

    以上结果在保持原始纵横比的同时,始终使屏幕尽可能大的图像。当它旋转以适应屏幕时,它会增长和缩小。如果您希望图像保持不变大小,只需使用Math.Min(normalRatio, rotatedRatio)

    请注意,上述方法仅适用于您调用Rotate(bool right)如果您直接调用Rotate(int degrees)。这是因为使用两个比率的逻辑仅适用,因为图像只有两种可能的尺寸(纵向和横向),仅当您将旋转限制为 90° 增量时才会出现这种情况。如果您想将角度设置为其他值,例如 20°,计算图像有效尺寸的数学会变得有点复杂,您需要开始根据角度动态计算它。

    【讨论】:

      猜你喜欢
      • 2015-02-28
      • 2018-12-19
      • 2011-04-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-22
      相关资源
      最近更新 更多