c# - 如何在C#中将EXIF数据写入图像?

标签 c# exif

我在将 EXIF 数据写入图像时遇到了很大的麻烦。到目前为止,我已经成功编写了需要字符串作为输入的数据。然而,我不知道如何处理需要不同类型的元素(例如曝光时间、快门速度)。

我正在关注this指南,但除了字符串之外没有任何示例。这个website解释了我必须使用哪种数据类型以及 Microsoft documentation提供相应的数值。不幸的是我无法用它来解决我的问题。 为了找出哪个 ID 对应于哪个值,我使用 this名单及官方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");

任何有关如何编写非字符串 EXIF 数据的帮助将不胜感激!!

最佳答案

PropertyItem 上的Value 中包含的是一个基于该字段相应Type 的字节数组。对于您已经可以执行的文本字段,该字节数组采用以 null 结尾的 ASCII 字节数组的形式。我在下面的 TagTypes 下评论了其他类型。对于曝光时间字段,这是一个 8 字节数组,由两个无符号 32 位整数组成 - 分子,后跟分母。我们可以使用 BitConverter.GetBytes() 方法将 uint(无符号 32 位整数)转换为 4 字节表示形式 - 然后只需与另一个字节数组连接即可获得一对分子和分母。

以下是一些扩展,展示了如何使用 Short/type 3 字段和 Rational/type 5 字段以及 Type 2 字符串字段:

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

用法:

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

关于c# - 如何在C#中将EXIF数据写入图像?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56210826/

相关文章:

c# - 错误 CS7036 没有给定的参数对应于 'driver' 的所需形式参数 'SpecflowBaseTest.SpecflowBaseTest(IWebDriver)'

C#:具有显式添加/删除的事件!=典型事件?

ios - 快速将 GPS 元数据字典添加到使用 AVFoundation 拍摄的图像

android - 关于如何从 URI 获取 Exif 数据的最终答案

c# - c# 中的 stdout 与 console.write

c# - 在 MVVM 中创建 WPF 动态面板

c# - ASP.NET MVC 2 验证选择列表

android - 以 Intent ACTION_IMAGE_CAPTURE 开始设置 android 相机的方向

javascript - 将图像转换为本地存储的 DataURL 时删除了 EXIF?

ios - 来自 iOS 相机的图像在 Web 应用程序中旋转发送