LASAPlatform/Infrastructure/Helpers/ExifReader.cs

195 lines
7.0 KiB
C#
Raw Normal View History

2025-09-11 09:00:01 +08:00
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Infrastructure.Helpers
{
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Text;
public class ExifReader
{
// Exif 标签ID与名称的映射字典部分常见标签
private static readonly Dictionary<int, string> ExifTags = new Dictionary<int, string>
{
{ 0x010E, "ImageDescription" },
{ 0x010F, "Make" },
{ 0x0110, "Model" },
{ 0x0112, "Orientation" },
{ 0x011A, "XResolution" },
{ 0x011B, "YResolution" },
{ 0x0128, "ResolutionUnit" },
{ 0x0131, "Software" },
{ 0x0132, "DateTime" },
{ 0x0213, "YCbCrPositioning" },
{ 0x8769, "ExifIFD" },
{ 0x829A, "ExposureTime" },
{ 0x829D, "FNumber" },
{ 0x8822, "ExposureProgram" },
{ 0x8827, "ISOSpeedRatings" },
{ 0x9000, "ExifVersion" },
{ 0x9003, "DateTimeOriginal" },
{ 0x9004, "DateTimeDigitized" },
{ 0x9101, "ComponentsConfiguration" },
{ 0x9201, "ShutterSpeedValue" },
{ 0x9202, "ApertureValue" },
{ 0x9203, "BrightnessValue" },
{ 0x9204, "ExposureBiasValue" },
{ 0x9205, "MaxApertureValue" },
{ 0x9206, "SubjectDistance" },
{ 0x9207, "MeteringMode" },
{ 0x9208, "LightSource" },
{ 0x9209, "Flash" },
{ 0x920A, "FocalLength" },
{ 0x927C, "MakerNote" },
{ 0x9286, "UserComment" },
{ 0x9290, "SubsecTime" },
{ 0x9291, "SubsecTimeOriginal" },
{ 0x9292, "SubsecTimeDigitized" },
{ 0xA000, "FlashpixVersion" },
{ 0xA001, "ColorSpace" },
{ 0xA002, "PixelXDimension" },
{ 0xA003, "PixelYDimension" },
{ 0xA004, "RelatedSoundFile" },
{ 0xA005, "InteroperabilityIFD" },
{ 0xA20B, "FlashEnergy" },
{ 0xA20C, "SpatialFrequencyResponse" },
{ 0xA20E, "FocalPlaneXResolution" },
{ 0xA20F, "FocalPlaneYResolution" },
{ 0xA210, "FocalPlaneResolutionUnit" },
{ 0xA214, "SubjectLocation" },
{ 0xA215, "ExposureIndex" },
{ 0xA217, "SensingMethod" },
{ 0xA300, "FileSource" },
{ 0xA301, "SceneType" },
{ 0xA302, "CFAPattern" },
{ 0xA401, "CustomRendered" },
{ 0xA402, "ExposureMode" },
{ 0xA403, "WhiteBalance" },
{ 0xA404, "DigitalZoomRatio" },
{ 0xA405, "FocalLengthIn35mmFilm" },
{ 0xA406, "SceneCaptureType" },
{ 0xA407, "GainControl" },
{ 0xA408, "Contrast" },
{ 0xA409, "Saturation" },
{ 0xA40A, "Sharpness" },
{ 0xA40B, "DeviceSettingDescription" },
{ 0xA40C, "SubjectDistanceRange" },
{ 0xA420, "ImageUniqueID" },
{ 0xA431, "BodySerialNumber" },
{ 0xA432, "LensSpecification" },
{ 0xA433, "LensMake" },
{ 0xA434, "LensModel" },
{ 0xA435, "LensSerialNumber" },
{ 0x8298, "Copyright" }, // 这是你特别关心的 Copyright 字段
{ 0x013B, "Artist" },
{ 0x9C9B, "WindowsTitle" },
{ 0x9C9C, "WindowsComment" },
{ 0x9C9D, "WindowsAuthor" },
{ 0x9C9E, "WindowsKeywords" },
{ 0x9C9F, "WindowsSubject" }
};
public static Dictionary<string, string> GetAllExifData(Stream imageStream)
{
var exifData = new Dictionary<string, string>();
using (Image image = Image.FromStream(imageStream))
{
foreach (PropertyItem propItem in image.PropertyItems)
{
string tagName = ExifTags.ContainsKey(propItem.Id) ?
ExifTags[propItem.Id] : $"Unknown (0x{propItem.Id:X4})";
string value = InterpretExifValue(propItem);
exifData[tagName] = value;
}
}
return exifData;
}
private static string InterpretExifValue(PropertyItem propItem)
{
try
{
switch (propItem.Type)
{
case 1: // Byte array
return $"Byte[{propItem.Len}]";
case 2: // ASCII string
return Encoding.ASCII.GetString(propItem.Value).TrimEnd('\0');
case 3: // Unsigned short (16-bit)
if (propItem.Len == 2)
return BitConverter.ToUInt16(propItem.Value, 0).ToString();
break;
case 4: // Unsigned long (32-bit)
if (propItem.Len == 4)
return BitConverter.ToUInt32(propItem.Value, 0).ToString();
break;
case 5: // Unsigned rational (two 32-bit values: numerator/denominator)
if (propItem.Len == 8)
{
uint numerator = BitConverter.ToUInt32(propItem.Value, 0);
uint denominator = BitConverter.ToUInt32(propItem.Value, 4);
return denominator != 0 ? $"{numerator}/{denominator}" : "Invalid rational";
}
break;
case 7: // Undefined
return $"Undefined[{propItem.Len}]";
case 9: // Signed long (32-bit)
if (propItem.Len == 4)
return BitConverter.ToInt32(propItem.Value, 0).ToString();
break;
case 10: // Signed rational (two 32-bit values: numerator/denominator)
if (propItem.Len == 8)
{
int numerator = BitConverter.ToInt32(propItem.Value, 0);
int denominator = BitConverter.ToInt32(propItem.Value, 4);
return denominator != 0 ? $"{numerator}/{denominator}" : "Invalid rational";
}
break;
}
return $"Type {propItem.Type}[{propItem.Len}]";
}
catch (Exception ex)
{
return $"Error reading value: {ex.Message}";
}
}
// 专门获取 Copyright 信息的方法
public static string GetCopyright(Stream imageStream)
{
using (Image image = Image.FromStream(imageStream))
{
try
{
// 0x8298 是 Copyright 的 Exif tag ID
PropertyItem copyrightProp = image.GetPropertyItem(0x8298);
return InterpretExifValue(copyrightProp);
}
catch (ArgumentException)
{
// 如果没有找到 Copyright 属性
return "No copyright information";
}
}
}
}
}