Поворот изображения в Silverlight без обрезки - PullRequest
3 голосов
/ 24 марта 2010

В настоящее время я работаю над простым приложением Silverlight, которое позволит людям загружать изображение, обрезать, изменять его размер и поворачивать его, а затем загружать его через веб-сервис в CMS.

Кадрирование и изменение размера выполнено, однако вращение вызывает некоторые проблемы. Изображение обрезается и смещается от центра после поворота.

WriteableBitmap wb = new WriteableBitmap(destWidth, destHeight);

RotateTransform rt = new RotateTransform();
rt.Angle = 90;
rt.CenterX = width/2;
rt.CenterY = height/2;

//Draw to the Writeable Bitmap
Image tempImage2 = new Image();
tempImage2.Width = width;
tempImage2.Height = height;
tempImage2.Source = rawImage;

wb.Render(tempImage2,rt);
wb.Invalidate();
rawImage = wb;

message.Text = "h:" + rawImage.PixelHeight.ToString();
message.Text += ":w:" + rawImage.PixelWidth.ToString();

//Finally set the Image back
MyImage.Source = wb;
MyImage.Width = destWidth;
MyImage.Height = destHeight;

Приведенный выше код должен поворачиваться только на 90 °, поэтому я просто устанавливаю destWidth и destHeight для высоты и ширины исходного изображения.

Ответы [ 4 ]

7 голосов
/ 24 марта 2010

Похоже, ваше целевое изображение имеет тот же размер, что и исходное изображение. Если вы хотите повернуть более чем на 90 градусов, ваши ширина и высота должны быть изменены:

WriteableBitmap wb = new WriteableBitmap(destHeight, destWidth);

Кроме того, если вы поворачиваете вокруг центра исходного изображения, его часть окажется за пределами границ. Вы можете включить некоторые трансляционные преобразования или просто повернуть изображение относительно другой точки:

rt.CenterX = rt.CenterY = Math.Min(width / 2, height / 2);

Попробуйте с кусочком прямоугольной бумаги, чтобы понять, почему это имеет смысл.

2 голосов
/ 17 октября 2011

Большое спасибо тем, кто выше. Они очень помогли. Я включил здесь простой пример, который включает в себя дополнительное преобразование, необходимое для перемещения повернутого изображения обратно в верхний левый угол результата.

        int width = currentImage.PixelWidth;
        int height = currentImage.PixelHeight;
        int full = Math.Max(width, height);

        Image tempImage2 = new Image();
        tempImage2.Width = full;
        tempImage2.Height = full;
        tempImage2.Source = currentImage;

        // New bitmap has swapped width/height
        WriteableBitmap wb1 = new WriteableBitmap(height,width);


        TransformGroup transformGroup = new TransformGroup();

        // Rotate around centre
        RotateTransform rotate = new RotateTransform();
        rotate.Angle = 90;
        rotate.CenterX = full/2;
        rotate.CenterY = full/2;
        transformGroup.Children.Add(rotate);

        // and transform back to top left corner of new image
        TranslateTransform translate = new TranslateTransform();
        translate.X = -(full - height) / 2;
        translate.Y = -(full - width) / 2;
        transformGroup.Children.Add(translate);



        wb1.Render(tempImage2, transformGroup);
        wb1.Invalidate();
0 голосов
/ 01 декабря 2016

Вам необходимо рассчитать масштабирование на основе поворота углов относительно центра.

Если изображение квадратное, необходим только один угол, но для прямоугольника необходимо проверить 2 угла, чтобы увидеть, перекрывается ли вертикальный или горизонтальный край. Эта проверка представляет собой линейное сравнение того, насколько превышены высота и ширина прямоугольника.

Нажмите здесь, чтобы создать рабочее приложение для испытаний, созданное для этого ответа (рисунок ниже):

enter image description here

double CalculateConstraintScale(double rotation, int pixelWidth, int pixelHeight)

