简体   繁体   中英

How to write EXIF data to an image in C#?

I have great trouble to write EXIF data to an image. So far I have managed to write data that requires a string as input. However I am at loss on how to do it for elements that require a different type (eg exposure time, shutter speed).

I am following this guide but there is no example for something besides a string. This website explains which data type I have to use and the Microsoft documentation provides the corresponding numerical value. Unfortunately I am unable to use this to solve my problem. To find out which ID is corresponding to which value, I am using this list and the offical documentation .

System.Drawing.Image imgEXIF = System.Drawing.Image.FromFile("D:/def.jpg");
System.Drawing.Image imgDummy = System.Drawing.Image.FromFile("D:/IMG_3214.jpg");
System.Drawing.Imaging.PropertyItem item = imgDummy.PropertyItems[0];
item.Id = 0x9286;
item.Type = 2; //String
item.Value = System.Text.Encoding.UTF8.GetBytes("Hello World\r\nthis is a test\0");
item.Len = item.Value.Length;
imgEXIF.SetPropertyItem(item);
imgEXIF.Save("D:/ghi.jpg");

Any help on how to write EXIF data that is not a string would be greatly appreciated!!

What goes into Value on the PropertyItem is a byte array based on the corresponding Type for that field. For the text fields you can already do, that byte array takes the form of an ASCII byte array which is null terminated. The other types I have commented below under TagTypes . For the Exposure Time field, this is an 8 byte array consisting of two unsigned 32-bit integers - the numerator, followed by the denominator. We can use the BitConverter.GetBytes() method to convert uint (unsigned 32-bit integer) to a 4 byte representation - then simply join with another byte array to get the pair of numerator and denominator.

Here are some extensions which show how to use a Short / type 3 field and a Rational / type 5 field in addition to a Type 2 string field:

public static class ImageMetaExtensions
{
    public static void SetMaxAperture(this Image image, uint numerator, uint denominator)
    {
        SetMetaDataItem(image, MAX_APERTURE, (short)TagTypes.RATIONAL, GetPairUnsigned32Integer(numerator, denominator));
    }

    public static void SetExposureTime(this Image image, uint numerator, uint denominator)
    {
        SetMetaDataItem(image, EXPOSURE_TIME, (short)TagTypes.RATIONAL, GetPairUnsigned32Integer(numerator, denominator));
    }

    public static void SetUserComment(this Image image, string text)
    {
        SetMetaDataItem(image, USER_COMMENT, (short)TagTypes.ASCII, GetNullTerminatedString(text));
    }

    public static void Set35mmFocalLength(this Image image, short focalLength)
    {
        SetMetaDataItem(image, FOCALLENGTH_35MM, (short)TagTypes.SHORT, BitConverter.GetBytes(focalLength));
    }

    public enum TagTypes : short
    {
        BYTE = 1, // 8 bit unsigned integer
        ASCII = 2,
        SHORT = 3, // 16-bit unsigned integer
        LONG = 4, // 32-bit unsigned integer
        RATIONAL = 5, // two unsigned longs - first numerator, second denominator
        UNDEFINED = 6, // any value depending on field definition
        SLONG = 7, // signed 32-bit
        SRATIONAL = 10 // signed pair of 32-bit numerator/denominator
    }

    private static void SetMetaDataItem(Image image, int id, short type, byte[] data)
    {
        PropertyItem anyItem = image.PropertyItems[0];
        anyItem.Id = id;
        anyItem.Len = data.Length;
        anyItem.Type = type;
        anyItem.Value = data;
        image.SetPropertyItem(anyItem);
    }

    private static byte[] GetPairUnsigned32Integer(uint numerator, uint denominator)
    {
        return BitConverter.GetBytes(numerator).Concat(BitConverter.GetBytes(denominator)).ToArray();
    }

    private static byte[] GetNullTerminatedString(string text)
    {
        return Encoding.ASCII.GetBytes(text + "\0");
    }

    private const int EXPOSURE_TIME = 0x829A;      
    private const int USER_COMMENT = 0x9286;
    private const int MAX_APERTURE = 0x9205;
    private const int FOCALLENGTH_35MM = 0xA405;
}

Usage:

System.Drawing.Image myImage = System.Drawing.Image.FromFile(@"c:\temp\someimage.jpg");
myImage.SetExposureTime(1, 30); // 1/30sec
myImage.SetUserComment("Hello, world");
myImage.Set35mmFocalLength(5);
myImage.Save(@"c:\temp\someotherimage.jpg"); // save somewhere else

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM