Wie ein Kommentar zu einem JPG-Bild hinzufügen und anzeigen?

  • VB.NET
  • .NET (FX) 4.0

Es gibt 30 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

    Wie ein Kommentar zu einem JPG-Bild hinzufügen und anzeigen?

    Hallo,

    ich versuche seit paar Stunden herauszufinden, wie ich ein Kommentar zu einem JPG-Bild hinzufügen kann.
    Dass ich EXIF-Daten nutzen muss, ist mir klar. Dass ich das Bild als Image einlesen muss, um auf die PropertyItems zugreifen zu können, ist mir auch klar.

    Leider haben die Bilder nur wenige IDs zur Auswahl vorhanden, und nirgendwo war "UserComment" oder "ImageDesription" (ID 0x9286 oder 0x010e). Wie kann ich denn ein neues PropertyItem hinzufügen? Über "New System.Drawing.Imaging.PropertyItem" geht es leider nicht, weil "New" als Friend definiert ist :(

    Danke.
    Der Trick ist, Du musst ein PropertyItem von irgendeinem Bitmap-Objekt mit Exif-Daten kopieren. Dann änderst Du die Eingenschaften des PropertyItems und weise dieses deinem Bild mithilfe der Methode SetPropertyItem zu.
    In etwa so:

    VB.NET-Quellcode

    1. Dim refBitmap As Bitmap = My.Resources.ImageWithExifData
    2. Dim filename As String = "fullpath"
    3. Dim bmp As Bitmap = Nothing
    4. Using fs As New IO.FileStream(filename, IO.FileMode.Open, IO.FileAccess.Read)
    5. bmp = CType(Image.FromStream(fs, True), Bitmap)
    6. End Using
    7. Dim prop = refBitmap.PropertyItems(0) ' Einfach das erste PropertyItem kopieren und Eigenschaften ändern
    8. prop.Id = 37510
    9. prop.Value = System.Text.Encoding.Default.GetBytes("Habe nüx zu sagen!")
    10. prop.Type = 2
    11. bmp.SetPropertyItem(prop) ' das PropertyItem dem Bitmap-Objekt zuweisen
    12. bmp.Save(filename, Drawing.Imaging.ImageFormat.Jpeg) ' Speichern

    msdn schrieb:

    It is difficult to set property items, because the PropertyItem class has no public constructors. One way to work around this restriction is to obtain a PropertyItem by retrieving the PropertyItems property value or calling the GetPropertyItem method of an Image that already has property items. Then you can set the fields of the PropertyItem and pass it to SetPropertyItem.


    Da bekommst du jedoch ein Problem, wenn das Bild keine Propertyitems hat.

    Ich hätte deshalb jetzt einfach mal sowas vorgeschlagen. Habs weder getestet noch weiß ich ob es funktioniert. Aber versuchen kannst du es ja:

    C#-Quellcode

    1. var image = Image.FromFile(@"C:\Temp\test.jpg");
    2. var propertyItem = (PropertyItem)Activator.CreateInstance(
    3. typeof (PropertyItem),
    4. BindingFlags.NonPublic | BindingFlags.Instance,
    5. null, null, null);
    6. propertyItem.Id = 37510;
    7. propertyItem.Value = Encoding.Default.GetBytes("Kommentar...");
    8. propertyItem.Type = 2;
    9. image.SetPropertyItem(propertyItem);
    10. image.Save(@"C:\Temp\test1.jpg");


    @xtts02 mit deiner Methode kannst du ein Problem bekommen. Und zwar aus folgendem Grund:

    http://msdn.microsoft.com/en-us/library/system.drawing.image.propertyitems.aspx schrieb:

    If the image has no property items or if the image format does not support property items, PropertyItems returns an empty array (that is, an array of length zero).


    Zusätzlich besteht die Gefahr, dass dadurch ein anderes PropertyItem verloren geht.

    EDIT: Grad getestet und funktioniert wunderbar: s1.directupload.net/images/140519/7crv9a9g.png


    Opensource Audio-Bibliothek auf github: KLICK, im Showroom oder auf NuGet.

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

    Könntest du mir erklären, wie ich das in VB schreiben soll? Die IDE macht keine Vorschläge nach Activator.CreateInstance ;(

    EDIT:

    @thefiloe
    Leider wird noch was anderes dazugeschrieben, nicht lesbare Zeichen. Und auslesen klappt leider gar nicht ;(

    VB.NET-Quellcode

    1. Private Function GetComment(ByVal im As System.Drawing.Image) As String
    2. Dim items = im.PropertyItems
    3. ' Return System.Text.Encoding.Default.GetString(items(0).Value)
    4. For Each pi In items
    5. If pi.Id = &H9286 Then
    6. Return System.Text.Encoding.Default.GetString(pi.Value)
    7. End If
    8. Next
    9. Return Nothing
    10. End Function


    Ich bekomme bei "Kommentar... unlesbare Zeichen" nur "K". Davor standen da jpg-Infos.

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

    Übersetzt wäre es so:

    VB.NET-Quellcode

    1. Dim propertyItem = DirectCast(Activator.CreateInstance(GetType(PropertyItem), BindingFlags.NonPublic Or BindingFlags.Instance, Nothing, Nothing, Nothing), PropertyItem)


    lg
    ScheduleLib 0.0.1.0
    Kleine Lib zum Anlaufen von Code zu bestimmten Zeiten
    Entschuldigung. Hatte nicht gesehen, dass das Thema den VB.NET Tag hat. Aber bin auch eigentlich davon ausgegangen, dass du halbwegs C# kannst oder zumindest bereits Erfahrung in der Benutzung eines Converters hast ;).


    Opensource Audio-Bibliothek auf github: KLICK, im Showroom oder auf NuGet.
    Habe nicht gesehen, dass da noch weitere Antworten kamen.

    Habe es mit Converter übersetzen können (wollte eigentlich selbst, aber dieses Reflection-Zeugs kenne ich halt nicht), nur hapert es an der Umsetzung: siehe meinen vorigen Post.

    xtts02 schrieb:

    VB.NET-Quellcode

    1. bmp.Save(filename, Drawing.Imaging.ImageFormat.Jpeg) ' Speichern


    Leider stürzt er mir hier ab, ich habe schon einen anderen Filenamen genommen (weil er mir bei meinen ersten Versuchen da deswegen abstürzte) und statt Bitmap Image ausprobiert, trotzdem ExternalException

    @xtts02
    Dieser dämlicher Editor löscht neuerdings X( Früher stand hier:
    Die Exception kam von Image.FromStream. Ich nehme jetzt Image.FromFile, das funktioniert dann beim Speichern. Muss aber einen anderen Namen nehmen als vorher.
    @thefiloe
    Mit deinem Code und Unicode klappt es leider auch nicht...

    Ich mache jetzt:

    VB.NET-Quellcode

    1. Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
    2. Dim sfd = New System.Windows.Forms.SaveFileDialog
    3. Dim bmp As Image = Nothing
    4. If sfd.ShowDialog() = Windows.Forms.DialogResult.OK Then
    5. bmp = Image.FromFile(sfd.FileName)
    6. SetComment2(bmp)
    7. Dim temp = sfd.FileName.Split("."c)(0) & "_1.jpg"
    8. bmp.Save(temp, Imaging.ImageFormat.Jpeg)
    9. End If
    10. End Sub
    11. Private Sub SetComment2(ByVal bmp As System.Drawing.Image)
    12. Dim refBitmap As Bitmap = My.Resources.vbpfehler 'habe einfach ein Bild hochgeladen
    13. Dim prop = refBitmap.PropertyItems(0) ' Einfach das erste PropertyItem kopieren und Eigenschaften ändern
    14. prop.Id = 37510
    15. prop.Value = System.Text.Encoding.Default.GetBytes("Habe nüx zu sagen!")
    16. prop.Type = 2
    17. bmp.SetPropertyItem(prop) ' das PropertyItem dem Bitmap-Objekt zuweisen
    18. End Sub
    19. Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    20. Dim sfd = New System.Windows.Forms.OpenFileDialog
    21. If sfd.ShowDialog() = Windows.Forms.DialogResult.OK Then
    22. Dim im = Image.FromFile(sfd.FileName)
    23. TextBox1.Text = GetComment(im)
    24. End If
    25. End Sub
    26. Private Function GetComment(ByVal im As System.Drawing.Image) As String
    27. Dim items = im.PropertyItems
    28. For Each pi In items
    29. If pi.Id = &H9286 Then
    30. Return System.Text.Encoding.Default.GetString(pi.Value)
    31. End If
    32. Next
    33. Return Nothing
    34. End Function



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

    Das gibt es doch nicht, jetzt geht es wieder nicht X(

    Mit Encoding.Default kann ich jetzt nur den ersten Buchstaben lesen, mit Unicode nur ein Sternchen (jeweils mit gleichen Encoding schreiben und lesen). Beim allerersten Testen hat es allerdings funktioniert. ?(

    Ich habe die neuen Dateien gelöscht und wieder neu erstellt, aber irgendwie ist da der Wurm drin ;(
    Geht nicht, mit Unicode habe jetzt den ersten Buchstaben, mit Default das Sternchen (umgekehrt also).

    @xtts02
    Also, nach langem Rumprobieren und im Debugger anschauen:
    - im Windows Explorer funktioniert es wunderbar (unter Eigenschaften->Details->Kommentar)
    - wenn ich mir den Rückgabewert in die Variable ausgebe, dann sind zwischen alle Buchstaben noch zusätzliche Leerzeichen oder sonstiges (die Buchstaben sind weiterauseinander), damit kann die Textbox nicht umgehen.

    EDIT: habe jetzt als CharArray ausgegeben, jedes 2. Zeichen ist leer, also auf 0 wohl. Weißt du, warum das sein kann?

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

    Ich habe ihn jetzt hardcodiert selbst zerpflückt, allerdings würde mich echt interessieren, wieso es so komisch gespeichert hatte.

    VB.NET-Quellcode

    1. Dim komm = GetComment(im)
    2. Dim neu As New List(Of Char)
    3. For Each c In komm
    4. If Char.IsLetterOrDigit(c) OrElse Char.IsPunctuation(c) OrElse Char.IsWhiteSpace(c) Then
    5. neu.Add(c)
    6. End If
    7. Next
    8. TextBox1.Text = neu.ToArray
    Nein, da sind sie weg, haben aber am Ende noch:

    Habe nüx zu sagen!««««««««îþîþîþ

    Jetzt habe ich wieder das Convert.ToChar(0) rangehängt, das ist jetzt weg. (also wie es sein soll)
    Der UserComment erwartet 2 Bytes, habe ich in der Beschreibung gesehen...

    EDIT:
    @xtts02
    dafür steht der Kommentar jetzt doppelt, im "Thema" und im "Titel", ich hätte es gerne im Kommentar...