Поворот изображения в WPF без учета размера экрана - PullRequest
0 голосов
/ 30 мая 2020

В настоящее время у меня возникают проблемы при повороте изображения в WPF с использованием RotateTransform и LayoutTransform. Когда изображение, высота которого в пикселях превышает высоту монитора, и повернуто на 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.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);

, где height и width - размеры изображения, а MonitorInfo - класс, который извлекает текущее разрешение монитора.

Обновление

Ниже приведен минимальный код для sa mple 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;
            }
        }
    }
}

1 Ответ

2 голосов
/ 01 июня 2020

Проблема root в том, что вы вычисляете масштабирующую крысу ios только на основе размера изображения, когда оно не повернуто . После поворота изображения 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 панель задач.
  • Я вычисляю два масштаб крысы ios: normalRatio, когда изображение не повернуто или перевернуто по вертикали (180 °), и rotatedRatio, когда изображение повернуто на 90 ° в любом направлении. Я вычисляю последнее, меняя местами img.Source.Height и img.Source.Width.
  • Я добавил метод ScaleImage(), чтобы выполнить фактическое масштабирование изображения на основе предполагаемого поворота, поэтому я могу вызывать его из двух разных мест.
  • Я упростил Rotate(bool right), чтобы вычислить новый угол с помощью математики, вместо перечисления каждого возможного поворота.

Результатом выше является изображение, которое всегда является максимально большим для экран с сохранением исходного соотношения сторон. Он будет увеличиваться и уменьшаться по мере поворота по размеру экрана. Если вы хотите, чтобы изображение оставалось постоянного размера, просто используйте Math.Min(normalRatio, rotatedRatio).

Обратите внимание, что приведенное выше работает, только если вы вызываете Rotate(bool right), не , если вы вызываете Rotate(int degrees) прямо. Это связано с тем, что logi c использования двух крыс ios работает только потому, что есть только два возможных размера изображения (портретный и альбомный), что возможно только в том случае, если вы ограничиваете вращение с шагом 90 °. Если вы хотите установить другой угол, например 20 °, математика для расчета эффективного размера изображения станет немного более сложной, и вам нужно будет начать вычислять его динамически на основе угла.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...