如何旋转图像并保持原始尺寸?

3
我一直在试图旋转一张图片,但是我遇到了一些问题。第一块代码可以工作,但它造成了一个不良的副作用:在旋转后,图片被缩小以使x维度匹配现有的y维度。
因此,我旋转了图片,但它只占据了画布的一部分。
为了解决这个问题,我想我应该创建一个更大的位图作为中间步骤,这样当它被旋转时,图片就不需要缩小以适应。
第二段代码实现了这一点。不幸的是,当我运行它时,我得到了一个通用的GDI错误。
有人知道我做错了什么吗?
有效示例:
Imports System.Drawing

If XSize < YSize Then 'Needs to be rotated
    Dim img As Image = Image.FromFile(strFilename)

    Dim b = New Bitmap(img.Height, img.Width)
    Dim gr As Graphics = Graphics.FromImage(b)
    img.RotateFlip(RotateFlipType.Rotate90FlipNone)
    gr.DrawImage(img, New Point(0, 0))
    img = Nothing
    b.Save(strFilename)
End If

这段代码不起作用:

'Needs to be rotated
If XSize < YSize Then 
    Dim img As Image = Image.FromFile(strFilename)
    Dim bmpTemp As Image

    If img.Height > img.Width Then
        bmpTemp = New Bitmap(img.Height, img.Height)
    Else
        bmpTemp = New Bitmap(img.Width, img.Width)
    End If

    Dim gr2 As Graphics = Graphics.FromImage(bmpTemp)
    gr2.DrawImage(img, New Point(0, 0))

    Dim b = New Bitmap(img.Height, img.Width)
    Dim gr As Graphics = Graphics.FromImage(b)
    bmpTemp.RotateFlip(RotateFlipType.Rotate90FlipNone)
    gr.DrawImage(bmpTemp, New Point(0, 0))
    img = Nothing
    b.Save(strFilename)
End If

1
错误发生在哪一行?这段代码在我的机器上可以运行。顺便说一下,RotateFlip 不会缩放任何东西,所以我不确定你想要实现什么。 - Nico Schertler
@NicoSchertler,它发生在最后一行,即b.Save(strFileName)。真的吗?即使画布不足以正确旋转,它也不能扩展吗?这很奇怪。在我的应用程序中,它绝对似乎是这样做的。谢谢。 - Peter F
1
那么文件可能仍然在某个地方打开。该函数只是在图像中移动像素(并交换宽度和高度)。它实际上无法进行缩放。如果图像看起来被缩放了,这可能是由于您显示它的方式。 - Nico Schertler
1个回答

1

我不太清楚您希望如何旋转图像。问题是旋转轴、旋转后图像的新尺寸还是其他什么?

无论如何,根据我的猜测,以下代码片段将图像围绕画布边缘或中心点旋转。

Private Function RotateImage(ByVal src As Bitmap,
                            ByVal width As Integer,
                            ByVal height As Integer,
                            ByVal angle As Single,
                            Optional ByVal CenterRotation As Boolean = False) As Bitmap

   Dim cornors As Point() = {New Point(0, 0),
                        New Point(width, 0),
                        New Point(width, height),
                        New Point(0, height)}
   Using m As New Matrix
    If Not CenterRotation Then
        m.RotateAt(angle, New PointF(width / 2, height / 2))
        m.TransformPoints(cornors)
    End If

    Dim left = Integer.MaxValue
    Dim right = Integer.MinValue
    Dim top = Integer.MaxValue
    Dim bottom = Integer.MinValue

    For i = 0 To UBound(cornors)
        If cornors(i).X < left Then left = cornors(i).X
        If cornors(i).X > right Then right = cornors(i).X
        If cornors(i).Y < top Then top = cornors(i).Y
        If cornors(i).Y > bottom Then bottom = cornors(i).Y
    Next

    Dim b As New Bitmap(right - left, bottom - top)
    Dim x = (b.Width - width) / 2
    Dim y = (b.Height - height) / 2

    Using g As Graphics = Graphics.FromImage(b)
        m.Reset()
        m.RotateAt(angle, New PointF(b.Width / 2, b.Height / 2))
        g.Transform = m
        g.InterpolationMode = InterpolationMode.HighQualityBicubic
        g.SmoothingMode = SmoothingMode.HighQuality
        g.CompositingQuality = CompositingQuality.HighQuality
        g.Clear(Color.Transparent)
        g.DrawImage(src, New Rectangle(x, y, width, height))
    End Using
    Return b
   End Using
End Function

如果您还需要调整旋转后的图像大小以适应画布,则需要在第一个代码之后添加以下代码:
Private Function CreateThumbnail(ByVal bmp As Bitmap,
                                    ByVal canvasWidth As Integer,
                                    ByVal canvasHeight As Integer,
                                    Optional Stretch As Boolean = False) As Bitmap

    Dim bmpOut As Bitmap = Nothing

    If Stretch Then
        bmpOut = bmp.GetThumbnailImage(canvasWidth, canvasHeight, Nothing, IntPtr.Zero)
    Else
        Dim newWidth As Integer = 0
            Dim newHeight As Integer = 0

            bmpOut = New Bitmap(canvasWidth, canvasHeight)

            Dim ratioX As Double = CDbl(canvasWidth) / CDbl(bmp.Width)
            Dim ratioY As Double = CDbl(canvasHeight) / CDbl(bmp.Height)
            Dim ratio = If(ratioX < ratioY, ratioX, ratioY)

            newWidth = Convert.ToInt32(bmp.Width * ratio)
            newHeight = Convert.ToInt32(bmp.Height * ratio)

            If newWidth > bmp.Width Then
                newWidth = bmp.Width
            End If
            If newHeight > bmp.Height Then
                newHeight = bmp.Height
            End If

            Dim posX = Convert.ToInt32((canvasWidth - newWidth) / 2)
            Dim posY = Convert.ToInt32((canvasHeight - newHeight) / 2)

            Using g As Graphics = Graphics.FromImage(bmpOut)
                g.InterpolationMode = InterpolationMode.HighQualityBicubic
                g.SmoothingMode = SmoothingMode.HighQuality
                g.CompositingQuality = CompositingQuality.HighQuality
                g.Clear(Color.Transparent)
                g.DrawImage(bmp, posX, posY, newWidth, newHeight)
            End Using
        End If

    Return bmpOut
End Function

这里是一个快速演示:

Image Rotation Demo

祝你好运。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接