Cómo agregar 'Comentarios' a un archivo JPEG usando C #

votos
15

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.

Publicado el 18/11/2009 a las 11:51
fuente por usuario
En otros idiomas...                            


5 respuestas

votos
14

Basándonos en las otras respuestas que escribí la clase siguiente, que permite diversas manipulaciones de metadatos. Se utiliza de esta manera:

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 los otros no son grandes. Principalmente he rediseñado para ser más limpio esto. También uso las propiedades de más alto nivel de BitmapMetadata, en lugar de la SetQuerymétodo.

Aquí está el código completo, que está disponible bajo la licencia MIT . Usted tendrá que añadir referencias a PresentationCore, WindowsBasey 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];
    }
}
Respondida el 20/05/2014 a las 15:27
fuente por usuario

votos
11

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.

Respondida el 19/11/2009 a las 18:06
fuente por usuario

votos
1

Gracias a las respuestas aquí, he codificado una solución para establecer un comentario usando sólo la 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 se olvide de disponer la imagen devuelta por este método. (Por ejemplo, después de guardar la imagen en un archivo)

Respondida el 26/02/2014 a las 01:10
fuente por usuario

votos
1

Gracias a los consejos anteriores que fue capaz de poner el siguiente juntos. Lo he probado y parece que funciona. Uno de los mayores obstáculos fue la determinación de la identificación 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. i.e. 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();
Respondida el 13/12/2013 a las 00:25
fuente por usuario

votos
0

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

Respondida el 18/11/2009 a las 11:57
fuente por usuario

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more