c# - Silverlight 旋转和缩放位图图像以适合矩形而不裁剪

标签 c# silverlight windows-phone-7 rotation windows-phone

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

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

我假设我需要扩展?

 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;

        }

如何缩小图像以使其不被裁剪?还是有别的办法?

最佳答案

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

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

Click here for the working testbed app created for this answer (image below): (抱歉,由于托管公司不是很好,我所有的网站内容都丢失了)

enter image description here

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

伪代码如下(最后是实际的C#代码):

  • 将旋转角度转换为弧度
  • 计算从矩形中心到一个角的“半径”
  • 将BR角位置转换为极坐标
  • 将BL角位置转换为极坐标
  • 将旋转应用于两个极坐标
  • 将新位置转换回笛卡尔坐标(ABS 值)
  • 找到 2 个水平位置中最大的一个
  • 找到 2 个垂直位置中最大的一个
  • 计算水平尺寸的增量变化
  • 计算垂直尺寸的增量变化
  • 如果水平变化较大则返回 width/2/x
  • 如果垂直变化较大则返回 height/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;
    }

I released a Test-bed of the code on my website so you can try it for real - click to try it (抱歉,由于托管公司不太好,我所有的网站内容都丢失了)

关于c# - Silverlight 旋转和缩放位图图像以适合矩形而不裁剪,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6801546/

相关文章:

银光 4 : ToolTipService

.net - 如何开始使用适用于 WP7 的 Facebook C# SDK?

c# - 为输入创建非矩形控件

wpf - MVVM-Light 工具包 V4 Beta 中的 IDataService

c# - 将 C# 8 可空引用类型标记为 "this can' t 为空”

c# - Key Input Bindings 与 CommandParameter 用法伯顿绑定(bind)

android - 保护 WCF Web 服务,保持与 Android 和 Silverlight 的兼容性

silverlight - 为 Windows Phone 7 silverlight 中的控件创建平铺背景图像

c# - MessageBoxResult 与 DialogResult

c# - 为什么包含命名参数会导致 "type arguments for method cannot be inferred from usage"错误?