|
|
|
|
@ -0,0 +1,194 @@
|
|
|
|
|
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";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|