Silverlight 旋转 &缩放位图图像以适应矩形而无需裁剪 [英] Silverlight Rotate & Scale a bitmap image to fit within rectangle without cropping

查看:14
本文介绍了Silverlight 旋转 &缩放位图图像以适应矩形而无需裁剪的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要旋转 WriteableBitmap 并在裁剪之前缩小或放大它.

如果高度大于宽度,我当前的代码将旋转但会裁剪边缘.

我认为我需要扩展?

 public WriteableBitmap Rotate(WriteableBitmap Source, double Angle){RotateTransform rt = new RotateTransform();rt.Angle = 角度;TransformGroup transform = new TransformGroup();变换.Children.Add(rt);图像 tempImage2 = new Image();WriteableBitmap wb;rt.CenterX = Source.PixelWidth/2;rt.CenterY = Source.PixelHeight/2;tempImage2.Width = Source.PixelWidth;tempImage2.Height = Source.PixelHeight;wb = new WriteableBitmap((int)(Source.PixelWidth), Source.PixelHeight);tempImage2.Source = 源;tempImage2.UpdateLayout();wb.Render(tempImage2, 变换);wb.Invalidate();返回 wb;}

如何缩小图像以使其不会被裁剪?或者有其他方法吗?

解决方案

您需要根据角相对于中心的旋转来计算缩放比例.

如果图像是正方形,则只需要一个角,但对于矩形,您需要检查 2 个角,以查看垂直或水平边缘是否重叠.此检查是对超出矩形高度和宽度的程度进行线性比较.

(抱歉,我所有的网站内容都丢失了,这要归功于一家不太棒的托管公司)

I need to rotate a WriteableBitmap and scale it down or up before it gets cropped.

My current code will rotate but will crop the edges if the height is larger then the width.

I assume I need to scale?

 public WriteableBitmap Rotate(WriteableBitmap Source, double Angle)
        {
            RotateTransform rt = new RotateTransform();
            rt.Angle = Angle;

            TransformGroup transform = new TransformGroup();
            transform.Children.Add(rt);

            Image tempImage2 = new Image();
            WriteableBitmap wb;
            rt.CenterX = Source.PixelWidth / 2;
            rt.CenterY = Source.PixelHeight / 2;
            tempImage2.Width = Source.PixelWidth;
            tempImage2.Height = Source.PixelHeight;
            wb = new WriteableBitmap((int)(Source.PixelWidth), Source.PixelHeight);
            tempImage2.Source = Source;
            tempImage2.UpdateLayout();

            wb.Render(tempImage2, transform);
            wb.Invalidate();

            return wb;

        }

How do I scale down the image so it will not be cropped? Or is there another way?

解决方案

You need to calculate the scaling based on the rotation of the corners relative to the centre.

If the image is a square only one corner is needed, but for a rectangle you need to check 2 corners in order to see if a vertical or horizontal edge is overlapped. This check is a linear comparison of how much the rectangle's height and width are exceeded.

Click here for the working testbed app created for this answer (image below): (apologies, all my website content was lost thanks to a non-awesome hosting company)

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

The pseudo-code is as follows (actual C# code at the end):

  • Convert rotation angle into Radians
  • Calculate the "radius" from the rectangle centre to a corner
  • Convert BR corner position to polar coordinates
  • Convert BL corner position to polar coordinates
  • Apply the rotation to both polar coordinates
  • Convert the new positions back to Cartesian coordinates (ABS value)
  • Find the largest of the 2 horizontal positions
  • Find the largest of the 2 vertical positions
  • Calculate the delta change for horizontal size
  • Calculate the delta change for vertical size
  • Return width/2 / x if horizontal change is greater
  • Return height/2 / y if vertical change is greater

The result is a multiplier that will scale the image down to fit the original rectangle regardless of rotation.

*Note: While it is possible to do much of the maths using matrix operations, there are not enough calculations to warrant that. I also thought it would make a better example from first-principles.

C# Code:

    /// <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;
    }

Example of use:

    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;
    }

I released a Test-bed of the code on my website so you can try it for real - click to try it (apologies, all my website content was lost thanks to a non-awesome hosting company)

这篇关于Silverlight 旋转 &amp;缩放位图图像以适应矩形而无需裁剪的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