Псевдокод выглядит следующим образом (фактический код C # в конце):

  • Преобразовать угол поворота в радианы
  • Рассчитать "радиус" от центра прямоугольника до угла
  • Преобразование углового положения БР в полярные координаты
  • Преобразовать угловое положение BL в полярные координаты
  • Применить вращение к обеим полярным координатам
  • Преобразование новых позиций обратно в декартовы координаты (значение ABS)
  • Найти наибольшее из двух горизонтальных положений
  • Найти наибольшее из 2 вертикальных положений
  • Рассчитать дельта-изменение для горизонтального размера
  • Рассчитать дельта-изменение для вертикального размера
  • Возвращает ширину / 2 / x, если горизонтальное изменение больше
  • Возврат высоты / 2 / y, если вертикальное изменение больше

Результатом является множитель, который уменьшит изображение до исходного прямоугольника независимо от поворота.

** Примечание. Хотя большую часть математики можно выполнить с помощью матричных операций, для этого недостаточно вычислений. Я также думал, что это послужит лучшим примером из первых принципов. *

C # код:

    /// <summary>
    /// Calculate the scaling required to fit a rectangle into a rotation of that same rectangle
    /// </summary>
    /// <param name="rotation">Rotation in degrees</param>
    /// <param name="pixelWidth">Width in pixels</param>
    /// <param name="pixelHeight">Height in pixels</param>
    /// <returns>A scaling value between 1 and 0</returns>
    /// <remarks>Released to the public domain 2011 - David Johnston (HiTech Magic Ltd)</remarks>
    private double CalculateConstraintScale(double rotation, int pixelWidth, int pixelHeight)
    {
        // Convert angle to radians for the math lib
        double rotationRadians = rotation * PiDiv180;

        // Centre is half the width and height
        double width = pixelWidth / 2.0;
        double height = pixelHeight / 2.0;
        double radius = Math.Sqrt(width * width + height * height);

        // Convert BR corner into polar coordinates
        double angle = Math.Atan(height / width);

        // Now create the matching BL corner in polar coordinates
        double angle2 = Math.Atan(height / -width);

        // Apply the rotation to the points
        angle += rotationRadians;
        angle2 += rotationRadians;

        // Convert back to rectangular coordinate
        double x = Math.Abs(radius * Math.Cos(angle));
        double y = Math.Abs(radius * Math.Sin(angle));
        double x2 = Math.Abs(radius * Math.Cos(angle2));
        double y2 = Math.Abs(radius * Math.Sin(angle2));

        // Find the largest extents in X & Y
        x = Math.Max(x, x2);
        y = Math.Max(y, y2);

        // Find the largest change (pixel, not ratio)
        double deltaX = x - width;
        double deltaY = y - height;

        // Return the ratio that will bring the largest change into the region
        return (deltaX > deltaY) ? width / x : height / y;
    }

Пример использования:

    private WriteableBitmap GenerateConstrainedBitmap(BitmapImage sourceImage, int pixelWidth, int pixelHeight, double rotation)
    {
        double scale = CalculateConstraintScale(rotation, pixelWidth, pixelHeight);

        // Create a transform to render the image rotated and scaled
        var transform = new TransformGroup();
        var rt = new RotateTransform()
            {
                Angle = rotation,
                CenterX = (pixelWidth / 2.0),
                CenterY = (pixelHeight / 2.0)
            };
        transform.Children.Add(rt);
        var st = new ScaleTransform()
            {
                ScaleX = scale,
                ScaleY = scale,
                CenterX = (pixelWidth / 2.0),
                CenterY = (pixelHeight / 2.0)
            };
        transform.Children.Add(st);

        // Resize to specified target size
        var tempImage = new Image()
            {
                Stretch = Stretch.Fill,
                Width = pixelWidth,
                Height = pixelHeight,
                Source = sourceImage,
            };
        tempImage.UpdateLayout();

        // Render to a writeable bitmap
        var writeableBitmap = new WriteableBitmap(pixelWidth, pixelHeight);
        writeableBitmap.Render(tempImage, transform);
        writeableBitmap.Invalidate();
        return writeableBitmap;
    }

Я выпустил тестовый стенд кода на своем сайте, чтобы вы могли попробовать его по-настоящему - нажмите, чтобы попробовать

P.S. Да, это мой ответ на другой вопрос, точно дублированный, но для ответа на этот вопрос требуется тот же ответ, что и тот.

0 голосов
/ 24 марта 2010

Если изображение не квадратное, вы получите обрезку.

Я знаю, что это не даст вам точно правильный результат, вам нужно будет обрезать его впоследствии, но оно создаст растровое изображение, достаточно большое в каждом направлении, чтобы получить повернутое изображение.

    //Draw to the Writeable Bitmap
    Image tempImage2 = new Image();
    tempImage2.Width = Math.Max(width, height);
    tempImage2.Height = Math.Max(width, height);
    tempImage2.Source = rawImage;
...