在WPF中旋转图像不尊重屏幕大小。

问题描述 投票:0回答:1

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

屏幕截图示例。应用程序运行时,图像以90º旋转应用程序运行时图像为0º

我使用的是下面的代码(简化版),其中包括 mainWindow.img 作为 System.Windows.Control.Image:

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

这是一个图片查看器项目,完整的源代码可在以下网站获得。https:/github.comRuben2776PicView

我试过移动图像的宽度和高度值,但产生了不理想的结果(比例偏斜)。

图片大小的计算是根据用户的屏幕高度进行的,使用下面的修剪代码。

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>

主窗口.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个回答
2
投票

问题的根源是你只根据图像的大小计算你的缩放比例。不旋转时. 一旦你旋转图像。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 是通过从窗口的高度中减去图像的高度来计算的,差额就是其他所有东西的aggrigate大小。
  • 而不是使用 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°,计算图像有效尺寸的数学就会变得有点复杂,你需要根据角度开始动态计算。

© www.soinside.com 2019 - 2024. All rights reserved.