none
Ich würde gerne in der VB.Net Oberfläche einen GDI+ Loop als Gif Dateiformat speichern. Ist das möglich?

    Frage

  • Hallo.

    Ich studiere die GDI+ Möglichkeiten des VB.Net Programms. Es folgt ein kleiner Loop einer graphischen Ausgabe.

    Imports System.Drawing.Drawing2D
    
    Public Class Form1
        Dim WithEvents t As New Timer() With {.Interval = 50}
        Dim zweiPlusZwei As Boolean
        Dim startUndZiel As Integer
        Dim dieEins As Integer
        Dim minus As Integer
    
        Private Sub Form1_Load(sender As Object, e As System.EventArgs) Handles Me.Load
            CenterToScreen()
            t.Start()
            DoubleBuffered = True
            zweiPlusZwei = True
            startUndZiel = 10
            dieEins = 1
            minus = 200
        End Sub
    
        Private Sub Form1_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
            ' Create a GraphicsPath object and add a rectangle to it.
            Dim myPath As New GraphicsPath
            Dim pathRect As New Rectangle(20, startUndZiel, 100, minus) ' falls minus ersetzt wird durch eine Zahl bewegt sich der Monolit so ist es nur eine optische Täuschung
            myPath.AddRectangle(pathRect)
    
            ' Draw the path to the screen.
            Dim myPen As New Pen(Color.Black, 2)
            e.Graphics.DrawPath(myPen, myPath)
        End Sub
    
        Private Sub t_Tick(sender As Object, e As EventArgs) Handles t.Tick
            If zweiPlusZwei = True Then
                If startUndZiel <= 128 Then
                    startUndZiel += dieEins
                    minus -= dieEins
                Else
                    zweiPlusZwei = False
                End If
            End If
    
            If zweiPlusZwei = False Then
                If startUndZiel > 10 Then
                    startUndZiel -= dieEins
                    minus += dieEins
                Else
                    zweiPlusZwei = True
                End If
            End If
            Refresh()
        End Sub
    
    End Class

    Ich wünsche mir die graphische Darstellung gespeichert in einem Gif Dateiformat, so dass ich mir wenn ich die Gif Datei Doppelklicke nur die graphische Bewegung angezeigt wird. Es muss kein Doppelklick sein, das Gif Dateiformat kann auch mit dem Windows Programm Fotos abgespielt werden so das gespeicherte Bewegungen abspielbar sind. Wenn eine Speicherung der Ausgabe des VB.Net Programms möglich ist würde ich gerne Wissen wie das geht. Danke.
    Donnerstag, 9. August 2018 17:17

Antworten

  • Hallo Stefan Mihael Rihar,

    wenn Du die Klasse AnimatedGifEncoder aus dem verlinkten Forumsbeitrag meiner ersten Antwort verwendest, könnte die Implementierung so aussehen:

    Public Class Form1
    
    	Dim WithEvents t As New Timer() With {.Interval = 50}
    	Dim blackPen As New Pen(Color.Black, 3)
    	Dim zweiPlusZwei As Boolean
    	Dim startUndZiel As Integer
    	Dim dieEins As Integer
    	Dim minus As Integer
    	Dim Encoder1 As New AnimatedGifEncoder
    	Public Property MetadataComment As List(Of String) = New List(Of String)
    
    	Private Sub Form1_Load(sender As Object, e As System.EventArgs) Handles Me.Load
    		Me.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None
    		CenterToScreen()
    		t.Start()
    		DoubleBuffered = True
    		zweiPlusZwei = True
    		startUndZiel = 10
    		dieEins = 1
    		minus = 200
    	End Sub
    
    	Private Sub Form1_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
    		DrawRectangleRectangle(e)
    	End Sub
    
    	Private Sub t_Tick(sender As Object, e As EventArgs) Handles t.Tick
    		If zweiPlusZwei = True Then
    			If startUndZiel <= 128 Then
    				startUndZiel += dieEins
    				minus -= dieEins
    			Else
    				zweiPlusZwei = False
    			End If
    		End If
    
    		If zweiPlusZwei = False Then
    			If startUndZiel > 10 Then
    				startUndZiel -= dieEins
    				minus += dieEins
    			Else
    				zweiPlusZwei = True
    			End If
    		End If
    
    		Refresh()
    		castleGrayscul(e)
    	End Sub
    
    
    	Public Sub SaveImage(filename As String)
    		Dim FS As New IO.FileStream(filename, IO.FileMode.Create)
    		Encoder1.FrameRate = t.Interval
    		Encoder1.MetadataString = MetadataComment
    		Encoder1.Repeat = True
    		Encoder1.Save(FS)
    		FS.Flush()
    		FS.Close()
    	End Sub
    
    	Public Sub DrawRectangleRectangle(ByVal e As PaintEventArgs)
    		e.Graphics.DrawRectangle(blackPen, 20, startUndZiel, 100, minus)
    	End Sub
    
    
    	Sub castleGrayscul(ByVal e As EventArgs) 'castleGrayscul versus Monkeyisland. . .
    		Dim bmp As New Bitmap(Width - 16, Height - 39)
    		DrawToBitmap(bmp, New Rectangle(0, 0, bmp.Width, bmp.Height))
    		Encoder1.AddFrame(bmp)
    		bmp.Dispose()
    	End Sub
    
    	Private Sub Form1_FormClosed(sender As Object, e As FormClosedEventArgs) Handles MyBase.FormClosed
    		SaveImage("C:\Temp\Probst.gif")
    	End Sub
    End Class
    Bei den Referenzen müssen ggfls. Assemblies hinzugefügt werden, die von AnimatedGifEncoder verwendet werden (PresentationCore).

    Das Ergebnis sieht dann so aus:


    - Gruß Florian

    Mittwoch, 29. August 2018 09:56
  • Du kannst das Speichern direkt unter t.Stop aufrufen, ggfls. auch gleich die Form schließen.

    - Gruß Florian

    Donnerstag, 30. August 2018 07:15

