2010-05-02 18 views
6

En algunos archivos .JPG (previsualizaciones EPS, generadas por Adobe Illustrator) en Windows 7 InPlaceBitmapMetadataWriter.TrySave() devuelve verdadero después de algunas llamadas SetQuery(), pero no hace nada.InPlaceBitmapMetadataWriter.TrySave() devuelve verdadero pero no hace nada

Ejemplo de código:

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

Puede reproducir el problema (si tiene Windows 7) mediante la descarga de la muestra de la imagen y el uso de este ejemplo de código para establecer el título de esta imagen. La imagen tiene suficiente espacio para los metadatos, y este ejemplo de código funciona bien en mi WinXP. El mismo código funciona bien en Win7 con otros archivos .JPG.

Todas las ideas son bienvenidas :)

Respuesta

0

todavía no encontró la respuesta y tiene que escribir envoltura para exiftool en lugar de utilizar el camino de WPF para trabajar con metadatos ... Puede ser SOM1, le resultará útil.

4

dos cosas:

  1. No creo que usted será capaz de escribir a la variable de metadata así como así, ya que será congelado. Por lo tanto, tendrá que clonarlo:

     
    BitmapMetadata metadata = frame.Metadata.Clone() as BitmapMetadata; 
    
  2. Relleno, que necesita relleno. Descubrí esto después de aproximadamente un día de retoques tratando de hacer funcionar algún código (similar al tuyo). InPlaceBitmapMetadataWriter no funcionará si no hay un relleno de metadatos en su archivo de imagen. por lo que necesita algo como:

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

Ahora se puede utilizar el archivo que se encuentra en _myoutputpath que ha añadido el relleno de metadatos para sus operaciones InPlaceBitmapMetadataWriter.

This article y el código adjunto deberían ayudarte.

+2

TrySave() returns _true_! Pero no hace nada. Entonces no hay manera de averiguar si los metadatos están escritos o no. – mephisto123

+0

Lazo, no hay método de guardado para el codificador en .NET 4. – Roger

3

Hola, encontré this artículo sobre InPlaceBitmapMetadataWriter donde el tipo dijo que TrySave() podría corromper la imagen y es por eso que recomendó hacer TrySave() en la copia del archivo original y, si esto no funciona, agregar relleno a la copia del archivo original y a TrySave() nuevamente y, si funciona, elimine el original y cambie el nombre de la copia.

Me rasqué la cabeza y me pregunté por qué debería molestarme con InPlaceBitmapMetadataWriter y escribir 3x archivo original en el disco por si TrySave() no funciona porque no hay suficiente relleno, si puedo clonar metadatos, escribir lo que sea ellos y ensamblar el archivo jpeg de inmediato.

Luego comencé a pensar que tal vez gracias a InPlaceBitmapMetadataWriter puedo editar metadatos sin perder calidad, pero parece que "solo" te ayuda a escribir metadatos más rápidamente si hay suficiente relleno.

Escribí una pequeña prueba donde comprime un archivo muchas veces para ver la degradación de la calidad y se puede ver en la compresión del tercer cuarto, que es muy malo.

Pero afortunadamente, si siempre utiliza el mismo QualityLevel con JpegBitmapEncoder, no hay degradación.

En este ejemplo reescribo palabras clave 100x en metadatos y la calidad parece no cambiar.

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