C#在JPG'中设置和获取PropertyItem;未找到属性';例外

C#在JPG'中设置和获取PropertyItem;未找到属性';例外,c#,jpeg,C#,Jpeg,在C#中,我试图在jpg文件中设置以下属性。但当我试图取回它们时,我得到了属性NotFoundException。此外,SetPropertyItem调用无法报告成功\失败,因此很难理解出错的原因 0x5111 PropertyTagPixelPerUnitX 0x5112 属性标签像素属性 string file = "New.jpg"; double x = 24524.5555598; double y = 234123.4123423; Image img = Image.FromFil

在C#中,我试图在jpg文件中设置以下属性。但当我试图取回它们时,我得到了属性NotFoundException。此外,SetPropertyItem调用无法报告成功\失败,因此很难理解出错的原因

0x5111 PropertyTagPixelPerUnitX

0x5112 属性标签像素属性

string file = "New.jpg";
double x = 24524.5555598;
double y = 234123.4123423;
Image img = Image.FromFile(file);
PropertyItem[] props = img.PropertyItems;
PropertyItem newProp1 = props.FirstOrDefault();
newProp1.Id = 0x5111;
newProp1.Type = 1;
newProp1.Value = BitConverter.GetBytes(x);
newProp1.Len = newProp1.Value.Length;

PropertyItem newProp2 = props.FirstOrDefault();
newProp2.Id = 0x5112;
newProp2.Type = 1;
newProp2.Value = BitConverter.GetBytes(y);
newProp2.Len = newProp1.Value.Length;

img.SetPropertyItem(newProp1);
img.SetPropertyItem(newProp2);
img.Save("New1.jpg", ImageFormat.Jpeg);
和检索它们的代码

string file = "New1.jpg";
Image img = Image.FromFile(file);
PropertyItem prop = img.GetPropertyItem(0x5111);

上面这行抛出异常“Property not found”

我不知道为什么他们将PropertyItem构造函数设置为内部,并且没有提供任何其他创建属性项的方法。但是,您可以使用反射来解决这个奇怪的问题,它将起作用:

        string file = @"New1.jpg";
        double x = 24524.5555598;
        double y = 234123.4123423;
        var img = System.Drawing.Image.FromFile(file);
        // note how to force Activator.CreateInstance to call internal constructor, 
        // it's important to call this overload
        var newProp1 = (PropertyItem) Activator.CreateInstance(typeof(PropertyItem), BindingFlags.Instance | BindingFlags.NonPublic, null, new object[0], CultureInfo.InvariantCulture);
        newProp1.Id = 0x5111;
        newProp1.Type = 1;
        newProp1.Value = BitConverter.GetBytes(x);
        newProp1.Len = newProp1.Value.Length;

        var newProp2 = (PropertyItem)Activator.CreateInstance(typeof(PropertyItem), BindingFlags.Instance | BindingFlags.NonPublic, null, new object[0], CultureInfo.InvariantCulture);
        newProp2.Id = 0x5112;
        newProp2.Type = 1;
        newProp2.Value = BitConverter.GetBytes(y);
        newProp2.Len = newProp1.Value.Length;

        img.SetPropertyItem(newProp1);
        img.SetPropertyItem(newProp2);
        img.Save("New1.jpg", ImageFormat.Jpeg);

在代码中用newProp2覆盖newProp1。它们都引用了相同的第一个属性。啊,谢谢你指出。但是,由于PropertyItem不随构造函数提供,如何添加新属性(0x5112)而不影响现有属性?请注意,您可能需要检查具有此类id的属性是否已经存在,如果是,则更新现有项。谁知道复制的属性将如何运行。这似乎可行,但当我读回保存的文件时,新属性不在那里。@JoelCoehoorn我刚刚用简单的jpeg图像测试了这段代码,所有新的exif属性在保存后都在那里(在“PropertyItems”数组中),也用image magick
identify
工具确认。据我所知,.NET图像类不太擅长使用exif标记,可能会跳过其中的一些标记,但对于这个特定的标记(PixelPerUnit),它工作得很好。如果您试图设置不同的标记-可能就是这样。如果确实添加了标记,请确保使用identify或任何其他工具,因为Image.PropertyItems不是这方面的可靠来源。您是对的……这确实有效,但仅适用于JPG。我正在开发一个应用程序,让学生工作者可以用面部区域快速注释肖像图像,这样进一步的自动化过程就可以裁剪图像并调整其大小,以便快速上传到小型学院的各种系统(图书馆流通、学生门户、SIS、LMS、电子邮件等),而不管目标需要多大的长宽比,没有剪掉任何一张脸。我通常有JPG,但偶尔会有png、bmp或gif。我想要一些通用的东西来为所有这些类型工作。看起来我需要为每种类型分别编写代码:(@JoelCoehoorn,我想这并不是那么简单。我尝试了各种png文件,效果很好,尽管官方png不支持exif标记。各种软件可以将它们嵌入png,其他软件可以读取,但没有官方规范。(与jpeg不同)。bmp也是如此(实际上从未听说过bmp中的exif标记,即使是最复杂的工具,如exiftool,也无法将exif标记添加到bmp中)。以下是关于png和exif的问题: