在 C# 中从 JPEG、XMP 或 EXIF 读取数据元数据

发布于 2024-08-21 20:42:58 字数 342 浏览 6 评论 0原文

我一直在寻找一种在 C# 中从 JPEG 文件中读取元数据(特别是拍摄日期)的好方法,但我的发现有点短。据我所知,现有信息显示的代码如下;

BitmapMetadata bmd = (BitmapMetadata)frame.Metadata;
string a1 = (string)bmd.GetQuery("/app1/ifd/exif:{uint=36867}");

但由于我的无知,我不知道 GetQuery() 将返回哪些元数据,或者传递什么。

我想首先尝试读取 XMP,如果 XMP 不存在,则返回到 EXIF。有没有一种简单的方法可以做到这一点?

谢谢。

I've been looking around for a decent way of reading metadata (specifically, the date taken) from JPEG files in C#, and am coming up a little short. Existing information, as far as I can see, shows code like the following;

BitmapMetadata bmd = (BitmapMetadata)frame.Metadata;
string a1 = (string)bmd.GetQuery("/app1/ifd/exif:{uint=36867}");

But in my ignorance I have no idea what bit of metadata GetQuery() will return, or what to pass it.

I want to attempt reading XMP first, falling back to EXIF if XMP does not exist. Is there a simple way of doing this?

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

不奢求什么 2024-08-28 20:42:58