Alle Antworten

  • Hallo Stefan Mihael Rihar,

    es ist möglich, aber der Encoder muss, so wie hier nachzulesen "Animated GIF encoder .NET" erweitert werden, um den GIF89a Teil - Code für den Encoder und Anwendungsbeispiel sind unter dem Link zu finden.

    Viel Erfolg!


    - Gruß Florian



    • Bearbeitet Florian Haupt Freitag, 10. August 2018 07:37 Tippfehler
    • Als Antwort vorgeschlagen Florian Haupt Freitag, 31. August 2018 07:09
    Freitag, 10. August 2018 07:35
  • Hm. Das wird wohl ungefähr ewig dauern bis ich an der Oberfläche schwimmen lerne. Am liebsten wäre mir ein Beispiel mit meinem Beispiel, dann hätte ich vielleicht ein Eck das hängen bleibt. Den Erfolgswunsch werd ich dringend brauchen.
    Freitag, 10. August 2018 12:06
  • Verstehe ich gerade nicht, wo da jetzt das Problem liegt. Deine Form ist ein Control und daher kannst Du nach jedem Paint oder am Ende einfach DrawToBitmap aufrufen um deine Form in ein Bitmap zu zeichnen, dieses dann als Frame in dein GIF, fertig. Du kannst natürlich auch direkt in deine GIF Frames Zeichnen und dir damit die Form vollständig sparen.

    - Gruß Florian

    Freitag, 10. August 2018 12:43
  • Ich habe noch nicht den Befehl DrawToBitmap aufgerufen. Wird noch etwas Arbeit notwendig sein um das Thema verstehen zu lernen. Direkt in ein GIF Frames zeichnen scheint einfach zu sein doch habe ich auch dazu keinen Begriff. Ich werde mich auch weiterhin bemühen meine Projektarbeiten nicht woanders abzuladen nur manchmal brauch ich einige Hinweise.

    Mit freundlichen Grüßen

    Stefan

    Freitag, 10. August 2018 14:56
  • Hallo Stefan Mihael Rihar,

    die Dokumentation zu Control.DrawToBitmap. Weiterhin benötigst Du die Größe, z. B. über die Size-Eigenschaft (bzw. Width, Height).

    Das gilt dann allgemein für jedes Control:

    • Bitmap in der Größe des Controls anlegen
    • Das Control mit DrawToBitmap ins Bitmap zeichnen lassen

    Bsp.: 

    Dim bmp as New Bitmap(meinControl.Width, meinControl.Height)
    meinControl.DrawToBitmap(bmp, New Rectangle(0,0, bmp.Width, bmp.Height))

    Das bmp kann dann in den Frame gespeichert werden.


    - Gruß Florian

    Montag, 13. August 2018 07:23
  • Mein Vb.Net Studium ohne Universitätszugang wird wohl eine Zeit dauern. Die Frage an der ich mich versuche ist wie ich mit dem Beispiel

    Public Class Form1
    
        Dim bmp As New Bitmap(Me.Width, Me.Height)
    
        Sub kleinerStein(ByVal a As EventArgs) 'castleGrayscul versus Monkeyisland. . .
    
            Me.DrawToBitmap(bmp, New Rectangle(0, 0, bmp.Width, bmp.Height))
    
        End Sub
    
        Private Sub Form1_Load(sender As Object, a As System.EventArgs) Handles Me.Load
    
            kleinerStein(a)
    
        End Sub
    
    End Class
     

    verstehen soll was ich mit meiner Kunst in den Frame speichern soll? Ich übe jeden Tag von Anfang an, falls sich das so bezeichnen lässt Vb.Net in mein Leben zu integrieren. Leider mühsam aber es geht. Das ist wichtig. Und ich würde gerne Wissen ist der Befehl DrawToBitmap ein Zwischenspeicher den ich nicht zu lesen weiß? Sichtbar machen ist für mich sehr wichtig.

    Mit freundlichen Grüßen

    Stefan

    Dienstag, 14. August 2018 18:29
  • Hallo Stefan Mihael Rihar.

    DrawToBitmap ist eine Methode der Klasse Control (Namespace: System.Windows.Forms), welche zwei Parameter hat und keinen Rückgabewert. Der erste Parameter (bitmap) gibt ein Object der Klasse Bitmap (Namespace: System.Drawing) an, auf dem gezeichnet werden soll. Der zweite Parameter (targetBounds) gibt ein Object der Struktur Rectangle (Namespace: System.Drawing) an, welches einen rechteckigen Bereich beschreibt, in dessen Grenzen gezeichnet werden soll.

    Nach dem Aufruf DrawToBitmap wurde in deine Bitmap Variable gezeichnet, die du als Parameter übergeben hast, dieses enthält nun ein Abbild deines Controls, zum Zeitpunkt des Aufrufs. Das Bitmap kann dann auf einem Anzeigegerät ausgegeben werden (Bildschirm, Drucker, ...) oder auch gespeichert (Bitmap hat dafür eine Methode Save) werden.


    - Gruß Florian

    Mittwoch, 15. August 2018 07:35
  • Ich finde keine Hinweis wie ich das Bitmap ( das mit DrawToBitmap eine Variable in meine Bitmap zeichnet ) auf dem Anzeigegerät Bildschirm ausgeben lassen kann.

    Mit freundlichem Gruß

    Stefan

    Donnerstag, 16. August 2018 17:06
  • Hallo, da Du ein Paint Event bereits behandelst

     Private Sub Form1_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint

    weißt Du bereits wo das Zeichnen stattfindet, in diesem Paint Event.

    Es ist natürlich nicht besonders Sinnvoll das Bitmap, welches die aktuelle Form enthält, in dieser auszugeben, aber das grundsätzliche Verfahren zum Anzeigen eines Bitmaps auf dem Bildschirm sollte damit ausreichend illustriert sein, hier unter Verwendung von DrawImage:

    Private Sub Form1_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
    ...
     e.Graphics.DrawImage(bmp, 0, 0)
    End Sub

    - Gruß Florian

    Montag, 20. August 2018 07:28
  • Meine schwache Ausdrucksweise in der Programmiersprache VB.Net ist eine Krücke. Ich habe einen Code aus verschiedenen Quellen zusammengebastelt mit dem ich wennmöglich weiter suchen kann zu verstehen was ich noch immer nicht kann.

    Imports System.Drawing.Drawing2D
    
    Public Class Form1
    
        Dim WithEvents t As New Timer() With {.Interval = 50}
        Dim bmp As New Bitmap(Me.Width - 16, Me.Height - 39)
        Dim blackPen As New Pen(Color.Black, 3)
        Dim zweiPlusZwei As Boolean
        Dim startUndZiel As Integer
        Dim dieEins As Integer
        Dim minus As Integer
    
        Private Sub Form1_Load(sender As Object, e As System.EventArgs) Handles Me.Load
            Me.FormBorderStyle = Windows.Forms.FormBorderStyle.None
            CenterToScreen()
            t.Start()
            DoubleBuffered = True
            zweiPlusZwei = True
            startUndZiel = 10
            dieEins = 1
            minus = 200
        End Sub
    
        Private Sub Form1_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
            DrawRectangleRectangle(e)
        End Sub
    
        Private Sub t_Tick(sender As Object, e As EventArgs) Handles t.Tick
    
            If zweiPlusZwei = True Then
                If startUndZiel <= 128 Then
                    startUndZiel += dieEins
                    minus -= dieEins
                Else
                    zweiPlusZwei = False
                End If
            End If
    
            If zweiPlusZwei = False Then
                If startUndZiel > 10 Then
                    startUndZiel -= dieEins
                    minus += dieEins
                Else
                    zweiPlusZwei = True
                End If
            End If
    
            Refresh()
        End Sub
    
    
        Public Sub SaveImage(filename As String, image As Image)
    
            Dim path As String = System.IO.Path.Combine(My.Application.Info.DirectoryPath, filename & ".Bmp")
    
            Dim mySource As New Bitmap(image.Width, image.Height)
    
            Dim grfx As Graphics = Graphics.FromImage(mySource)
    
            grfx.DrawImageUnscaled(image, Point.Empty)
    
            grfx.Dispose()
    
            mySource.Save(filename, System.Drawing.Imaging.ImageFormat.Bmp)
    
            mySource.Dispose()
    
        End Sub
    
        Public Sub DrawRectangleRectangle(ByVal e As PaintEventArgs)
    
            e.Graphics.DrawRectangle(blackPen, 20, startUndZiel, 100, minus)
            castleGrayscul(e)
    
        End Sub
    
    
        Sub castleGrayscul(ByVal e As EventArgs) 'castleGrayscul versus Monkeyisland. . .
            Me.DrawToBitmap(bmp, New Rectangle(0, 0, bmp.Width, bmp.Height))
            SaveImage("C:\Temp\Probst.bmp", bmp)
        End Sub
    End Class

    Zwei Probleme habe ich weiterhin. Das erste ist noch immer das Hauptthema. Ich kann nun von der Sequenz immer das letzte Bild speichern aber nicht die ganze Sequenz in einer Gif Datei. Das zweite ist wenn ich Sub castleGrayscul verwende dann ist der Ablauf des Loops nicht mehr im flüssigen Interval = 50. Die Spurensuche geht weiter. . .

    Mit freundlichen Grüßen

    Stefan


    Mittwoch, 22. August 2018 17:53
  • Hallo Stefan Mihael Rihar,

    wenn Du die Klasse AnimatedGifEncoder aus dem verlinkten Forumsbeitrag meiner ersten Antwort verwendest, könnte die Implementierung so aussehen:

    Public Class Form1
    
    	Dim WithEvents t As New Timer() With {.Interval = 50}
    	Dim blackPen As New Pen(Color.Black, 3)
    	Dim zweiPlusZwei As Boolean
    	Dim startUndZiel As Integer
    	Dim dieEins As Integer
    	Dim minus As Integer
    	Dim Encoder1 As New AnimatedGifEncoder
    	Public Property MetadataComment As List(Of String) = New List(Of String)
    
    	Private Sub Form1_Load(sender As Object, e As System.EventArgs) Handles Me.Load
    		Me.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None
    		CenterToScreen()
    		t.Start()
    		DoubleBuffered = True
    		zweiPlusZwei = True
    		startUndZiel = 10
    		dieEins = 1
    		minus = 200
    	End Sub
    
    	Private Sub Form1_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
    		DrawRectangleRectangle(e)
    	End Sub
    
    	Private Sub t_Tick(sender As Object, e As EventArgs) Handles t.Tick
    		If zweiPlusZwei = True Then
    			If startUndZiel <= 128 Then
    				startUndZiel += dieEins
    				minus -= dieEins
    			Else
    				zweiPlusZwei = False
    			End If
    		End If
    
    		If zweiPlusZwei = False Then
    			If startUndZiel > 10 Then
    				startUndZiel -= dieEins
    				minus += dieEins
    			Else
    				zweiPlusZwei = True
    			End If
    		End If
    
    		Refresh()
    		castleGrayscul(e)
    	End Sub
    
    
    	Public Sub SaveImage(filename As String)
    		Dim FS As New IO.FileStream(filename, IO.FileMode.Create)
    		Encoder1.FrameRate = t.Interval
    		Encoder1.MetadataString = MetadataComment
    		Encoder1.Repeat = True
    		Encoder1.Save(FS)
    		FS.Flush()
    		FS.Close()
    	End Sub
    
    	Public Sub DrawRectangleRectangle(ByVal e As PaintEventArgs)
    		e.Graphics.DrawRectangle(blackPen, 20, startUndZiel, 100, minus)
    	End Sub
    
    
    	Sub castleGrayscul(ByVal e As EventArgs) 'castleGrayscul versus Monkeyisland. . .
    		Dim bmp As New Bitmap(Width - 16, Height - 39)
    		DrawToBitmap(bmp, New Rectangle(0, 0, bmp.Width, bmp.Height))
    		Encoder1.AddFrame(bmp)
    		bmp.Dispose()
    	End Sub
    
    	Private Sub Form1_FormClosed(sender As Object, e As FormClosedEventArgs) Handles MyBase.FormClosed
    		SaveImage("C:\Temp\Probst.gif")
    	End Sub
    End Class
    Bei den Referenzen müssen ggfls. Assemblies hinzugefügt werden, die von AnimatedGifEncoder verwendet werden (PresentationCore).

    Das Ergebnis sieht dann so aus:


    - Gruß Florian

    Mittwoch, 29. August 2018 09:56
  • Ja, Perfekt. Du hast das Ziel erreicht. Ich habe noch eine abschließende Bitte zu diesem Thema. Ich würde gerne die Gif Animation so speichern, dass der Anfangspunkt genau mit demselben Endpunkt gespeichert wird. Wenn die Animation im Kreis läuft es keinen Unterschied zwischen Anfangs- und Endpunkt gibt.

    Mit freundlichen Grüßen

    Stefan

    Mittwoch, 29. August 2018 14:50
  • Ich habe schon eine Möglichkeit gefunden.

    Dim counter As Integer
    Dim search As New Label()
    
    Sub Form1_Load(. . .)
    . . .
    
    counter = 1
    End Sub
    
    Sub Form1_Paint(. . .)
            search.Size = New System.Drawing.Size(25, 13)
            search.Location = New System.Drawing.Point(237, 5)
            search.Text = counter
            Me.Controls.Add(search)
    
    . . .
    End Sub
    
    Sub t_Tick(. . .)
    . . .
    
            'If zweiPlusZwei = False Then
            '    If startUndZiel > 10 Then
            '        startUndZiel -= dieEins
            '        minus += dieEins
            '    Else
            '        zweiPlusZwei = True
            '    End If
            counter += 1
            'End If
    
            If counter = 121 Then
                t.Stop()
            End If
            'Refresh()
    
    . . .
    End Sub
    

     

    Doch möglicherweise gibt es eine elegantere Lösung die ich in meinem Arbeitsfieber nicht erkennen konnte. Das Programm mit Alt+F4 Tastenkombination beenden und nicht nur den Compiler beenden Knopf verwenden sonst wird die Arbeit Probst.gif nicht gespeichert.



    Mittwoch, 29. August 2018 18:08
  • Du kannst das Speichern direkt unter t.Stop aufrufen, ggfls. auch gleich die Form schließen.

    - Gruß Florian

    Donnerstag, 30. August 2018 07:15
  • Auf jeden Fall geht meine Reise hier zu Ende. Ich hoffe, dass ich jetzt nur noch kreative Animationen schreiben lerne und den technischen Studienteil auf später verschieben kann. Du hast mir mindestens 11 Millionen Lichtjahre Arbeit erspart.

    Vielen Dank

    Stefan

    p.s.: Da ich meine Frage auch auf vb-paradise.de online gestellt habe und du die Antwort geschrieben hast würde ich gerne deinen Namen dort zitieren (mit der Antwort), ist das möglich?

    Donnerstag, 30. August 2018 16:55
  • Auf jeden Fall geht meine Reise hier zu Ende. 

    ...

    Freut mich, dass es dich weiter gebracht hat.

    p.s.: Da ich meine Frage auch auf vb-paradise.de online gestellt habe und du die Antwort geschrieben hast würde ich gerne deinen Namen dort zitieren (mit der Antwort), ist das möglich?

    Da habe ich nichts dagegen.


    - Gruß Florian

    Freitag, 31. August 2018 07:09
  • Danke.

    Mit freundlichen Grüßen

    Stefan


    Freitag, 31. August 2018 11:33
  • Hallo Stefan,

    Wenn Deine Frage beantwortet wurde, wäre es nett von Dir, wenn Du die Beiträge, die Dich weitergebracht haben, als Antwort markieren würdest. Ich verweise Dich auf die Forenregeln:

    ·        Lösungsbeiträge als “Die Antwort“ markieren
    Bitte markieren Sie den Beitrag, der zur Lösung geführt hat, als "Die Antwort". Durch Bewerten eines Beitrags als "Die Antwort" können andere Teilnehmer die Lösung schneller finden. Außerdem können Sie dem Benutzer, der die Antwort eingereicht hat, für seinen Beitrag danken und zur Steigerung der Antwortqualität in der Diskussionsgruppe beitragen.
    [Quelle: Forenregeln]

    Gruß,
    Dimitar


    Bitte haben Sie Verständnis dafür, dass im Rahmen dieses Forums, welches auf dem Community-Prinzip „IT-Pros helfen IT-Pros“ beruht, kein technischer Support geleistet werden kann oder sonst welche garantierten Maßnahmen seitens Microsoft zugesichert werden können.

    Mittwoch, 5. September 2018 09:57
    Moderator
  • Danke für den Hinweis.

    Mit freundlichen Grüßen

    Mittwoch, 5. September 2018 16:02