Rotate and Resize Bitmap

Member #857553 0 Tallied Votes 981 Views Share
''' <summary>
    ''' Returns a new copy of the bitmap passed in.  The new copy is rotated
    ''' to the specified degree and resized to fit its new bounding box.
    ''' </summary>
    ''' <remarks>
    ''' The Original Bitmap should be the bitmap that has never been rotated.
    ''' If you keep rotating the same image the image will become distorted.
    ''' </remarks>
    Private Function RotateAndResize(ByRef Original_Bitmap As Bitmap, ByRef Angle As Double) As Bitmap

        'First store our original points into an array so we can pass
        'them to the matrix to get our new rotated points.
        Dim BoxCorners As Point() = {New Point(0, 0), _
                                    New Point(Original_Bitmap.Width, 0), _
                                    New Point(Original_Bitmap.Width, Original_Bitmap.Height), _
                                    New Point(0, Original_Bitmap.Height)}

        Dim M As New Matrix

        'Apply a rotation transform and rotate our original corners.
        M.RotateAt(Angle, New PointF(Original_Bitmap.Width / 2, Original_Bitmap.Height / 2))
        M.TransformPoints(BoxCorners)

        'Now get the size of the new box.
        Dim left, right, top, bottom As Integer
        For i = 0 To UBound(BoxCorners)
            If BoxCorners(i).X < left Then
                left = BoxCorners(i).X
            ElseIf BoxCorners(i).X > right Then
                right = BoxCorners(i).X
            End If

            If BoxCorners(i).Y < top Then
                top = BoxCorners(i).Y
            ElseIf BoxCorners(i).Y > bottom Then
                bottom = BoxCorners(i).Y
            End If
        Next

        'Initialize a new bitmap, get the new x and y start cooridinates which
        'is half the of new box size - the old box size, set the
        'graphics object to the new image.
        Dim RotatedBitmap = New Bitmap(right - left, bottom - top)
        Dim x As Integer = Math.Abs(RotatedBitmap.Width - Original_Bitmap.Width) / 2
        Dim y As Integer = Math.Abs(RotatedBitmap.Height - Original_Bitmap.Height) / 2
        Dim g As Graphics = Graphics.FromImage(RotatedBitmap)

        'reset the matrix, rotate it to our new box: set the graphics tranform, and
        'draw the image.
        M.Reset()
        M.RotateAt(Angle, New PointF(RotatedBitmap.Width / 2, RotatedBitmap.Height / 2))
        g.Transform = M
        g.DrawImage(Original_Bitmap, New Rectangle(x, y, Original_Bitmap.Width, Original_Bitmap.Height))

        M.Dispose()
        g.Dispose()

        'Our new rotated and resized bitmap.
        Return RotatedBitmap

    End Function

Dani AI

Generated

Good baseline — 's approach of transforming the four image corners and using that bounding box to create a new Bitmap is the correct high-level method for arbitrary-angle rotation. The original 90–270 problem is a common symptom when min/max variables are left uninitialized or when integer rounding drops needed precision. Switching the corner array to PointF, normalizing the angle, and preserving the original image's resolution and pixel format make the result more robust and higher quality.

Practical, non-invasive improvements:

  • Use PointF for corner coordinates so the Matrix's float results are not truncated before computing min/max.
  • Preserve source resolution and pixel format on the new bitmap:
    Dim rotated = New Bitmap(width, height, original.PixelFormat)
    rotated.SetResolution(original.HorizontalResolution, original.VerticalResolution)
  • Prefer Using blocks for Graphics/Matrix to ensure disposal (avoid manual Dispose calls scattered through code).
  • Short-circuit exact multiples of 90° with Image.RotateFlip for a lossless, faster path. Normalize the angle (Angle = ((Angle Mod 360) + 360) Mod 360) before testing.

Quality, alpha, and performance notes:

  • For best visual results set Graphics.InterpolationMode, SmoothingMode and PixelOffsetMode appropriately (e.g., HighQualityBicubic for photos). Clear the destination with Color.Transparent when using alpha-backed PixelFormats.
  • Avoid ByRef for the input Bitmap/Angle unless intentional; return a new Bitmap and let callers dispose of unused Bitmaps.
  • Remember to round offsets consistently (Math.Round / Math.Floor) when converting float positions to integer pixel coordinates to avoid off-by-one shifts.

These changes keep the same algorithm while fixing edge cases, preserving image metadata, and reducing subtle artifacts.

Member Avatar for Member #857553
Member #857553

Edit.

I made this for no reason. Turns out I needed it. After putting it to the test it has some issues. It doesn't work for angles 90 - 270.

This fixes it.

Private Function RotateAndResize(ByRef Original_Bitmap As Bitmap, ByRef Angle As Double) As Bitmap

        Dim BoxCorners As Point() = {New Point(0, 0), _
                                    New Point(Original_Bitmap.Width, 0), _
                                    New Point(Original_Bitmap.Width, Original_Bitmap.Height), _
                                    New Point(0, Original_Bitmap.Height)}

        Dim M As New Matrix
        M.RotateAt(Angle, New PointF(Original_Bitmap.Width / 2, Original_Bitmap.Height / 2))
        M.TransformPoints(BoxCorners)

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

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

        Dim RotatedBitmap = New Bitmap(right - left, bottom - top)
        Dim x As Integer = (RotatedBitmap.Width - Original_Bitmap.Width) / 2
        Dim y As Integer = (RotatedBitmap.Height - Original_Bitmap.Height) / 2
        Dim g As Graphics = Graphics.FromImage(RotatedBitmap)

        M.Reset()
        M.RotateAt(Angle, New PointF(RotatedBitmap.Width / 2, RotatedBitmap.Height / 2))

        g.Transform = M
        g.DrawImage(Original_Bitmap, New Rectangle(x, y, Original_Bitmap.Width, Original_Bitmap.Height))

        M.Dispose()
        g.Dispose()

        Return RotatedBitmap

    End Function
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.