JPG Bild laden und Tags auslesen

  • VB.NET
  • .NET 7–8

Es gibt 3 Antworten in diesem Thema. Der letzte Beitrag () ist von RodFromGermany.

    JPG Bild laden und Tags auslesen

    Hallo,
    ich bin am verzweifeln. Ich habe ein Visual Studio ein Projekt gestartet (WPF-Anwendung als Framework .NET 8.0).
    Nun versuche ich wie blöd ein Bild zu laden. Alle Informationen die ich finde, definieren das Bild als Image und laden das Bild mittels FromFile.
    Nur wenn ich das mache, klappt es nicht.
    Ich bekomme die Meldung "FromFile" ist kein Member von "MediaTypeNames.Image". Das gleiche Problem habe ich mit den PropertyItems (möchte die Tags der Bilddatei auslesen).

    Habe ich mein Projekt falsch erstellt? Oder ?? Anbei ein Versuchs Code:

    VB.NET-Quellcode

    1. Imports System
    2. Imports System.IO
    3. Imports System.Net.Mime.MediaTypeNames
    4. Imports System.Drawing
    5. Module Program
    6. Sub Main(args As String())
    7. Console.WriteLine("Hello World!")
    8. Dim filePath As String = "C:\Pfad\zu\deinem\Bild.jpg"
    9. Dim tags As Dictionary(Of String, Object) = GetJpegTags(filePath)
    10. ' Ausgabe der Tags
    11. For Each tag In tags
    12. Console.WriteLine($"{tag.Key}: {tag.Value}")
    13. Next
    14. End Sub
    15. Public Function GetJpegTags(filePath As String) As Dictionary(Of String, Object)
    16. ' Überprüfen, ob die Datei existiert und ein gültiges Bild ist
    17. If Not File.Exists(filePath) Then
    18. Throw New ArgumentException("Datei existiert nicht.")
    19. End If
    20. Dim image As Image = image.FromFile(filePath)
    21. ' Alle PropertyItems (Tags) abrufen
    22. Dim propertyItems As PropertyItem() = image.PropertyItems
    23. ' Dictionary zum Speichern der Tags erstellen
    24. Dim tags As New Dictionary(Of String, Object)
    25. ' PropertyItems in das Dictionary übertragen
    26. For Each item As PropertyItem In propertyItems
    27. ' Versuchen, den Tag-Namen zu finden
    28. Dim tagName As String = GetTagName(item.Id)
    29. ' Wenn ein Name gefunden wurde, den Wert speichern
    30. If Not String.IsNullOrEmpty(tagName) Then
    31. tags.Add(tagName, GetPropertyValue(item))
    32. End If
    33. Next
    34. Return tags
    35. End Function
    36. Private Function GetTagName(id As Integer) As String
    37. ' Hier könnte eine umfassendere Liste von Tag-IDs und -Namen definiert werden
    38. Select Case id
    39. Case &H112
    40. Return "Image Description"
    41. Case &H132
    42. Return "Make"
    43. Case &H131
    44. Return "Model"
    45. ' ... weitere Tag-IDs hinzufügen
    46. Case Else
    47. Return String.Empty
    48. End Select
    49. End Function
    50. Private Function GetPropertyValue(item As PropertyItem) As Object
    51. ' Je nach Datentyp des Tags den Wert entsprechend konvertieren
    52. Select Case item.Type
    53. Case 1 ' Byte
    54. Return Encoding.ASCII.GetString(item.Value)
    55. Case 2 ' ASCII
    56. Return Encoding.ASCII.GetString(item.Value)
    57. Case 3 ' Short
    58. ' ...
    59. ' ... weitere Datentypen hinzufügen
    60. Case Else
    61. Return "Unbekannter Datentyp"
    62. End Select
    63. End Function
    64. End Module


    Für jede Hilfe, Anregung bin ich dankbar. Aber wenn jemand eine fertige Klasse kennt, die ein Leihe nutzen kann, ohne Studiert zu haben, würde ich mich auch darüber freuen. Diese Klasse müsste Tags auch erstellen und ändern können.

    Vielen Dank
    Christian

    *Topic verschoben*

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Marcus Gräfe“ ()

    Hi,

    du musst noch mal zurück zum Anfang. Du musst dir erstmal selbst klar werden womit du arbeiten willst. Du sagst uns du hast ein WPF Projekt angelegt, zeigst aber Code für eine Console.

    Auch musst du mal in Erfahrund bringen was Namespace sind. Nur weil es Klassen mit den selbsen Namen in mehreren Namespace gibt, bedeutet das nicht, das alle das gleiche können.

    System.Drawing.Image ->learn.microsoft.com/en-us/dotn…e?view=windowsdesktop-9.0
    System.Windows.Controls.Image ->learn.microsoft.com/en-us/dotn…e?view=windowsdesktop-9.0
    Microsoft.UI.XAML.Controls.Image ->learn.microsoft.com/en-us/uwp/…ls.image?view=winrt-26100
    System.Net.Mime.MediaTypeNames.Image ->learn.microsoft.com/en-us/dotn…enames.image?view=net-9.0

    Deine Angabe mit Framework NET 8 stimmt auch nicht gänzlich. Damals gab es Net-Framework, dann kam NET-Core(bis 3.1), NET 4 gibts nicht, seit der 5. Version heist das nur noch NET. Also Net-Framework = alt. NET = neu. Ich würde empfehlen gleich mit NET zu arbeiten, egal ob Forms oder WPF. Wobei ich gerade dir eher zu Forms raten würde als zu WPF, denn das ist leichter, weil du keine 2 Sprachen lernen musst, denn in WPF kommt auch XAML zum Einsatz.

    Du musst lernen die Doku zu benutzen, denn dort findest du alles was eine Klasse kann. Wenn du dort nun mal durchschaust, wirst du nur eine "Image"-Klasse finden, die eine Funktion .FromFile hat. Fertigen code der auf dich zugeschnitten ist wird dir wohl eher keiner geben. Hier wird eher Hilfe zur Selbsthilfe gegeben. Würde ich dir fertigen Code geben, würdest du immer wieder fragen statt zu lernen. Mal einen kleinen Schnipsel ist ja noch OK, oder eine Code-Korrektur, aber dich am lernen hindern werde ich nicht. Zeig dem Hungrigen wie man fischt, anstatt im was zu Essen zu geben, dann kann er sich selbst versorgen ;) , immer wieder.

    bahnski schrieb:

    die ein Leihe nutzen kann, ohne Studiert zu haben,


    Wenn du programmieren willst, musst du es lernen. Dazu muss man nicht studieren. Ich habe keine Ausbildung/Studium in diesem Bereich gemacht und kann es trotzdem, sogar recht gut denke ich.
    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D

    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „DTF“ ()

    @bahnski

    Ich hatte vor längerer Zeit, mal angefangen mir so eine Klasse zu schreiben, weil ich die für ein privates kleines Projekt brauchte.
    Mein Beispiel hier ist nur ein Anfang, aber vielleicht hilf dir das etwas.

    Infos zu den HEX-Codes:
    learn.microsoft.com/en-us/dotn…g_Imaging_PropertyItem_Id


    Spoiler anzeigen

    Das MainForm:

    VB.NET-Quellcode

    1. Public Class FrmMain
    2. Private ReadOnly reader As PictureMetadataReader = PictureMetadataReader.Instance
    3. Public Sub New()
    4. InitializeComponent()
    5. End Sub
    6. Private Sub BtnOnePic_Click(sender As Object, e As EventArgs) Handles BtnOnePic.Click
    7. Using ofd As New OpenFileDialog()
    8. ofd.Filter = "Bilddateien (*.jpg;*.jpeg;*.png;*.bmp)|*.jpg;*.jpeg;*.png;*.bmp"
    9. ofd.Title = "Wähle ein Bild aus"
    10. If ofd.ShowDialog() = DialogResult.OK Then
    11. Dim imagePath As String = ofd.FileName
    12. ShowTagsInDGV(imagePath)
    13. ShowImageInPictureBox(imagePath)
    14. LblPicpath.Text = imagePath
    15. End If
    16. End Using
    17. End Sub
    18. Private Sub ShowTagsInDGV(imagePath As String)
    19. reader.ReadMetadata(imagePath)
    20. Dim metadataList As List(Of KeyValuePair(Of String, String)) = reader.GetMetadata()
    21. ' DataGridView vorbereiten
    22. dgvMetadata.DataSource = Nothing
    23. dgvMetadata.Rows.Clear()
    24. If dgvMetadata.Columns.Count = 0 Then
    25. dgvMetadata.Columns.Add("IDTag", "Tag ID")
    26. dgvMetadata.Columns.Add("Values", "Wert")
    27. End If
    28. ' Zeilen hinzufügen
    29. For Each kvp As KeyValuePair(Of String, String) In metadataList
    30. dgvMetadata.Rows.Add(kvp.Key, kvp.Value)
    31. Debug.WriteLine($"Beschreibung: {kvp.Key}, Wert: {kvp.Value}")
    32. Next
    33. ' Titel des Fensters aktualisieren
    34. Me.Text = $"Metadaten von: {imagePath}"
    35. End Sub
    36. Private Sub ShowImageInPictureBox(imagePath As String)
    37. Try
    38. Dim img As Image = Image.FromFile(imagePath)
    39. PicPreview.Image = img
    40. PicPreview.SizeMode = PictureBoxSizeMode.Zoom
    41. Catch ex As Exception
    42. MessageBox.Show($"Fehler beim Laden des Bildes: {ex.Message}")
    43. End Try
    44. End Sub
    45. End Class

    Die Klasse:

    VB.NET-Quellcode

    1. Imports System.Drawing.Imaging
    2. Public Class PictureMetadataReader
    3. Implements IDisposable
    4. Public Shared ReadOnly Instance As New PictureMetadataReader()
    5. ' Liste, um die Metadaten zu speichern
    6. Private _metadata As List(Of KeyValuePair(Of String, String))
    7. ' Tabelle für Tag-Namen
    8. Private ReadOnly TagDescriptions As New Dictionary(Of String, String) From {
    9. {"0x010E", "Image Description"},
    10. {"0x010F", "Manufacturer"},
    11. {"0x0110", "Model"},
    12. {"0x0112", "Orientation"},
    13. {"0x011A", "X Resolution"},
    14. {"0x011B", "Y Resolution"},
    15. {"0x0128", "Resolution Unit"},
    16. {"0x0131", "Software"},
    17. {"0x0132", "Date and Time"},
    18. {"0x013B", "Artist"},
    19. {"0x013E", "White Point"},
    20. {"0x013F", "Primary Chromaticities"},
    21. {"0x0211", "YCbCr Coefficients"},
    22. {"0x0213", "YCbCr Positioning"},
    23. {"0x0214", "Reference Black/White"},
    24. {"0x8298", "Copyright"},
    25. {"0x8769", "Exif Offset"},
    26. {"0x829A", "Exposure Time"},
    27. {"0x829D", "F-Number"},
    28. {"0x8822", "Exposure Program"},
    29. {"0x8827", "ISO Speed Ratings"},
    30. {"0x9201", "Shutter Speed Value"},
    31. {"0x9202", "Aperture Value"},
    32. {"0x9203", "Brightness Value"},
    33. {"0x9204", "Exposure Bias Value"},
    34. {"0xA217", "Sensing Method"},
    35. {"0xA300", "File Source"},
    36. {"0xA301", "Scene Type"},
    37. {"0xA302", "CFAPattern"},
    38. {"0xA401", "Custom Rendered"},
    39. {"0xA402", "Exposure Mode"},
    40. {"0xA403", "White Balance"},
    41. {"0xA404", "Digital Zoom Ratio"},
    42. {"0xA405", "Focal Length in 35mm Film"},
    43. {"0xA406", "Scene Capture Type"},
    44. {"0xA407", "Gain Control"},
    45. {"0xA408", "Contrast"},
    46. {"0xA409", "Saturation"},
    47. {"0xA40A", "Sharpness"},
    48. {"0xA40C", "Subject Distance Range"},
    49. {"0xA420", "Image Unique ID"},
    50. {"0xA430", "Camera Owner Name"},
    51. {"0xA431", "Body Serial Number"},
    52. {"0xA432", "Lens Specification"},
    53. {"0xA433", "Lens Make"},
    54. {"0x9C9E", "Keywords"} _
    55. ' Weitere möglich
    56. }
    57. Public Sub New()
    58. ' Initialisiert die Liste
    59. _metadata = New List(Of KeyValuePair(Of String, String))()
    60. End Sub
    61. ' Öffentliche Methode, um die Metadaten auszulesen
    62. Public Sub ReadMetadata(imagePath As String)
    63. ' Metadaten-Liste leeren
    64. _metadata.Clear()
    65. ' Bild laden und sicherstellen, dass Ressourcen freigegeben werden
    66. Using img As Image = Image.FromFile(imagePath)
    67. ' Alle PropertyItems durchlaufen
    68. For Each prop As PropertyItem In img.PropertyItems
    69. ' Tag-ID ermitteln und ggf. übersetzen
    70. Dim tagId As String = "0x" & prop.Id.ToString("X4")
    71. ' Wenn das Tag in der TagDescriptions-Liste ist, füge es hinzu
    72. If TagDescriptions.ContainsKey(tagId) Then
    73. Dim description As String = TagDescriptions(tagId)
    74. Dim value As String = GetPropertyValue(prop)
    75. ' Hinzufügen der Metadaten in die Liste
    76. _metadata.Add(New KeyValuePair(Of String, String)(description, value))
    77. End If
    78. Next
    79. End Using
    80. End Sub
    81. ' Methode, um die Liste zurückzugeben
    82. Public Function GetMetadata() As List(Of KeyValuePair(Of String, String))
    83. Return _metadata
    84. End Function
    85. ' Private Methode zur Interpretation der Property-Werte
    86. Private Function GetPropertyValue(prop As PropertyItem) As String
    87. Try
    88. ' Wenn es sich um ein Text-Tag handelt, müssen wir uns die Kodierung genau anschauen
    89. Select Case prop.Id
    90. Case &H9286 ' User Comment
    91. ' UTF-16-Dekodierung für User Comment
    92. Try
    93. Dim userComment As String = Text.Encoding.Unicode.GetString(prop.Value).TrimEnd(ChrW(0))
    94. If Not String.IsNullOrEmpty(userComment) Then
    95. Return userComment
    96. End If
    97. Catch ex As Exception
    98. Debug.WriteLine("Fehler bei der Dekodierung von User Comment (UTF-16): " & ex.Message)
    99. End Try
    100. Case &H9C9B ' Keywords (falls in UTF-16)
    101. Try
    102. ' Versuchen, den Keyword-Tag als UTF-16 zu dekodieren
    103. Dim keywords As String = Text.Encoding.Unicode.GetString(prop.Value).TrimEnd(ChrW(0))
    104. If Not String.IsNullOrEmpty(keywords) Then
    105. Return keywords
    106. End If
    107. Catch ex As Exception
    108. Debug.WriteLine("Fehler bei der Dekodierung von Keywords (UTF-16): " & ex.Message)
    109. End Try
    110. Case &H9209 ' Caption
    111. ' UTF-16 Dekodierung für Caption
    112. Try
    113. Dim caption As String = Text.Encoding.Unicode.GetString(prop.Value).TrimEnd(ChrW(0))
    114. If Not String.IsNullOrEmpty(caption) Then
    115. Return caption
    116. End If
    117. Catch ex As Exception
    118. Debug.WriteLine("Fehler bei der Dekodierung von Caption (UTF-16): " & ex.Message)
    119. End Try
    120. Case Else
    121. ' Wenn es ein Standard-Tag ist (Byte, ASCII, etc.), behandeln wir es wie gewohnt
    122. Return DecodeStandardTag(prop)
    123. End Select
    124. ' Falls keine der Bedingungen zutrifft, Rückgabe eines Standardwerts
    125. Return String.Empty
    126. Catch ex As Exception
    127. ' Detaillierte Fehlerbehandlung
    128. Debug.WriteLine("Fehler bei der Verarbeitung von PropertyItem: " & ex.Message)
    129. Return String.Empty ' Standardwert zurückgeben
    130. End Try
    131. End Function
    132. ' Eine zusätzliche Funktion, die Standard-PropertyItem-Tags behandelt
    133. Private Function DecodeStandardTag(prop As PropertyItem) As String
    134. Select Case prop.Type
    135. Case 1 ' BYTE
    136. Return String.Join(", ", prop.Value.Select(Function(b) b.ToString()))
    137. Case 2 ' ASCII
    138. Return Text.Encoding.ASCII.GetString(prop.Value).TrimEnd(Chr(0))
    139. Case 3 ' SHORT
    140. Return BitConverter.ToUInt16(prop.Value, 0).ToString()
    141. Case 4 ' LONG
    142. Return BitConverter.ToUInt32(prop.Value, 0).ToString()
    143. Case 5 ' RATIONAL
    144. Dim numerator As UInteger = BitConverter.ToUInt32(prop.Value, 0)
    145. Dim denominator As UInteger = BitConverter.ToUInt32(prop.Value, 4)
    146. Return numerator & "/" & denominator
    147. Case 7 ' UNDEFINED
    148. Return GetHexRepresentation(prop.Value)
    149. Case 10 ' SLONG
    150. Dim numerator As Integer = BitConverter.ToInt32(prop.Value, 0)
    151. Dim denominator As Integer = BitConverter.ToInt32(prop.Value, 4)
    152. Return numerator & "/" & denominator
    153. Case Else
    154. Return "Unbekannter Typ"
    155. End Select
    156. End Function
    157. ' Hilfsfunktion zur Hex-Darstellung von Daten
    158. Private Function GetHexRepresentation(value As Byte()) As String
    159. Return String.Join(", ", value.Select(Function(b) b.ToString("X2")))
    160. End Function
    161. ' Dispose-Methode zur Bereinigung
    162. Public Sub Dispose() Implements IDisposable.Dispose
    163. _metadata.Clear()
    164. End Sub
    165. End Class

    Bilder
    • Unbenannt-1.jpg

      301,5 kB, 800×485, 31 mal angesehen
    Asperger Autistin. Brauche immer etwas um gewisse Sachen zu verstehen. :huh:

    Amelie schrieb:

    VB.NET-Quellcode

    1. Private ReadOnly TagDescriptions As New Dictionary(Of String, String) From {
    2. {"0x010E", "Image Description"},
    Du solltest die HEX-Codes nicht vom Type String, sondern direkt als Integer-Werte behandeln.
    Ansonsten könnte es zu "Missverständnissen" kommen, wenn da 0x010e vorkommt.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!