2010-05-02 19 views
6

Bei einigen .JPG-Dateien (EPS-Vorschau, erstellt von Adobe Illustrator) in Windows 7 gibt InPlaceBitmapMetadataWriter.TrySave() nach einigen SetQuery() - Aufrufen den Wert true zurück, tut aber nichts.InPlaceBitmapMetadataWriter.TrySave() gibt true zurück, tut aber nichts

Codebeispiel:

BitmapDecoder decoder; 
BitmapFrame frame; 
BitmapMetadata metadata; 
InPlaceBitmapMetadataWriter writer; 
decoder = BitmapDecoder.Create(s, BitmapCreateOptions.PreservePixelFormat | BitmapCreateOptions.IgnoreColorProfile, BitmapCacheOption.Default); 
frame = decoder.Frames[0]; 
metadata = frame.Metadata as BitmapMetadata; 
writer = frame.CreateInPlaceBitmapMetadataWriter(); 
try { 
    writer.SetQuery("System.Title", title); 
    writer.SetQuery(@"/app1/ifd/{ushort=" + exiftagids[0] + "} ", (title + '\0').ToCharArray()); 
    writer.SetQuery(@"/app13/irb/8bimiptc/iptc/object name", title); 
    return writer.TrySave(); 
} 
catch { 
    return false; 
} 

Image sample

Sie können Problem reproduzieren (wenn Sie Windows 7) durch Bild Probe Download und die Verwendung dieses Codebeispiel Titel auf diesem Bild zu setzen. Bild hat genug Platz für Metadaten - und dieses Codebeispiel funktioniert gut auf meinem WinXP. Derselbe Code funktioniert auf Win7 mit anderen .JPG-Dateien.

Alle Ideen sind willkommen :)

Antwort

0

ich noch keine Antwort gefunden haben und hat Wrapper für exiftool zu schreiben, anstatt WPF Möglichkeit der Verwendung von mit Metadaten zu arbeiten ... som1 werden kann, wird es hilfreich sein.

4

Zwei Dinge:

  1. Ich glaube nicht, Sie in der Lage sein werden, Ihre metadata Variable wie das nur zu schreiben, wie es eingefroren werden. Also, werden Sie es klonen müssen:

     
    BitmapMetadata metadata = frame.Metadata.Clone() as BitmapMetadata; 
    
  2. Padding, müssen Sie Polsterung. Ich fand das heraus, nachdem ich ungefähr einen Tag damit verbracht hatte, herumzubasteln, um einen Code (ähnlich dem deinen) zu erstellen. InPlaceBitmapMetadataWriter funktioniert nicht, wenn in Ihrer Bilddatei kein Metadaten-Padding vorhanden ist. Sie müssen also so etwas wie:

     
    JpegBitmapEncoder encoder = new JpegBitmapEncoder(); 
    if(frame != null && metadata != null) { 
        metadata.SetQuery("/app1/ifd/PaddingSchema:Padding", padding); 
        encoder.Frames.Add(BitmapFrame.Create(frame, frame.Thumbnail, metadata, frame.ColorContexts)); 
        using (Stream outputFile = File.Open(_myoutputpath, FileMode.Create, FileAccess.ReadWrite)) { 
         encoder.Save(outputFile); 
        } 
    } 
    

Jetzt können Sie die Datei auf _myoutputpath befindet verwenden, die Metadaten-Polsterung für Ihre InPlaceBitmapMetadataWriter Operationen hinzugefügt.

This article und der angehängte Code sollte Ihnen helfen.

+2

TrySave() gibt _true_ zurück! Tut aber nichts. Es gibt also keine Möglichkeit herauszufinden, ob Metadaten geschrieben sind oder nicht. – mephisto123

+0

Lazo, es gibt keine sichere Methode für den Encoder in .NET 4. – Roger

3

Hallo Ich fand this Artikel über InPlaceBitmapMetadataWriter, wo der Typ sagte, dass TrySave() das Bild beschädigen könnte und deshalb riet er, TrySave() auf die Kopie der ursprünglichen Datei zu tun und wenn dies nicht funktioniert, fügen Sie Auffüllen zur Kopie der Originaldatei und als TrySave() erneut und wenn es funktioniert, löschen Sie das Original und benennen Sie die Kopie um.

Ich kratzte mich am Kopf und fragte mich, warum ich mich mit InPlaceBitmapMetadataWriter beschäftigen und 3x Originaldatei auf die Festplatte schreiben sollte, falls TrySave() nicht funktioniert, da ich nicht genügend Padding habe, Metadaten klonen kann sie und jpeg Datei sofort zusammenbauen.

Dann begann ich zu denken, dass ich dank InPlaceBitmapMetadataWriter Metadaten bearbeiten kann, ohne Qualität zu verlieren, aber es sieht so aus, als ob es "nur" hilft, Metadaten schneller zu schreiben, wenn genug Padding vorhanden ist.

Ich schrieb einen kleinen Test, wo ich eine Datei viele Male komprimiere, um die Qualitätsverschlechterung zu sehen, und Sie können es in der dritten bis vierten Kompression sehen, die sehr schlecht ist.

Aber zum Glück, wenn Sie immer die gleichen QualityLevel mit JpegBitmapEncoder verwenden, gibt es keine Verschlechterung.

In diesem Beispiel habe ich die Schlüsselwörter 100x in Metadaten umgeschrieben und die Qualität scheint sich nicht zu ändern.

private void LosslessJpegTest() { 
    var original = "d:\\!test\\TestInTest\\20150205_123011.jpg"; 
    var copy = original; 
    const BitmapCreateOptions createOptions = BitmapCreateOptions.PreservePixelFormat | BitmapCreateOptions.IgnoreColorProfile; 

    for (int i = 0; i < 100; i++) { 
    using (Stream originalFileStream = File.Open(copy, FileMode.Open, FileAccess.Read)) { 
     BitmapDecoder decoder = BitmapDecoder.Create(originalFileStream, createOptions, BitmapCacheOption.None); 

     if (decoder.CodecInfo == null || !decoder.CodecInfo.FileExtensions.Contains("jpg") || decoder.Frames[0] == null) 
     continue; 

     BitmapMetadata metadata = decoder.Frames[0].Metadata == null 
     ? new BitmapMetadata("jpg") 
     : decoder.Frames[0].Metadata.Clone() as BitmapMetadata; 

     if (metadata == null) continue; 

     var keywords = metadata.Keywords == null ? new List<string>() : new List<string>(metadata.Keywords); 
     keywords.Add($"Keyword {i:000}"); 
     metadata.Keywords = new ReadOnlyCollection<string>(keywords); 

     JpegBitmapEncoder encoder = new JpegBitmapEncoder {QualityLevel = 80}; 
     encoder.Frames.Add(BitmapFrame.Create(decoder.Frames[0], decoder.Frames[0].Thumbnail, metadata, 
     decoder.Frames[0].ColorContexts)); 

     copy = original.Replace(".", $"_{i:000}."); 

     using (Stream newFileStream = File.Open(copy, FileMode.Create, FileAccess.ReadWrite)) { 
     encoder.Save(newFileStream); 
     } 
    } 
    } 
}