You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在C#中为PNG文件写入DateTimeOriginal标签的问题求助

ExifLibNet对PNG文件EXIF读写无效的问题分析

问题背景

我用MetadataExtractor NuGet包提取PNG和JPG的元数据完全正常,但它不支持EXIF标签写入。调研后选用ExifLibNet,发现该包对JPG文件的读写功能完全正常,但对PNG文件无效——既读不出已存在的DateTimeOriginal等EXIF标签,写入后也无法保存生效。

代码复现(MAUI .NET 7项目,需安装MetadataExtractor 2.7.2和ExifLibNet 2.1.4)

引用命名空间:

using ExifLibrary;
using MetadataExtractor;
using MetadataExtractor.Formats.Exif;

按钮点击事件代码:

private void OnCounterClicked(object sender, EventArgs e)
{
    //string aFile = @"C:\Users\Beb\Google Drive\Python\EXIF Cleanup\NEW\2019_10_05_173730_JCS.JPG";
    string aFile = @"C:\Users\Beb\Google Drive\Python\EXIF Cleanup\NEW\IMG-20230420-WA0001_TAGGED 15 04 2023 13 00 ANDROID.png";

    // =====================================================================
    // USING METADATAEXTRACTOR 2.7.2
    // PART I : 提取所有标签(正常工作)
    IEnumerable<MetadataExtractor.Directory> directories = ImageMetadataReader.ReadMetadata(aFile);
    foreach (var directory in directories)
        foreach (var tag in directory.Tags)
            Debug.WriteLine($"{directory.Name} - {tag.Name} = {tag.Description}");

    // PART II : 读取DateTimeOriginal标签(正常工作)
    IEnumerable<Directory> dir = ImageMetadataReader.ReadMetadata(aFile);
    var subIfDir = dir.OfType<ExifSubIfdDirectory>().FirstOrDefault();
    var dtOriginal = subIfDir?.GetDescription(ExifDirectoryBase.TagDateTimeOriginal);
    Debug.WriteLine($"Using MetadataExtractor, Date Time Original is : {dtOriginal.ToString()}"); // 测试文件输出:2023:04:15 13:00:00

    // =====================================================================
    // USING EXIFLIBNET 2.1.4
    var img = ImageFile.FromFile(aFile);

    // PART I : 提取所有标签(JPG正常,PNG读不出2023:04:15的日期标签)
    foreach (ExifTag aTag in (ExifTag[])Enum.GetValues(typeof(ExifTag)))
    {
        ExifProperty exifTag = img.Properties.Get(aTag);
        if (exifTag != null)
            Debug.WriteLine($"{aTag.ToString()} ==> {exifTag.Value.ToString()}");
    }

    // PART II : 读取特定日期标签(JPG正常,PNG全部返回null)
    ExifProperty tagDT = img.Properties.Get(ExifTag.DateTime);
    ExifProperty tagDTO = img.Properties.Get(ExifTag.DateTimeOriginal);
    ExifProperty tagDTD = img.Properties.Get(ExifTag.DateTimeDigitized);
    ExifProperty tagPNGCT = img.Properties.Get(ExifTag.PNGCreationTime);

    Debug.WriteLine($"DateTime ==> {(tagDT == null ? "null" : tagDT.Value.ToString())}");
    Debug.WriteLine($"DateTime Original ==> {(tagDTO == null ? "null" : tagDTO.Value.ToString())}");
    Debug.WriteLine($"DateTime Digitzed ==> {(tagDTD == null ? "null" : tagDTD.Value.ToString())}");
    Debug.WriteLine($"DateTime PNG Creation Time  ==> {(tagPNGCT == null ? "null" : tagPNGCT.Value.ToString())}");

    // PART III : 尝试写入新日期标签(JPG正常,PNG无效果)
    DateTime newDate = new DateTime(2023, 04, 10, 13,37, 00);
    img.Properties.Set(ExifTag.DateTime, newDate);
    img.Properties.Set(ExifTag.DateTimeDigitized, newDate);
    img.Properties.Set(ExifTag.DateTimeOriginal, newDate);  // ExifLibNet中该标签值为236867
    img.Properties.Set(ExifTag.PNGCreationTime, newDate);
    img.Save(aFile);

    // PART IV : 重新读取验证(JPG显示新值,PNG仍无标签)
    img = ImageFile.FromFile(aFile);
    foreach (ExifTag aTag in (ExifTag[])Enum.GetValues(typeof(ExifTag)))
    {
        ExifProperty exifTag = img.Properties.Get(aTag);
        if (exifTag != null)
            Debug.WriteLine($"{aTag.ToString()} ==> {exifTag.Value.ToString()}");
    }
}

标签ID差异发现

根据标准定义,DateTimeOriginal标签的ID是0x9003(十进制36867)。对比两个库的源代码:

  • MetadataExtractor中TagDateTimeOriginal = 0x9003(直接使用标准标签ID)
  • ExifLibNet中DateTimeOriginal = 236867(比标准值多了前缀"2")

问题原因解析

  1. PNG与JPG的EXIF存储结构差异:
    JPG的EXIF数据直接嵌入在APP1块中,遵循标准的Exif IFD结构,ExifLibNet能正确解析。而PNG的EXIF数据通常存储在iTXt块的"EXIF"字段中,不属于标准JPG的APP块结构,ExifLibNet的PNG解析逻辑可能未处理这种存储方式,导致无法读取或写入。

  2. ExifLibNet的标签枚举设计:
    ExifLibNet的ExifTag枚举值并非单纯的标签ID,而是标签ID + IFD类型的位组合(比如高16位代表IFD类型,低16位是标签ID)。这种设计在JPG的标准IFD结构中能正确匹配,但PNG的EXIF数据不在预期的IFD路径中,导致标签匹配失败,读不出数据,写入时也无法正确关联到PNG的Exif块。

  3. ExifLibNet对PNG的支持不完善:
    该库的核心功能偏向JPG的Exif处理,对PNG的Exif读写逻辑存在缺失——可能未实现PNG的Exif块读取,或写入时未将Exif数据正确存入PNG的iTXt/tEXt块,导致修改后的数据无法持久化。

解决方案建议

  • 更换更完善的图像库:使用SixLabors.ImageSharp,它对PNG和JPG的Exif读写都有良好支持,API设计更直观,且持续维护。示例代码(写入DateTimeOriginal):
    using SixLabors.ImageSharp;
    using SixLabors.ImageSharp.Formats.Png;
    using SixLabors.ImageSharp.Metadata.Profiles.Exif;
    
    using (var image = Image.Load(aFile))
    {
        var exifProfile = image.Metadata.ExifProfile ?? new ExifProfile();
        exifProfile.SetValue(ExifTag.DateTimeOriginal, newDate);
        image.Metadata.ExifProfile = exifProfile;
        image.Save(aFile, new PngEncoder());
    }
    
  • 手动处理PNG的Exif块:如果坚持使用现有库,可以手动解析PNG的iTXt块,提取Exif数据进行修改后再写入,但实现复杂度较高。
  • 提交Issue或修复ExifLibNet:如果有开发能力,可以查看ExifLibNet的PNG处理源码,补充Exif块的读写逻辑并提交PR。

内容的提问来源于stack exchange,提问作者Beb

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 15:24:52