martedì 1 novembre 2011

[VB.NET] Rotazione Immagini

Descrizione :
Una mia tecnica per ottenere la rotazione di immagini di un numero di gradi X ( intero ) desiderato. Supporta immagini Bmp, Jpg, Png, Gif, e relative eventuali trasparenze.

+ Articolo :

Sfruttando l'utilissima classe System.Drawing.Drawing2D.Matrix, posso applicare trasformazioni geometriche, inclusa la rotazione attorno ad un punto di coordinate opportune ( nel mio caso, il centro del parallelogramma-immagine ).

Sul Web ci sono vari esempi di gente che ha risolto il problema con un autentico "fiume di codice" ( rotazione, una bella dose di trigonometria, e poi definizione caso per caso dei vertici ( PointF ) del disegno... ).

La mia soluzione è invece la seguente :

1. Una Function, che riceve in ingresso la bitmap che si desidera ruotare, l'angolo, il colore da dare alle regioni esterne che si vengono ovviamente a creare a causa della rotazione, e produce in uscita la nuova Bmp ruotata, che chiaramente sarà più grande di quella originale.

Faccio inoltre notare che la mia Function non fa nessun uso "furbo" di oggetti dell'interfaccia grafica WinForms, come PictureBox ecc...

    Public Function RotazioneBMP(ByVal BMPInput As Bitmap, ByVal angoloRotazione As Single, ByVal coloreSfondo As Brush) As Bitmap

        'Angolo di rotazione desiderato
        Dim radianti As Double = angoloRotazione * Math.PI / 180
        'Dimensioni di BMPInput 
        Dim bmpW As Integer = BMPInput.Width
        Dim bmpH As Integer = BMPInput.Height
        'Bitmap di output
        'Dimensioni
        Dim bmpOutW As Integer = bmpW * Math.Abs(Math.Cos(radianti)) + bmpH * Math.Abs(Math.Sin(radianti))
        Dim bmpOutH As Integer = bmpH * Math.Abs(Math.Cos(radianti)) + bmpW * Math.Abs(Math.Sin(radianti))
        Dim BMPOutput As New Bitmap(bmpOutW, bmpOutH)
        Dim G As Graphics = Graphics.FromImage(BMPOutput)
        'Colore di sfondo per le regioni esterne 
        G.FillRectangle(coloreSfondo, 0, 0, bmpOutW, bmpOutH)
        'Disegno / Rotazione di BMPInput su BMPOutput
        Dim M As New System.Drawing.Drawing2D.Matrix
        M.RotateAt(angoloRotazione, New PointF(bmpOutW / 2, bmpOutH / 2)) 'Centro della rotazione
        G.Transform = M
        G.DrawImage(BMPInput, CInt((bmpOutW - BMPInput.Width) / 2), CInt((bmpOutH - BMPInput.Height) / 2))
        Return BMPOutput

    End Function

2. La Form di test è molto semplice : bastano una PictureBox e un NumericUpDown ( "num_angolo" : da -1 a 360 ) per visualizzare i risultati delle rotazioni.

Il codice completo per questa FormMain è il seguente :
Public Class FormMain

    Private percorso As String = Application.StartupPath & "\"
    Private BMP As New Bitmap(percorso & "test.jpg")

    Private Sub FormMain_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        With num_angolo
            .Minimum = -1
            .Maximum = 360
            .Value = 0
        End With

        With PictureBox1
            .SizeMode = PictureBoxSizeMode.AutoSize '.Normal, ecc...
            .Image = BMP
        End With
     
    End Sub

    Private Sub num_angolo_ValueChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles num_angolo.ValueChanged

        If num_angolo.Value = num_angolo.Maximum Then num_angolo.Value = num_angolo.Minimum + 1
        If num_angolo.Value = num_angolo.Minimum Then num_angolo.Value = num_angolo.Maximum - 1

        PictureBox1.Image = RotazioneBMP(BMP, num_angolo.Value, Brushes.Red)

    End Sub

End Class

Come si può notare, ho riportato nel Load alcune impostazioni :

--> Per num_angolo il Minimum a -1 ( anzichè 0 ), unito alle prime due righe di codice nel ValueChanged, serve ad ottenere un NumericUpDown "senza fine", ossia che ricomincia il conteggio ciclicamente, una volta raggiunto il suo valore massimo o minimo.

--> Il SizeMode della PictureBox su AutoSize permette di vedere tutta la nuova BMP, come nella figura seguente :


+ Fine Articolo.

Un Click su "Mi Piace" è il modo migliore per ringraziare l'autore di questo articolo.



2 commenti:

Anonimo ha detto...

Grazie, ho capito più cose dal tuo codice che da due 'professionisti' di grafica

Anonimo ha detto...

Ciao Marco ... il tuo codice è molto compatto e funzionale. Purtroppo mi servirebbe ruotare un immagine senza che questa cambi posizione ... mi spiego meglio: supponiamo di avere un immagine con al suo centro, nel senso dell'altezza e della larghezza un CHIODO. Quando facciamo ruotare l'immagine, la sua posizione rimane fissa ... per intenderci, se l'immagine fosse un quadrato, ruotando su stessa, descriverebbe un cerchio ... perchè invece il tuo codice durante la rotazione, cambia la posizione dell'immagine? cosa devo modificare?

Posta un commento

 
Design by Free WordPress Themes Modificato da MarcoGG