如何使用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
相关产品推荐
相关产品推荐

