Modifizierte JPG-Metadaten Speichern funktioniert nicht!

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

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

    Modifizierte JPG-Metadaten Speichern funktioniert nicht!

    Hallo Leute,
    ich habe bei meiner Anwendung ein kleines Problem.
    Ich möchte, Metadata-Informationen aus JPG-File (Bewertung \ Copyright \ Autoren \ Markierungen … usw.) auslesen, darstellen, einige Metadata ändern und diese anschließend in das JPG-File wieder zurück Speichern.
    Die ersten Aufgaben (Auslesen \ darstellen \ ändern) sind mir gelungen, das Speichern von den angepassten Metadata funktioniert jedoch nicht!
    Für diese Bearbeitung verwende ich derzeit folgende VB2010 Code:

    VB.NET-Quellcode

    1. Imports System.IO
    2. Imports System.Windows.Media.Imaging
    3. Public Class Form1
    4. Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    5. Dim jpgStream As New System.IO.FileStream("C:\TestOrdner\TestFoto.jpg", FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite)
    6. Dim jpgDecoder As New JpegBitmapDecoder(jpgStream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default)
    7. Dim jpgFrame As BitmapFrame = jpgDecoder.Frames(0)
    8. Dim jpgInplace As InPlaceBitmapMetadataWriter = jpgFrame.CreateInPlaceBitmapMetadataWriter()
    9. 'Bewertung ändern
    10. jpgInplace.Rating = "5"
    11. 'Markierungen ändern
    12. jpgInplace.SetQuery("System.Keywords", "TestMarkierung")
    13. jpgInplace.TrySave()
    14. jpgStream.Close()
    15. End Sub
    16. End Clas


    Was mach ich falsch? ?(
    Ich habe schon sehr viel über das Thema recherchiert und sehr viel ausprobiert (ExifWorks, andere Methoden …), leider ohne Erfolg! ;(
    Am liebsten wäre mir ein einfaches VB2010 Beispiel-Code. :)
    Ich hoffe es kann mir jemand weiterhelfen, Vielen Dank in voraus.
    Willkommen im Forum. :thumbup:

    Kipippo schrieb:

    CreateInPlaceBitmapMetadataWriter
    Gugst Du hier.
    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!
    Frage zu Zeile #13: jpgInplace.TrySave() ?
    Soweit ich das lese, is die TrySave-Funktion vom Typen Boolean, warum verwendest du sie, wenn du den Wert, ob das Speichern erfolgreiche wäre nicht sondern führst sie einfach aus?
    In general (across programming languages), a pointer is a number that represents a physical location in memory. A nullpointer is (almost always) one that points to 0, and is widely recognized as "not pointing to anything". Since systems have different amounts of supported memory, it doesn't always take the same number of bytes to hold that number, so we call a "native size integer" one that can hold a pointer on any particular system. - Sam Harwell

    Radinator schrieb:

    ob das Speichern erfolgreiche wäre
    Jou.
    @Kipippo Gugst Du hier.
    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!

    RodFromGermany schrieb:

    Willkommen im Forum. :thumbup:

    Kipippo schrieb:

    CreateInPlaceBitmapMetadataWriter
    Gugst Du hier.

    Danke für deine nette Begrüßung :D und deinen Link :)
    Genau diesen Code habe ich ja auch verwendet, leider funktioniert das nicht!
    Was mache ich falsch?

    Radinator schrieb:

    Frage zu Zeile #13: jpgInplace.TrySave() ?
    Soweit ich das lese, is die TrySave-Funktion vom Typen Boolean, warum verwendest du sie, wenn du den Wert, ob das Speichern erfolgreiche wäre nicht sondern führst sie einfach aus?

    Danke für deinen Beitrag!
    Da ich nur ein Code-Laie bin verstehe ich deinen Einwand nicht, sorry :|
    Könntest du bitte den oben geposteten Code so anpassen wie du denkst das es funktioniert und diesen dann posten?
    Ich wäre dir sehr dankbar dafür :)
    jpgInplace liefert dir True zurück wenn das speichern erfolgreich war. Du prüfst allerdings gar nicht ob es erfolgreich war.

    Du kannst das ganz einfach prüfen mit einen If-Block:

    VB.NET-Quellcode

    1. If jpgInplace.TrySave () = True Then
    2. 'Speichern erfolgreich
    3. End If
    KaskadekingDE on GitHub :)
    Bitte keine Fragen über Programmierung per PN! Dafür ist das Forum hier.

    Who cares? ¯\_(ツ)_/¯

    Kipippo schrieb:

    Genau diesen Code habe ich ja auch verwendet
    Offensichtlich nicht, denn in deinem Code kommt kein If vor.
    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!

    KaskadekingDE schrieb:

    jpgInplace liefert dir True zurück wenn das speichern erfolgreich war. Du prüfst allerdings gar nicht ob es erfolgreich war.
    Du kannst das ganz einfach prüfen mit einen If-Block:

    Danke für deinen Beitrag und tipp bezüglich

    VB.NET-Quellcode

    1. jpgInplace.TrySave()


    @RodFromGermany: haste recht, Code ist nicht identisch!
    Mein ziel ist ja aber die Metadata-Tags in das JPG-File zu speichern ... für das brauche ich .TrySave() nicht unbedingt oder?

    Ich bitte um ein simples code beispiel wie ich die Metadata-Tags in das JPG-File speichern kann!
    dankeschön

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

    Hallo Leute,

    endlich habe ich im Netz eine lösung zu diesem Thema gefunden :thumbsup:
    Hier der VB-Code
    Viel spaß :)

    VB.NET-Quellcode

    1. Function MetaDataEditor()
    2. Dim originalPath As String = "c:\TestFotoINP.jpg"
    3. Dim outputPath As String = "c:\TestFotoOUT.jpg"
    4. Dim createOptions As BitmapCreateOptions = BitmapCreateOptions.PreservePixelFormat Or BitmapCreateOptions.IgnoreColorProfile
    5. Dim paddingAmount As UInteger = 2048
    6. ' 2Kb padding for this example, but really this can be any value.
    7. ' Our recommendation is to keep this between 1Kb and 5Kb as most metadata updates are not large.
    8. ' High level overview:
    9. ' 1. Perform a lossles transcode on the JPEG
    10. ' 2. Add appropriate padding
    11. ' 3. Optionally add whatever metadata we need to add initially
    12. ' 4. Save the file
    13. ' 5. For sanity, we verify that we really did a lossless transcode
    14. ' 6. Open the new file and add metadata in-place
    15. Using originalFile As Stream = File.Open(originalPath, FileMode.Open, FileAccess.Read)
    16. ' Notice the BitmapCreateOptions and BitmapCacheOption. Using these options in the manner here
    17. ' will inform the JPEG decoder and encoder that we're doing a lossless transcode operation. If the
    18. ' encoder is anything but a JPEG encoder, then this no longer is a lossless operation.
    19. ' ( Details: Basically BitmapCreateOptions.PreservePixelFormat | BitmapCreateOptions.IgnoreColorProfile
    20. ' tell the decoder to use the original image bits and BitmapCacheOption.None tells the decoder to wait
    21. ' with decoding. So, at the time of encoding the JPEG encoder understands that the input was a JPEG
    22. ' and just copies over the image bits without decompressing and recompressing them. Hence, this is a
    23. ' lossless operation. )
    24. Dim original As BitmapDecoder = BitmapDecoder.Create(originalFile, createOptions, BitmapCacheOption.None)
    25. If Not original.CodecInfo.FileExtensions.Contains("jpg") Then
    26. Console.WriteLine("The file you passed in is not a JPEG.")
    27. 'Return
    28. End If
    29. Dim output As New JpegBitmapEncoder()
    30. ' If you're just interested in doing a lossless transcode without adding metadata, just do this:
    31. 'output.Frames = original.Frames;
    32. ' If you want to add metadata to the image using the InPlaceBitmapMetadataWriter, first add padding:
    33. If original.Frames(0) IsNot Nothing AndAlso original.Frames(0).Metadata IsNot Nothing Then
    34. ' Your gut feel may want you to do something like:
    35. ' output.Frames = original.Frames;
    36. ' BitmapMetadata metadata = output.Frames[0].Metadata as BitmapMetadata;
    37. ' if (metadata != null)
    38. ' {
    39. ' metadata.SetQuery("/app1/ifd/PaddingSchema:Padding", paddingAmount);
    40. ' }
    41. ' However, the BitmapMetadata object is frozen. So, you need to clone the BitmapMetadata and then
    42. ' set the padding on it. Lastly, you need to create a "new" frame with the updated metadata.
    43. Dim metadata As BitmapMetadata = TryCast(original.Frames(0).Metadata.Clone(), BitmapMetadata)
    44. ' Of the metadata handlers that we ship in WIC, padding can only exist in IFD, EXIF, and XMP.
    45. ' Third parties implementing their own metadata handler may wish to support IWICFastMetadataEncoder
    46. ' and hence support padding as well.
    47. metadata.SetQuery("/app1/ifd/PaddingSchema:Padding", paddingAmount)
    48. metadata.SetQuery("/app1/ifd/exif/PaddingSchema:Padding", paddingAmount)
    49. metadata.SetQuery("/xmp/PaddingSchema:Padding", paddingAmount)
    50. metadata.Title = "Das ist der Titel"
    51. metadata.SetQuery("System.Keywords", "Das ist eine Markierung")
    52. metadata.SetQuery("System.Author", "Ich bin der Autor von diesem Foto")
    53. metadata.Copyright = "Das ist das Copyrigh von dem Foto"
    54. metadata.Rating = "5"
    55. ' Create a new frame identical to the one from the original image, except the metadata will have padding.
    56. ' Essentially we want to keep this as close as possible to:
    57. ' output.Frames = original.Frames;
    58. output.Frames.Add(BitmapFrame.Create(original.Frames(0), original.Frames(0).Thumbnail, metadata, original.Frames(0).ColorContexts))
    59. End If
    60. Using outputFile As Stream = File.Open(outputPath, FileMode.Create, FileAccess.ReadWrite)
    61. output.Save(outputFile)
    62. End Using
    63. End Using
    64. ' For sanity, let's verify that the original and the output contain image bits that are the same.
    65. Using originalFile As Stream = File.Open(originalPath, FileMode.Open, FileAccess.Read)
    66. Dim original As BitmapDecoder = BitmapDecoder.Create(originalFile, createOptions, BitmapCacheOption.None)
    67. Using savedFile As Stream = File.Open(outputPath, FileMode.Open, FileAccess.Read)
    68. Dim output As BitmapDecoder = BitmapDecoder.Create(savedFile, createOptions, BitmapCacheOption.None)
    69. End Using
    70. End Using
    71. Dim originalInfo As New FileInfo(originalPath)
    72. Dim outputInfo As New FileInfo(outputPath)
    73. Console.WriteLine()
    74. Console.WriteLine("Original File Size: " & vbTab & vbTab & vbTab & "{0}", originalInfo.Length)
    75. Console.WriteLine("After Padding File Size: " & vbTab & vbTab & "{0}", outputInfo.Length)
    76. Return True
    77. End Function

    Kipippo schrieb:

    im Netz
    Würdest Du bitte die Quelle nennen?
    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!
    Hallo Kipippo,

    könntest Du mir / uns allen vielleicht auch noch sagen, welche Impports bzw. Verweise Du hierfür genutzt hast? Der Link von der Quelle ist leider nicht mehr gültig.

    Wenn ich nämlich Deine Funktion so in ein VB-Net 2010 Express - Projekt kopiere, dann bekomme ich schn so einige Fehler

    1. Dim createOptions As BitmapCreateOptions ..
    2. Dim original As BitmapDecoder ...
    3. Dim output As New JpegBitmapEncoder() ...
    4. Dim metadata As BitmapMetadata ...
    5. output.Frames.Add(BitmapFrame ...
    Jeweils das letzte Wort ist unterstrichen

    Den Anfang habe ich wie folgt schon selbst geändert;
    Imports System.IO

    Module Module1
    ' set the padding on it. Lastly, you need to create a "new" frame with the updated metadata.
    Function MetaDataEditor() As Boolean

    Wäre echt super, wenn Du mir Deinen vollständigen Code incl. der Verweise geben könntest.

    Vielen Dank
    Volker
    P.S. Wenn jemand anderes natürlich mir bei den Fehlern helfen kann, gerne.
    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!