Auf einem Control (z.B. Picturebox) mit befüllten Image etwas auf einem neuen Layer zeichnen

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 4 Antworten in diesem Thema. Der letzte Beitrag () ist von dive26.

    Auf einem Control (z.B. Picturebox) mit befüllten Image etwas auf einem neuen Layer zeichnen

    Hallo Leute,

    ich stehe vor folgender Aufgabe:

    1. Ich möchte ein Foto anzeigen lassen (mir egal ob in Picturebox oder in Panel etc...) - soweit Ok
    2. Ich möchte nun darauf mit der Maus Markierungen vornehmen (z.B. etwas einkreisen) - soweit OK
    3. Ich möchte aber die vorgenommenen Markierungen (das auf das Control gezeichnete) ohne das Hintergrundbild speichern.

    Welchen Ansatz würdet Ihr hier verfolgen?

    Hintergrund, warum ich die Markierungen separat haben möchte ist, dass man das Foto jederzeit wieder aufrufen kann und die Anmerkungen dann löschen oder ergänzen kann.
    Das endgültige Zusammenführen der beiden Grafiken bekomme ich hin, das ist nicht das Problem.

    EDIT: Habe gerade im Netz diesen Hinweis gelesen (aber noch nicht ausprobiert):

    First, the picturebox has two "layers" that you can draw on. You can assign your bitmap to the Picturebox.BackgroundImage and then do your drawing on the PictureBox.Image. In this case when you clear the PictureBox.Image, the .BackgroundImage would remain.


    Wenn das wirklich funktioniert, dann könnte ich das Foto als BackgroundImage laden und als .Image einfach eine transparente Bitmap in der selben Größe und dann zeichne ich im Prinzip auf die transparente Bitmap und das ursprüngliche Foto bleibt unbehelligt. Mal sehen ob ich heute noch dazukomme dies auszuprobieren.

    LG Roland



    Das Zusammenmischen der beiden Dateien in .image und .backgroundimage funktioniert schon.
    Hier mal nur meinen Code rauskopiert.

    VB.NET-Quellcode

    1. Private Sub ListView_FotoHaupt_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ListView_FotoHaupt.SelectedIndexChanged
    2. If ListView_FotoHaupt.SelectedItems.Count = 0 Then Exit Sub
    3. Dim AktuelleFotoDatei As String = ListView_FotoHaupt.SelectedItems(0).Tag.ToString
    4. 'Foto in die Picturebox laden (aber ins .BackgroundImage)
    5. Dim TempBMP As Bitmap
    6. Using fs As New System.IO.FileStream(AktuelleFotoDatei, System.IO.FileMode.Open, System.IO.FileAccess.Read)
    7. TempBMP = New Bitmap(fs) ' File wird nicht blockiert
    8. fs.Close()
    9. End Using
    10. If PictureBox_DragHere.BackgroundImage IsNot Nothing Then PictureBox_DragHere.BackgroundImage.Dispose()
    11. PictureBox_DragHere.BackgroundImage = TempBMP
    12. 'Prüfen ob es eine Anmerkungsdatei gibt
    13. If File.Exists(AktuelleFotoDatei + ".annotation") Then
    14. 'Bereits eine Markierung vorhanden
    15. MarkierungenBearbeitenToolStripMenuItem.Text = "Markierungen bearbeiten"
    16. Dim TempLayerBMP As Bitmap
    17. Using fs As New System.IO.FileStream(AktuelleFotoDatei + ".annotation", System.IO.FileMode.Open, System.IO.FileAccess.Read)
    18. TempLayerBMP = New Bitmap(fs) ' File wird nicht blockiert
    19. fs.Close()
    20. End Using
    21. If PictureBox_DragHere.Image IsNot Nothing Then PictureBox_DragHere.Image.Dispose()
    22. TempLayerBMP.MakeTransparent(Color.White)
    23. PictureBox_DragHere.Image = TempLayerBMP
    24. Else
    25. 'Keine Markierung vorhanden, also nichts ins .image
    26. MarkierungenBearbeitenToolStripMenuItem.Text = "Markierung hinzufügen"
    27. If PictureBox_DragHere.Image IsNot Nothing Then PictureBox_DragHere.Image = Nothing
    28. End If
    29. End Sub


    Das Zeichnen probiere ich nun auch noch. Wird aber zu 99% funktionieren ;-).

    Beiträge zusammengefügt. ~Thunderbolt
    Bilder
    • 26112021214354.jpg

      160,54 kB, 692×245, 68 mal angesehen
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „Thunderbolt“ ()

    Ohne jetzt großartig was geplant zu haben, habe ich einfach mal losgelegt, 15 Minuten und die Idee funktioniert, weitere 5 und alles gefällt mir schon besser. Ist aber noch sehr viel zu machen, erst recht wenn man nun noch einzelne Layer oder Elemente im Layer bewegen will. Das painting der Layer und Element wird in der Reihenfolge gecallt, wie sie hinzugefügt wurden(layer1-Elemente dann layer2-elemente usw....), kannst also auch Elemente in der Liste Verschieben um die "mal-Reihenfolge" zu ändern. Entstanden ist nun eine PictureBoxWithLayer welche wie der Name schon verrät Layer hat und von PictureBox erbt. Könnte man den Layern oder einzelnen Elementen "im Layer" eine Visible Property verpassen, lassen sich auch einzelne Element oder ganze Layer ausblenden.

    Wenn du auf dieser Basis arbeitest, kannste leicht eigene Layer-Elemente bauen, egal ob für Images, Strings(text), oder was du sonst noch brauchst. Hab gerade in der Onlineliste gesehen, warst im Thema Zoom in PictureBox am lesen, alles ganz einfach, jedes element für layer hat psoition wie auch größe, zoom also schon erledigt, xD.

    CODE nochmals editiert, war noch Zeug drin was man nicht brauchte.

    Die PictureBoxWithLayer & Co
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Option Strict On
    2. Public Class PictureBoxWithLayer
    3. Inherits PictureBox
    4. Private Layers As New List(Of PictureBoxLayer)
    5. Public Sub CreateLayer()
    6. Layers.Add(PictureBoxLayer.CreateLayer())
    7. End Sub
    8. Public Sub AddToLayer(rectangle As LayerRectangle, index As Integer)
    9. Layers(index).AddLayerRectangle(rectangle)
    10. Invalidate()
    11. End Sub
    12. Public Sub AddToLayer(ellipse As LayerEllipse, index As Integer)
    13. Layers(index).AddLayerEllipse(ellipse)
    14. Invalidate()
    15. End Sub
    16. Protected Overrides Sub OnPaint(pe As PaintEventArgs)
    17. MyBase.OnPaint(pe)
    18. For Each l As PictureBoxLayer In Layers
    19. l.Paint(pe.Graphics)
    20. Next
    21. End Sub
    22. End Class
    23. Public Class PictureBoxLayer
    24. Private Elements As New List(Of Object)
    25. Public Shared Function CreateLayer() As PictureBoxLayer
    26. Return New PictureBoxLayer()
    27. End Function
    28. Public Sub AddLayerRectangle(rectangle As LayerRectangle)
    29. Elements.Add(rectangle)
    30. End Sub
    31. Public Sub AddLayerEllipse(ellipse As LayerEllipse)
    32. Elements.Add(ellipse)
    33. End Sub
    34. Public Sub Paint(g As Graphics, Optional penWidth As Integer = 1)
    35. For Each r As LayerBase In Elements
    36. r.Paint(g, penWidth)
    37. Next
    38. End Sub
    39. End Class
    40. Public Class LayerBase
    41. Protected LayerType As LayerTypes
    42. Public Function GetLayerType() As LayerTypes
    43. Return LayerType
    44. End Function
    45. Public X, Y, Width, Height As Integer
    46. Public Color As Color = SystemColors.Control
    47. Public PaintType As PaintOptions = PaintOptions.Draw
    48. Public Sub Paint(g As Graphics, Optional penWidth As Integer = 1)
    49. Select Case LayerType
    50. Case LayerTypes.Ellipse
    51. DirectCast(Me, LayerEllipse).Paint(g, penWidth)
    52. Case LayerTypes.Rectangle
    53. DirectCast(Me, LayerRectangle).Paint(g, penWidth)
    54. End Select
    55. End Sub
    56. End Class
    57. Public Class LayerRectangle
    58. Inherits LayerBase
    59. Public Sub New()
    60. LayerType = LayerTypes.Rectangle
    61. End Sub
    62. Overloads Sub Paint(g As Graphics, penWidth As Integer)
    63. If (PaintType And PaintOptions.AntiAlias) = PaintOptions.AntiAlias Then
    64. g.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
    65. End If
    66. If (PaintType And PaintOptions.Draw) = PaintOptions.Draw Then
    67. g.DrawRectangle(New Pen(New SolidBrush(Color), penWidth), X, Y, Width, Height)
    68. End If
    69. If (PaintType And PaintOptions.Fill) = PaintOptions.Fill Then
    70. g.FillRectangle(New SolidBrush(Color), X, Y, Width, Height)
    71. End If
    72. End Sub
    73. End Class
    74. Public Class LayerEllipse
    75. Inherits LayerBase
    76. Public Sub New()
    77. LayerType = LayerTypes.Ellipse
    78. End Sub
    79. Overloads Sub Paint(g As Graphics, penWidth As Integer)
    80. If (PaintType And PaintOptions.AntiAlias) = PaintOptions.AntiAlias Then
    81. g.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
    82. End If
    83. If (PaintType And PaintOptions.Draw) = PaintOptions.Draw Then
    84. g.DrawEllipse(New Pen(New SolidBrush(Color), penWidth), X, Y, Width, Height)
    85. End If
    86. If (PaintType And PaintOptions.Fill) = PaintOptions.Fill Then
    87. g.FillEllipse(New SolidBrush(Color), X, Y, Width, Height)
    88. End If
    89. End Sub
    90. End Class
    91. Public Enum LayerTypes
    92. Rectangle
    93. Ellipse
    94. End Enum
    95. Public Enum PaintOptions
    96. Fill = 1
    97. Draw = 1 << 1
    98. AntiAlias = 1 << 2
    99. End Enum


    und natürlich auch ein Anwendungsbeispiel:

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    3. PictureBoxWithLayer1.CreateLayer()
    4. Dim r As New LayerRectangle
    5. r.X = 10
    6. r.Y = 10
    7. r.Width = 100
    8. r.Height = 50
    9. r.Color = Color.Blue
    10. r.PaintType = PaintOptions.Draw
    11. PictureBoxWithLayer1.AddToLayer(r, 0)
    12. Dim el As New LayerEllipse
    13. el.X = 15
    14. el.Y = 15
    15. el.Width = 100
    16. el.Height = 50
    17. el.PaintType = PaintOptions.Fill Or PaintOptions.AntiAlias
    18. el.Color = Color.Red
    19. PictureBoxWithLayer1.AddToLayer(el, 0)
    20. End Sub
    21. End Class

    Dieser Beitrag wurde bereits 8 mal editiert, zuletzt von „Takafusa“ ()

    Vielen Dank für Deinen Code.

    Habs jetzt fertig. Und es funktionerte wie gedacht.

    1. Bild wird in eine Picturebox (Backgroundimage) mit Sizemode=Zoom geladen
    2. Das zweite Bild mit den Notizen (bzw. eine leere Transparente Bitmap) wird ebenfalls in die Picturebox (image) geladen
    3. Dann kann man beliebig im .image zeichnen und auch als separate Datei abspeichern
    4. Beim Zeichnen wird auch der Zoom-Faktor berücksichtigt, dass es auch richtig funktioniert.
    (siehe Screenshot)
    Bilder
    • Unbenannt-1.jpg

      1,21 MB, 1.694×1.088, 67 mal angesehen
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „dive26“ ()

    Hast es ja nun schon anders gemacht. Mach das nun mal mit mehreren Bildern und Strings und sonstigen Geometrischen Formen oder auch ausscheiden und auf einem anderen Layer einfügen, oder gar mehr als 2 Layer, da wäre meine Basis deutlich skalierbarer, auch wenns mehr arbeit ist. Eine gute erweiterbarkeit ist auch gegeben.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Takafusa“ ()

    ja, vielen Dank.
    Aber mehr als mit der Maus auf dem Bild was zu markieren brauchte ich nicht.
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at