【发布时间】:2020-01-27 19:25:16
【问题描述】:
在 Windows XP 中,“FileInfo.LastWriteTime”将返回照片的拍摄日期 - 无论文件在文件系统中移动了多少次。
在 Vista 中,它返回的是从相机复制照片的日期。
如何知道照片是在 Vista 中拍摄的?在 Windows 资源管理器中,此字段称为“拍摄日期”。
【问题讨论】:
标签: c#
在 Windows XP 中,“FileInfo.LastWriteTime”将返回照片的拍摄日期 - 无论文件在文件系统中移动了多少次。
在 Vista 中,它返回的是从相机复制照片的日期。
如何知道照片是在 Vista 中拍摄的?在 Windows 资源管理器中,此字段称为“拍摄日期”。
【问题讨论】:
标签: c#
这里尽可能快速和干净。通过使用 FileStream,您可以告诉 GDI+ 不要加载整个图像进行验证。它在我的机器上运行速度超过 10 倍。
//we init this once so that if the function is repeatedly called
//it isn't stressing the garbage man
private static Regex r = new Regex(":");
//retrieves the datetime WITHOUT loading the whole image
public static DateTime GetDateTakenFromImage(string path)
{
using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
using (Image myImage = Image.FromStream(fs, false, false))
{
PropertyItem propItem = myImage.GetPropertyItem(36867);
string dateTaken = r.Replace(Encoding.UTF8.GetString(propItem.Value), "-", 2);
return DateTime.Parse(dateTaken);
}
}
是的,正确的 id 是 36867,而不是 306。
下面的其他开源项目应注意这一点。在处理数千个文件时,这对性能造成了巨大的损失。
【讨论】:
Image myImage = Image.FromFile(@"C:\temp\IMG_0325.JPG");
PropertyItem propItem = myImage.GetPropertyItem(306);
DateTime dtaken;
//Convert date taken metadata to a DateTime object
string sdate = Encoding.UTF8.GetString(propItem.Value).Trim();
string secondhalf = sdate.Substring(sdate.IndexOf(" "), (sdate.Length - sdate.IndexOf(" ")));
string firsthalf = sdate.Substring(0, 10);
firsthalf = firsthalf.Replace(":", "-");
sdate = firsthalf + secondhalf;
dtaken = DateTime.Parse(sdate);
【讨论】:
自 2002 年以来,我维护了一个 simple open-source library,用于从图像/视频文件中提取元数据。
// Read all metadata from the image
var directories = ImageMetadataReader.ReadMetadata(stream);
// Find the so-called Exif "SubIFD" (which may be null)
var subIfdDirectory = directories.OfType<ExifSubIfdDirectory>().FirstOrDefault();
// Read the DateTime tag value
var dateTime = subIfdDirectory?.GetDateTime(ExifDirectoryBase.TagDateTimeOriginal);
在我的基准测试中,此代码的运行速度比 Image.GetPropertyItem 快 12 倍以上,比 WPF JpegBitmapDecoder/BitmapMetadata API 快约 17 倍。
库中提供了大量额外信息,例如相机设置(F-stop、ISO、快门速度、闪光模式、焦距……)、图像属性(尺寸、像素配置)和其他信息如 GPS 位置、关键字、版权信息等。
如果您只对元数据感兴趣,那么使用这个库非常快,因为它不会解码图像(即位图)。如果您有足够快的存储空间,您可以在几秒钟内扫描数千张图像。
ImageMetadataReader 可以识别多种文件类型(JPEG、PNG、GIF、BMP、TIFF、PCX、WebP、ICO 等)。如果您知道您正在处理 JPEG,并且您只需要 Exif 数据,那么您可以通过以下方式加快处理速度:
var directories = JpegMetadataReader.ReadMetadata(stream, new[] { new ExifReader() });
元数据提取器库可通过NuGet 和code's on GitHub 获得。感谢多年来改进库和提交测试图像的所有出色的贡献者。
【讨论】:
【讨论】:
在 Windows XP 中“FileInfo.LastWriteTime” 将返回图片的日期 采取 - 无论多少次 文件在 文件系统。
我非常怀疑 XP 是否真的这样做了。您用于将图像从相机复制到硬盘的工具更有可能将文件修改日期重置为图像的拍摄日期。
【讨论】:
您必须检查图片中的 EXIF 信息。我认为使用常规的 .Net 函数您不会知道照片的拍摄时间。
可能有点复杂...
【讨论】:
图像中会嵌入 EXIF 数据。如果您搜索 EXIF 和 C#,网络上有大量示例。
【讨论】:
//retrieves the datetime WITHOUT loading the whole image
public static DateTime GetDateTakenFromImage(string path)
{
using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
using (Image myImage = Image.FromStream(fs, false, false))
{
PropertyItem propItem = null;
try
{
propItem = myImage.GetPropertyItem(36867);
}
catch { }
if (propItem != null)
{
string dateTaken = r.Replace(Encoding.UTF8.GetString(propItem.Value), "-", 2);
return DateTime.Parse(dateTaken);
}
else
return new FileInfo(path).LastWriteTime;
}
}
【讨论】: