2010-05-02 20 views
6

Su alcuni file .JPG (anteprime EPS, generate da Adobe Illustrator) in Windows 7 InPlaceBitmapMetadataWriter.TrySave() restituisce true dopo alcune chiamate SetQuery(), ma non fa nulla.InPlaceBitmapMetadataWriter.TrySave() restituisce true ma non fa nulla

codice di esempio:

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

È possibile riprodurre il problema (se si dispone di Windows 7) scaricando campione di immagine e l'utilizzo di questo esempio di codice per impostare il titolo su questa immagine. L'immagine ha spazio sufficiente per i metadati e questo esempio di codice funziona correttamente sul mio WinXP. Lo stesso codice funziona bene su Win7 con altri file .JPG.

Tutte le idee sono benvenute :)

risposta

0

io ancora non ho trovato la risposta e deve scrivere wrapper per exiftool invece di usare la via di WPF per lavorare con i metadati ... Può essere SOM1 lo troveranno utile.

4

due cose:

  1. Non credo che sarà in grado di scrivere al vostro metadata variabile proprio così, come sarà congelato. Quindi, si dovrà clonarlo:

     
    BitmapMetadata metadata = frame.Metadata.Clone() as BitmapMetadata; 
    
  2. Imbottitura, è necessario imbottitura. L'ho scoperto dopo circa un giorno di lavoro in giro cercando di fare del codice (simile al tuo) lavoro. InPlaceBitmapMetadataWriter non funzionerà se non c'è riempimento dei metadati nel file immagine. quindi è necessario qualcosa di simile:

     
    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); 
        } 
    } 
    

Ora è possibile utilizzare il file che si trova in _myoutputpath che ha aggiunto metadati imbottitura per le InPlaceBitmapMetadataWriter operazioni.

This article e il codice allegato dovrebbero aiutarti.

+2

TrySave() restituisce _true_! Ma non fa niente. Quindi non c'è modo di scoprire se i metadati sono scritti o meno. – mephisto123

+0

Lazo, non esiste un metodo di salvataggio per encoder in .NET 4. – Roger

3

Hi Ho trovato this articolo su InPlaceBitmapMetadataWriter in cui ha detto che il ragazzo che TrySave() potrebbe danneggiare l'immagine e per questo che ha consigliato di fare TrySave() sulla copia del file originale, e se questo non funziona, aggiungere imbottitura alla copia del file originale e di TrySave() di nuovo e se funziona, eliminare l'originale e rinominare la copia.

Mi sono grattato la testa e mi sono chiesto perché dovrei preoccuparmi di InPlaceBitmapMetadataWriter e scrivere il file originale 3x sul disco nel caso in cui TrySave() non funzioni perché non c'è abbastanza padding, se posso clonare i metadati, scrivere qualsiasi cosa in loro e assemblare file jpeg subito.

Poi ho iniziato a pensare che forse grazie a InPlaceBitmapMetadataWriter posso modificare i metadati senza perdere qualità, ma sembra che "solo" ti aiuti a scrivere più velocemente i metadati se c'è abbastanza padding.

Ho scritto un piccolo test in cui comprimo un file più volte per vedere il degrado della qualità e lo si può vedere nella compressione del terzo quarto, che è molto brutta.

Ma fortunatamente, se si utilizza sempre lo stesso QualityLevel con JpegBitmapEncoder, non si verifica alcun degrado.

In questo esempio, riscrivo le parole chiave 100x nei metadati e la qualità sembra non cambiare.

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); 
     } 
    } 
    } 
} 
Problemi correlati