我正在编写一个C#程序,它从JPEG文件中提取EXIF DateTimeOriginal字段,如果该属性在数据中,我需要将其解析为DateTime
值。我的代码是:
BitmapFrame src = decoder.Frames[ 0 ];
if ( src.Metadata != null ) {
BitmapMetadata metaData = (BitmapMetadata) src.Metadata;
if ( metaData.ContainsQuery( "/app1/{ushort=0}/{ushort=34665}/{ushort=36867}" ) ) {
object o = metaData.GetQuery( "/app1/{ushort=0}/{ushort=34665}/{ushort=36867}" );
if ( o != null && o is string ) {
string originalDate = Convert.ToString( o );
if ( originalDate != null ) {
if ( !DateTime.TryParseExact( originalDate.Trim(), "yyyy:MM:dd hh:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out createDate ) ) {
// Sets createDate to a default value if the date doesn't parse.
}
}
}
}
}
但是,对TryParseExact
的调用中的格式字符串不起作用,因为代码执行的是用注释替换的代码。
编写格式字符串的正确方法是什么? DateTimeOriginal
属性中的值格式为YYYY:MMY:DD HH:MM:SS。它是YYYY,MM和DD说明符之间的冒号,它们正在杀死我。他们为什么要用冒号?
修改
我尝试将格式说明符字符串更改为“yyyy \:MM \ dd hh \:mm:\ ss”,但这也不起作用。
答案 0 :(得分:11)
这是一个来自旧程序的代码片段,我躺在那里做了类似于此的事情:
string dateTakenText;
using (Image photo = Image.FromFile(file.Name))
{
PropertyItem pi = photo.GetPropertyItem(Program.propertyTagExifDTOrig_);
ASCIIEncoding enc = new ASCIIEncoding();
dateTakenText = enc.GetString(pi.Value, 0, pi.Len - 1);
}
if (string.IsNullOrEmpty(dateTakenText))
{
continue;
}
DateTime dateTaken;
if (!DateTime.TryParseExact(dateTakenText, "yyyy:MM:dd HH:mm:ss",
CultureInfo.CurrentCulture, DateTimeStyles.None, out dateTaken))
{
continue;
}
此代码段位于foreach
循环内,该循环说明了continue
关键字的使用。
这是我在2002年或2003年的某个时间编写的程序中的代码,从那时起我就一直在使用它。它非常可靠。
答案 1 :(得分:2)
这个link描述了一种解析字符串各个部分的方法,而不是使用DateTime.Parse解析它:
/// <summary>
/// Returns the EXIF Image Data of the Date Taken.
/// </summary>
/// <param name="getImage">Image (If based on a file use Image.FromFile(f);)</param>
/// <returns>Date Taken or Null if Unavailable</returns>
public static DateTime? DateTaken(Image getImage)
{
int DateTakenValue = 0x9003; //36867;
if (!getImage.PropertyIdList.Contains(DateTakenValue))
return null;
string dateTakenTag = System.Text.Encoding.ASCII.GetString(getImage.GetPropertyItem(DateTakenValue).Value);
string[] parts = dateTakenTag.Split(':', ' ');
int year = int.Parse(parts[0]);
int month = int.Parse(parts[1]);
int day = int.Parse(parts[2]);
int hour = int.Parse(parts[3]);
int minute = int.Parse(parts[4]);
int second = int.Parse(parts[5]);
return new DateTime(year, month, day, hour, minute, second);
}
答案 2 :(得分:2)
感谢Mark Seemann&amp;马库斯,我终于搞清楚了。 EXIF数据的时间是24小时/军事时间。 &#34; hh&#34;字符串中的格式说明符是使用AM / PM的12小时时间。我通过的时间是14:14,或者下午2:14。在12小时的时间内,&#34; 14&#34;是一个无效的时间。
所以正确的格式说明符是&#34; yyyy:MM:dd HH:mm:ss&#34;。
答案 3 :(得分:2)
我最近重写了我在其他答案中提到的应用程序。这一次,我用F#写的。做这项工作的相关部分是:
[<Literal>]
let private exifDateTaken = 0x0132
[<Literal>]
let private exifDateTimeOriginal = 0x9003
let private tryParseDate s =
let res =
DateTime.TryParseExact(
s,
"yyyy:MM:dd HH:mm:ss",
CultureInfo.InvariantCulture,
DateTimeStyles.None)
match res with
| true, dt -> Some dt
| _ -> None
let extractDateTaken (fi : FileInfo) =
let extractExif (img : Image) exif =
if img.PropertyIdList |> Array.contains exif
then
let pi = img.GetPropertyItem exif
Some (Encoding.ASCII.GetString(pi.Value, 0, pi.Len - 1))
else None
use photo = Image.FromFile fi.FullName
[ exifDateTimeOriginal; exifDateTaken ]
|> Seq.choose (extractExif photo)
|> Seq.tryHead
|> Option.bind tryParseDate