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.
2 commenti:
Grazie, ho capito più cose dal tuo codice che da due 'professionisti' di grafica
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