如何在 C# 中将 EXIF 数据写入图像?
How to write EXIF data to an image in C#?
我很难将 EXIF 数据写入图像。到目前为止,我已经设法编写了需要字符串作为输入的数据。但是,对于需要不同类型(例如曝光时间、快门速度)的元素,我不知道如何做到这一点。
我在下面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提供了相应的数值。不幸的是我无法用它来解决我的问题。
为了找出哪个 ID 对应于哪个值,我使用 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[=10=]");
item.Len = item.Value.Length;
imgEXIF.SetPropertyItem(item);
imgEXIF.Save("D:/ghi.jpg");
任何关于如何编写非字符串的 EXIF 数据的帮助将不胜感激!!
在 PropertyItem
上进入 Value
的是一个基于该字段对应 Type
的字节数组。对于您已经可以做的文本字段,该字节数组采用 ASCII
字节数组的形式,该数组以 null 结尾。我在下面 TagTypes
下评论的其他类型。对于曝光时间字段,这是一个 8 字节数组,由两个无符号 32 位整数组成 - 分子,后跟分母。我们可以使用 BitConverter.GetBytes()
方法将 uint
(无符号 32 位整数)转换为 4 字节表示 - 然后简单地与另一个字节数组连接以获得分子和分母对。
这里有一些扩展,展示了除了 Type 2 字符串字段之外如何使用 Short/type 3 字段和 Rational/type 5 字段:
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 + "[=10=]");
}
private const int EXPOSURE_TIME = 0x829A;
private const int USER_COMMENT = 0x9286;
private const int MAX_APERTURE = 0x9205;
private const int FOCALLENGTH_35MM = 0xA405;
}
用法:
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
我很难将 EXIF 数据写入图像。到目前为止,我已经设法编写了需要字符串作为输入的数据。但是,对于需要不同类型(例如曝光时间、快门速度)的元素,我不知道如何做到这一点。
我在下面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提供了相应的数值。不幸的是我无法用它来解决我的问题。 为了找出哪个 ID 对应于哪个值,我使用 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[=10=]");
item.Len = item.Value.Length;
imgEXIF.SetPropertyItem(item);
imgEXIF.Save("D:/ghi.jpg");
任何关于如何编写非字符串的 EXIF 数据的帮助将不胜感激!!
在 PropertyItem
上进入 Value
的是一个基于该字段对应 Type
的字节数组。对于您已经可以做的文本字段,该字节数组采用 ASCII
字节数组的形式,该数组以 null 结尾。我在下面 TagTypes
下评论的其他类型。对于曝光时间字段,这是一个 8 字节数组,由两个无符号 32 位整数组成 - 分子,后跟分母。我们可以使用 BitConverter.GetBytes()
方法将 uint
(无符号 32 位整数)转换为 4 字节表示 - 然后简单地与另一个字节数组连接以获得分子和分母对。
这里有一些扩展,展示了除了 Type 2 字符串字段之外如何使用 Short/type 3 字段和 Rational/type 5 字段:
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 + "[=10=]");
}
private const int EXPOSURE_TIME = 0x829A;
private const int USER_COMMENT = 0x9286;
private const int MAX_APERTURE = 0x9205;
private const int FOCALLENGTH_35MM = 0xA405;
}
用法:
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