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

如何使用C#读写JPEG图片中的相机序列号?

C#读写JPEG相机序列号的解决方案

问题描述

我尝试用C#给JPEG文件写入相机序列号,原以为直接设置对应EXIF头值即可,但使用System.Drawing.Image.FromFile()加载图片时,image.PropertyIdList里没有相机序列号对应的EXIF ID。在Windows资源管理器的属性-详细信息面板里看不到该字段,手动设置为“hello”并保存后,再次用C#加载图片,PropertyIdList依然没有新增对应ID。请问能否用C#代码实现相机序列号的读写?

附上测试代码:

static void Main(string[] args)
{
    using (var image = System.Drawing.Image.FromFile(@"c:\temp\example.jpeg"))
    {
        foreach (var propertyId in image.PropertyIdList)
        {
            Console.WriteLine($"{propertyId:x}");
            /*
10e     image description
10f     camera make
110     camera model
131     software name
8298    copyright
9003    original date
9004    digitized date
9286    comment
5091    ChrominanceTable
5090    LuminanceTable
             */
        }
    }
}

(注:前8个属性为保存图片时写入)


解决方案

可以实现读写,核心问题是System.Drawing.Image的PropertyIdList仅枚举图片中已存在的标签,而相机序列号对应的EXIF标签(ID为0xA431(十六进制))默认不会被主动识别,需手动处理。

方法一:System.Drawing原生实现

1. 写入相机序列号

手动创建PropertyItem对象指定目标标签ID,将序列号转为符合格式的字节数组后赋值,保存时需确保保留EXIF信息:

using System.Drawing;
using System.Drawing.Imaging;
using System.Text;

static void WriteCameraSerialNumber(string imagePath, string serialNumber)
{
    using (var image = Image.FromFile(imagePath))
    {
        // 从现有属性复制模板,确保PropertyItem结构合法
        var propItem = image.PropertyItems.First();
        propItem.Id = 0xA431; // 相机序列号对应的EXIF ID
        propItem.Type = 2; // 字符串类型(ASCII编码)
        propItem.Value = Encoding.ASCII.GetBytes(serialNumber + "\0"); // 需以null结尾
        propItem.Len = propItem.Value.Length;

        // 添加或替换属性
        image.SetPropertyItem(propItem);

        // 保存图片并保留EXIF
        var jpegEncoder = ImageCodecInfo.GetImageEncoders().First(e => e.FormatID == ImageFormat.Jpeg.Guid);
        var encoderParams = new EncoderParameters(1);
        encoderParams.Param[0] = new EncoderParameter(Encoder.Quality, 100L); // 维持原画质
        image.Save(@"c:\temp\output.jpeg", jpegEncoder, encoderParams);
    }
}

2. 读取相机序列号

不依赖PropertyIdList,直接尝试获取ID为0xA431的属性:

static string ReadCameraSerialNumber(string imagePath)
{
    using (var image = Image.FromFile(imagePath))
    {
        try
        {
            var propItem = image.GetPropertyItem(0xA431);
            return Encoding.ASCII.GetString(propItem.Value).TrimEnd('\0');
        }
        catch (ArgumentException)
        {
            // 图片无该标签时返回null
            return null;
        }
    }
}

方法二:第三方库实现(推荐)

如果原生API使用繁琐,可使用跨平台的EXIF处理库ImageSharp,支持.NET 6+:

安装依赖包

Install-Package SixLabors.ImageSharp
Install-Package SixLabors.ImageSharp.Formats.Jpeg

读写示例

using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Metadata.Profiles.Exif;

// 写入相机序列号
using (var image = Image.Load(@"c:\temp\example.jpeg"))
{
    image.Metadata.ExifProfile.SetValue(ExifTag.CameraSerialNumber, "hello");
    image.Save(@"c:\temp\output.jpeg", new JpegEncoder());
}

// 读取相机序列号
using (var image = Image.Load(@"c:\temp\output.jpeg"))
{
    var serialNumber = image.Metadata.ExifProfile.GetValue(ExifTag.CameraSerialNumber);
    Console.WriteLine(serialNumber);
}

注意事项

  • System.Drawing.Common在.NET 6+的非Windows平台已标记为过时,跨平台场景优先使用ImageSharp等第三方库。
  • 保存图片时需指定编码器参数,避免EXIF信息丢失。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 00:25:01