Cómo agregar ‘Comentarios’ a un archivo JPEG usando C #

Dentro de la ventana de propiedades de una imagen JPEG, hay una pestaña llamada ‘Resumen’. Dentro de esta pestaña, hay un campo llamado ‘Comentarios’ Me gustaría escribir un código c # que agregará una cadena dada a este campo, por ejemplo, “Esta es una foto”.

¿Algún alma amable sabe cómo hacer esto?

Muchas gracias.

Basado en otras respuestas, escribí la siguiente clase que permite varias manipulaciones de metadatos. Lo usas así:

var jpeg = new JpegMetadataAdapter(pathToJpeg); jpeg.Metadata.Comment = "Some comments"; jpeg.Metadata.Title = "A title"; jpeg.Save(); // Saves the jpeg in-place jpeg.SaveAs(someNewPath); // Saves with a new path 

Las diferencias entre mi solución y las otras no son grandes. Principalmente he refactorizado esto para ser más limpio. También uso las propiedades de nivel superior de BitmapMetadata , en lugar del método SetQuery .

Aquí está el código completo, que está licenciado bajo la licencia de MIT . Deberá agregar referencias a PresentationCore , WindowsBase y System.Xaml .

 public class JpegMetadataAdapter { private readonly string path; private BitmapFrame frame; public readonly BitmapMetadata Metadata; public JpegMetadataAdapter(string path) { this.path = path; frame = getBitmapFrame(path); Metadata = (BitmapMetadata)frame.Metadata.Clone(); } public void Save() { SaveAs(path); } public void SaveAs(string path) { JpegBitmapEncoder encoder = new JpegBitmapEncoder(); encoder.Frames.Add(BitmapFrame.Create(frame, frame.Thumbnail, Metadata, frame.ColorContexts)); using (Stream stream = File.Open(path, FileMode.Create, FileAccess.ReadWrite)) { encoder.Save(stream); } } private BitmapFrame getBitmapFrame(string path) { BitmapDecoder decoder = null; using (Stream stream = File.Open(path, FileMode.Open, FileAccess.ReadWrite, FileShare.None)) { decoder = new JpegBitmapDecoder(stream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad); } return decoder.Frames[0]; } } 

El siguiente código soluciona mi problema y agrega comentarios a una imagen JPEG dada:

 public void addImageComment(string imageFlePath, string comments) { string jpegDirectory = Path.GetDirectoryName(imageFlePath); string jpegFileName = Path.GetFileNameWithoutExtension(imageFlePath); BitmapDecoder decoder = null; BitmapFrame bitmapFrame = null; BitmapMetadata metadata = null; FileInfo originalImage = new FileInfo(imageFlePath); if (File.Exists(imageFlePath)) { // load the jpg file with a JpegBitmapDecoder using (Stream jpegStreamIn = File.Open(imageFlePath, FileMode.Open, FileAccess.ReadWrite, FileShare.None)) { decoder = new JpegBitmapDecoder(jpegStreamIn, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad); } bitmapFrame = decoder.Frames[0]; metadata = (BitmapMetadata)bitmapFrame.Metadata; if (bitmapFrame != null) { BitmapMetadata metaData = (BitmapMetadata)bitmapFrame.Metadata.Clone(); if (metaData != null) { // modify the metadata metaData.SetQuery("/app1/ifd/exif:{uint=40092}", comments); // get an encoder to create a new jpg file with the new metadata. JpegBitmapEncoder encoder = new JpegBitmapEncoder(); encoder.Frames.Add(BitmapFrame.Create(bitmapFrame, bitmapFrame.Thumbnail, metaData, bitmapFrame.ColorContexts)); //string jpegNewFileName = Path.Combine(jpegDirectory, "JpegTemp.jpg"); // Delete the original originalImage.Delete(); // Save the new image using (Stream jpegStreamOut = File.Open(imageFlePath, FileMode.CreateNew, FileAccess.ReadWrite)) { encoder.Save(jpegStreamOut); } } } } } 

Esta es esencialmente una versión ligeramente modificada del código encontrado debajo del enlace que Konamiman amablemente suministró.

Tenga en cuenta que para que esto funcione, deberá agregar referencias .NET a PresentationCore y WindowsBase . Si usa Visual Studio 2008, esto se puede lograr a través de lo siguiente:

  1. Haga clic derecho en su proyecto en el Explorador de soluciones

  2. En la lista desplegable, selecciona Agregar ‘Referencia …’

  3. Desde la nueva casilla que se abre, selecciona la pestaña ‘.NET’

  4. Desplácese a las dos referencias mencionadas anteriormente y en cada una, haga clic en Aceptar

Muchas gracias a danbystrom y Konamiman por su ayuda en este asunto. Realmente aprecio la respuesta rápida.

Gracias a los consejos anteriores, pude juntar lo siguiente. Lo probé y parece funcionar. Uno de los mayores obstáculos fue determinar la Id necesaria para el campo que desea asignar.

 string fileName = "c:/SomeImage.jpg"; // Retrieve the Image System.Drawing.Image originalImage = System.Drawing.Image.FromFile(fileName); // Get the list of existing PropertyItems. ie the metadata PropertyItem[] properties = originalImage.PropertyItems; // Create a bitmap image to assign attributes and do whatever else.. Bitmap bmpImage = new Bitmap((Bitmap)originalImage); // Don't need this anymore originalImage.Dispose(); // Get / setup a PropertyItem PropertyItem item = properties[0]; // We have to copy an existing one since no constructor exists // This will assign "Joe Doe" to the "Authors" metadata field string sTmp = "Joe DoeX"; // The X will be replaced with a null. String must be null terminated. var itemData = System.Text.Encoding.UTF8.GetBytes(sTmp); itemData[itemData.Length - 1] = 0;// Strings must be null terminated or they will run together item.Type = 2; //String (ASCII) item.Id = 315; // Author(s), 315 is mapped to the "Authors" field item.Len = itemData.Length; // Number of items in the byte array item.Value = itemData; // The byte array bmpImage.SetPropertyItem(item); // Assign / add to the bitmap // This will assign "MyApplication" to the "Program Name" field sTmp = "MyApplicationX"; itemData = System.Text.Encoding.UTF8.GetBytes(sTmp); itemData[itemData.Length - 1] = 0; // Strings must be null terminated or they will run together item.Type = 2; //String (ASCII) item.Id = 305; // Program Name, 305 is mapped to the "Program Name" field item.Len = itemData.Length; item.Value = itemData; bmpImage.SetPropertyItem(item); // Save the image bmpImage.Save(fileName, System.Drawing.Imaging.ImageFormat.Jpeg); //Clean up bmpImage.Dispose(); 

Gracias a las respuestas aquí, he codificado una solución para establecer un comentario solo con memoria:

 public static Image SetImageComment(Image image, string comment) { using (var memStream = new MemoryStream()) { image.Save(memStream, ImageFormat.Jpeg); memStream.Position = 0; var decoder = new JpegBitmapDecoder(memStream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.OnLoad); BitmapMetadata metadata; if (decoder.Metadata == null) { metadata = new BitmapMetadata("jpg"); } else { metadata = decoder.Metadata; } metadata.Comment = comment; var bitmapFrame = decoder.Frames[0]; BitmapEncoder encoder = new JpegBitmapEncoder(); encoder.Frames.Add(BitmapFrame.Create(bitmapFrame, bitmapFrame.Thumbnail, metadata, bitmapFrame.ColorContexts)); var imageStream = new MemoryStream(); encoder.Save(imageStream); imageStream.Position = 0; image.Dispose(); image = null; return Image.FromStream(imageStream); } } 

No olvide disponer de la imagen devuelta por este método. (Por ejemplo, después de guardar la imagen en un archivo)

La parte fácil:

Agregue este elemento de propiedad:

 var data = System.Text.Encoding.UTF8.GetBytes( "Some comments" ); PropertyItem pi; *** create an empty PropertyItem here pi.Type = 2; pi.Id = 37510; pi.Len = data.Length; pi.Value = data; 

A la colección PropertItems de la imagen.

La parte algo más engorrosa: ¿cómo se crea un nuevo PropertyItem, ya que no tiene un constructor público?

El “truco” común es tener una imagen vacía de la que pueda robar un PropertyItem. suspiro