以下似乎工作得很好,但如果有什么不好的地方,我会很感激任何评论。

    public string GetDate(FileInfo f)
    {
        using(FileStream fs = new FileStream(f.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
        {
            BitmapSource img = BitmapFrame.Create(fs);
            BitmapMetadata md = (BitmapMetadata)img.Metadata;
            string date = md.DateTaken;
            Console.WriteLine(date);
            return date;
        }
    }

The following seems to work nicely, but if there's something bad about it, I'd appreciate any comments.

    public string GetDate(FileInfo f)
    {
        using(FileStream fs = new FileStream(f.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
        {
            BitmapSource img = BitmapFrame.Create(fs);
            BitmapMetadata md = (BitmapMetadata)img.Metadata;
            string date = md.DateTaken;
            Console.WriteLine(date);
            return date;
        }
    }
燃情 2024-08-28 20:42:58

我最近将我的长期开源 Java 库移植到了 .NET,它支持 XMP、Exif、ICC、JFIF 以及跨一系列图像格式的更多类型的元数据。它一定会实现你所追求的。

https://github.com/drewnoakes/metadata-extractor-dotnet

var directories = ImageMetadataReader.ReadMetadata(imagePath);
var subIfdDirectory = directories.OfType<ExifSubIfdDirectory>().FirstOrDefault();
var dateTime = subIfdDirectory?.GetDescription(ExifDirectoryBase.TagDateTime);

该库还通过 Adob​​e XmpCore Java 库的 C# 端口支持 XMP 数据。

https://github.com/drewnoakes/xmp-core-dotnet

I've ported my long-time open-source Java library to .NET recently, and it supports XMP, Exif, ICC, JFIF and many more types of metadata across a range of image formats. It will definitely achieve what you're after.

https://github.com/drewnoakes/metadata-extractor-dotnet

var directories = ImageMetadataReader.ReadMetadata(imagePath);
var subIfdDirectory = directories.OfType<ExifSubIfdDirectory>().FirstOrDefault();
var dateTime = subIfdDirectory?.GetDescription(ExifDirectoryBase.TagDateTime);

This library also supports XMP data, via a C# port of Adobe's XmpCore library for Java.

https://github.com/drewnoakes/xmp-core-dotnet

飘过的浮云 2024-08-28 20:42:58

如果您在使用 XMP jn jpeg 时遇到困难,那么这很有效。这可不是无缘无故的残酷!

public class BrutalXmp
{
    public XmlDocument ExtractXmp(byte[] jpegBytes)
    {
        var asString = Encoding.UTF8.GetString(jpegBytes);
        var start = asString.IndexOf("<x:xmpmeta");
        var end = asString.IndexOf("</x:xmpmeta>") + 12;
        if (start == -1 || end == -1)
            return null;
        var justTheMeta = asString.Substring(start, end - start);
        var returnVal = new XmlDocument();
        returnVal.LoadXml(justTheMeta);
        return returnVal;
    }
}

If you're struggling with XMP jn jpeg, this works. It's not called brutal for nothing!

public class BrutalXmp
{
    public XmlDocument ExtractXmp(byte[] jpegBytes)
    {
        var asString = Encoding.UTF8.GetString(jpegBytes);
        var start = asString.IndexOf("<x:xmpmeta");
        var end = asString.IndexOf("</x:xmpmeta>") + 12;
        if (start == -1 || end == -1)
            return null;
        var justTheMeta = asString.Substring(start, end - start);
        var returnVal = new XmlDocument();
        returnVal.LoadXml(justTheMeta);
        return returnVal;
    }
}
留蓝 2024-08-28 20:42:58

我认为您正在做的事情是一个很好的解决方案,因为 System.DateTaken 处理程序会自动应用 照片元数据策略,返回到其他命名空间以查找值是否存在。

I think what you are doing is a good solution because the System.DateTaken handler automatically apply Photo metadata policies of falling back to other namespaces to find if a value exist.

昨迟人 2024-08-28 20:42:58

如果您尝试访问这些属性:

在此处输入图像描述

您可以执行以下操作:

  1. 添加对 C:\Windows\System32\Shell32.dll 的引用。 VS 2022 自动创建互操作性来与 ActiveX 库交互。
  2. 我将以下代码添加到按钮单击事件中以演示获取所需的数据。

代码示例:

Shell32.Shell shell = new Shell32.Shell();
Shell32.Shell objShell = shell.Application;
Shell32.Folder folder = objShell.NameSpace(@"D:\TestFolder");
Shell32.FolderItem folderItem = folder.ParseName("TestMetadata.jpg");
for (int tagIndex = 0; tagIndex < 321; tagIndex++)
{
   // Pass null in the first parameter to get the tagName
   string tagName = folder.GetDetailsOf(null, tagIndex);

   if (!string.IsNullOrEmpty(tagName))
   {
      // Pass an instance of Shell32.FolderItem to get the tag value.
      string tagValue = folder.GetDetailsOf(folderItem, tagIndex);

      Console.WriteLine($"[{tagIndex}] {tagName} = {tagValue}");
   }
}

控制台将显示代表感兴趣值的字符串。我不确定为什么包含个位数月份和/或日期值的日期会显示一个?对于 0 数字。这些可以轻松替换,然后可以解析日期。以下是 Properties\Details 选项卡中显示的一些有趣的输出:

[3] Date modified = 9/3/2022 2:37 PM
[4] Date created = 9/3/2022 2:35 PM
[5] Date accessed = 9/3/2022 10:38 PM
[12] Date taken = ?1/?1/?2022 ??2:36 PM
[18] Tags = Metadata Tags
[21] Title = My Test Title
[22] Subject = Being and Nothingness
[24] Comments = Kilroy wuz here!
[25] Copyright = 2022
[136] Date acquired = ?1/?2/?2022 ??2:36 PM

据我所知,有多达 320 种不同的标记类型。

If you are trying to access these properties:

enter image description here

You can do the following:

  1. Add a reference to C:\Windows\System32\Shell32.dll. VS 2022 automatically creates an interop to interact with the ActiveX library.
  2. I added the following code to a button click event to demonstrate getting the data desired.

Code Sample:

Shell32.Shell shell = new Shell32.Shell();
Shell32.Shell objShell = shell.Application;
Shell32.Folder folder = objShell.NameSpace(@"D:\TestFolder");
Shell32.FolderItem folderItem = folder.ParseName("TestMetadata.jpg");
for (int tagIndex = 0; tagIndex < 321; tagIndex++)
{
   // Pass null in the first parameter to get the tagName
   string tagName = folder.GetDetailsOf(null, tagIndex);

   if (!string.IsNullOrEmpty(tagName))
   {
      // Pass an instance of Shell32.FolderItem to get the tag value.
      string tagValue = folder.GetDetailsOf(folderItem, tagIndex);

      Console.WriteLine(
quot;[{tagIndex}] {tagName} = {tagValue}");
   }
}

The console will display strings representing the values of interest. I'm not sure why, by dates containing single digit month and/or day values will display a ? for the 0 digit. These can easily be replaced and then the date can be parsed. Here is the output for some of the interesting ones displayed in the Properties\Details tab:

[3] Date modified = 9/3/2022 2:37 PM
[4] Date created = 9/3/2022 2:35 PM
[5] Date accessed = 9/3/2022 10:38 PM
[12] Date taken = ?1/?1/?2022 ??2:36 PM
[18] Tags = Metadata Tags
[21] Title = My Test Title
[22] Subject = Being and Nothingness
[24] Comments = Kilroy wuz here!
[25] Copyright = 2022
[136] Date acquired = ?1/?2/?2022 ??2:36 PM

As far as I am aware, there are as many as 320 different tag types.

萌逼全场 2024-08-28 20:42:58

我的 公司 开发了 .NET 工具包,包括 XMP 和 EXIF 解析器。

典型的过程是这样的:

XmpParser parser = new XmpParser();
System.Xml.XmlDocument xml = (System.Xml.XmlDocument)parser.ParseFromImage(stream, frameIndex);

对于 EXIF,你会这样做:

ExitParser parser = new ExifParser();
ExifCollection exif = parser.ParseFromImage(stream, frameIndex);

显然,对于 JPEG,frameIndex 将为 0。

My company makes a .NET toolkit that includes XMP and EXIF parsers.

The typical process is something like this:

XmpParser parser = new XmpParser();
System.Xml.XmlDocument xml = (System.Xml.XmlDocument)parser.ParseFromImage(stream, frameIndex);

for EXIF you would do this:

ExitParser parser = new ExifParser();
ExifCollection exif = parser.ParseFromImage(stream, frameIndex);

obviously, frameIndex would be 0 for JPEG.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文