Silverlight旋转和缩放位图图像以适合矩形而不进行裁剪

我需要旋转一个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个角,以查看垂直或水平边是否重叠。 此检查是线性比较矩形的高度和宽度是多少。

单击此处查看为此答案创建的工作测试平台应用程序(如下图所示):

在此处输入图像描述

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

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

  • 将旋转角度转换为Radians
  • 计算从矩形中心到拐角的“半径”
  • 将BR角位置转换为极坐标
  • 将BL角位置转换为极坐标
  • 将旋转应用于两个极坐标
  • 将新位置转换回笛卡尔坐标(ABS值)
  • 找到2个水平位置中最大的位置
  • 找到2个垂直位置中最大的位置
  • 计算水平尺寸的增量变化
  • 计算垂直尺寸的增量变化
  • 如果水平变化较大,则返回宽度/ 2 / x
  • 如果垂直变化较大,则返回高度/ 2 / y

结果是一个乘数,无论旋转如何,都会缩小图像以适合原始矩形。

**注意:虽然可以使用矩阵运算来完成大部分数学运算,但没有足够的计算来保证这一点。 我还认为它会从第一原则中得到一个更好的例子。*

C#代码:

  ///  /// Calculate the scaling required to fit a rectangle into a rotation of that same rectangle ///  /// Rotation in degrees /// Width in pixels /// Height in pixels /// A scaling value between 1 and 0 /// Released to the public domain 2011 - David Johnston (HiTech Magic Ltd) 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; } 

我在我的网站上发布了代码的测试平台,因此您可以尝试实际 – 点击尝试