Skip to content

Commit

Permalink
Read and write miliseconds in photo taken timestamp if present or if …
Browse files Browse the repository at this point in the history
…manually requested to fix the full problem of oozcitak#82
  • Loading branch information
RudyTheDev committed Aug 4, 2022
1 parent ac9b06e commit 4d87cf0
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 21 deletions.
56 changes: 48 additions & 8 deletions ExifLibrary/ExifBitConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ public static string ToString(byte[] data)
/// <summary>
/// Returns a DateTime object converted from the given byte array.
/// </summary>
public static DateTime ToDateTime(byte[] data, bool hastime)
public static DateTime ToDateTime(byte[] data, bool hastime, out bool preserveMilliseconds)
{
string str = ToAscii(data, Encoding.ASCII);
string[] parts = str.Split(new char[] { ':', ' ' });
Expand All @@ -68,37 +68,68 @@ public static DateTime ToDateTime(byte[] data, bool hastime)
if (hastime && parts.Length == 6)
{
// yyyy:MM:dd HH:mm:ss
// This is the expected format though some cameras
// This is the expected format through some cameras
// can use single digits. See Issue 21.
// Also, the seconds can be non-decimal (e.g. 2016:07:31 10:10:20.291), so use double to parse. See Issue 82
return new DateTime(int.Parse(parts[0]), int.Parse(parts[1]), int.Parse(parts[2]), int.Parse(parts[3]), int.Parse(parts[4]), (int)double.Parse(parts[5]));

if (parts[5].Contains("."))
{
string[] secondParts = parts[5].Split('.');

preserveMilliseconds = true;
return new DateTime(
int.Parse(parts[0]),
int.Parse(parts[1]),
int.Parse(parts[2]),
int.Parse(parts[3]),
int.Parse(parts[4]),
int.Parse(secondParts[0]),
int.Parse(secondParts[1])
);
}
else
{
preserveMilliseconds = false;
return new DateTime(
int.Parse(parts[0]),
int.Parse(parts[1]),
int.Parse(parts[2]),
int.Parse(parts[3]),
int.Parse(parts[4]),
int.Parse(parts[5])
);
}
}
else if (!hastime && parts.Length == 3)
{
// yyyy:MM:dd
preserveMilliseconds = false;
return new DateTime(int.Parse(parts[0]), int.Parse(parts[1]), int.Parse(parts[2]));
}
else
{
preserveMilliseconds = false;
return DateTime.MinValue;
}
}
catch (ArgumentOutOfRangeException)
{
preserveMilliseconds = false;
return DateTime.MinValue;
}
catch (ArgumentException)
{
preserveMilliseconds = false;
return DateTime.MinValue;
}
}

/// <summary>
/// Returns a DateTime object converted from the given byte array.
/// </summary>
public static DateTime ToDateTime(byte[] data)
public static DateTime ToDateTime(byte[] data, out bool preserveMilliseconds)
{
return ToDateTime(data, true);
return ToDateTime(data, true, out preserveMilliseconds);
}

/// <summary>
Expand Down Expand Up @@ -294,13 +325,22 @@ public static byte[] GetBytes(string value, Encoding encoding)
/// <summary>
/// Converts the given datetime to an array of bytes with a null terminator.
/// </summary>
public static byte[] GetBytes(DateTime value, bool hastime)
public static byte[] GetBytes(DateTime value, bool hastime, bool preserveMilliseconds)
{
string str = "";
string str;

if (hastime)
str = value.ToString("yyyy:MM:dd HH:mm:ss", System.Globalization.CultureInfo.InvariantCulture);
{
if (preserveMilliseconds)
str = value.ToString("yyyy:MM:dd HH:mm:ss.fff", System.Globalization.CultureInfo.InvariantCulture);
else
str = value.ToString("yyyy:MM:dd HH:mm:ss", System.Globalization.CultureInfo.InvariantCulture);
}
else
{
str = value.ToString("yyyy:MM:dd", System.Globalization.CultureInfo.InvariantCulture);
}

return GetBytes(str, true, Encoding.ASCII);
}

Expand Down
30 changes: 26 additions & 4 deletions ExifLibrary/ExifExtendedProperty.cs
Original file line number Diff line number Diff line change
Expand Up @@ -125,25 +125,38 @@ public override ExifInterOperability Interoperability
/// </summary>
public class ExifDateTime : ExifProperty
{
private readonly bool mPreserveMilliseconds;
protected DateTime mValue;
protected override object _Value { get { return Value; } set { Value = (DateTime)value; } }
public new DateTime Value { get { return mValue; } set { mValue = value; } }

static public implicit operator DateTime(ExifDateTime obj) { return obj.mValue; }

public override string ToString() { return mValue.ToString("yyyy.MM.dd HH:mm:ss"); }
public override string ToString()
{
if (mPreserveMilliseconds)
return mValue.ToString("yyyy.MM.dd HH:mm:ss.fff");
else
return mValue.ToString("yyyy.MM.dd HH:mm:ss");
}

public ExifDateTime(ExifTag tag, DateTime value)
public ExifDateTime(ExifTag tag, DateTime value, bool preserveMilliseconds)
: base(tag)
{
mValue = value;
mPreserveMilliseconds = preserveMilliseconds;
}

public override ExifInterOperability Interoperability
{
get
{
return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), InterOpType.ASCII, (uint)20, ExifBitConverter.GetBytes(mValue, true));
return new ExifInterOperability(
ExifTagFactory.GetTagID(mTag),
InterOpType.ASCII,
mPreserveMilliseconds ? (uint)24 : (uint)20,
ExifBitConverter.GetBytes(mValue, true, mPreserveMilliseconds)
);
}
}
}
Expand Down Expand Up @@ -172,7 +185,16 @@ public override ExifInterOperability Interoperability
{
get
{
return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), InterOpType.ASCII, (uint)11, ExifBitConverter.GetBytes(mValue, false));
return new ExifInterOperability(
ExifTagFactory.GetTagID(mTag),
InterOpType.ASCII,
(uint)11,
ExifBitConverter.GetBytes(
mValue,
false,
false // does not matter because we don't have time part anyway
)
);
}
}
}
Expand Down
8 changes: 4 additions & 4 deletions ExifLibrary/ExifPropertyCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -159,9 +159,9 @@ public void Add(ExifTag key, object value)
/// </summary>
/// <param name="key">The tag to set.</param>
/// <param name="value">The value of tag.</param>
public void Add(ExifTag key, DateTime value)
public void Add(ExifTag key, DateTime value, bool preserveMilliseconds = false)
{
AddItem(new ExifDateTime(key, value));
AddItem(new ExifDateTime(key, value, preserveMilliseconds));
}
/// <summary>
/// Adds an <see cref="ExifLibrary.ExifProperty"/> with the specified key.
Expand Down Expand Up @@ -341,9 +341,9 @@ public void Set(ExifTag key, object value)
/// </summary>
/// <param name="key">The tag to set.</param>
/// <param name="value">The value of tag.</param>
public void Set(ExifTag key, DateTime value)
public void Set(ExifTag key, DateTime value, bool preserveMilliseconds = false)
{
SetItem(new ExifDateTime(key, value));
SetItem(new ExifDateTime(key, value, preserveMilliseconds));
}
/// <summary>
/// Sets an <see cref="ExifLibrary.ExifProperty"/> with the specified key.
Expand Down
10 changes: 5 additions & 5 deletions ExifLibrary/ExifPropertyFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public static ExifProperty Get(ushort tag, ushort type, uint count, byte[] value
else if (tag == 0x128) // ResolutionUnit
return new ExifEnumProperty<ResolutionUnit>(ExifTag.ResolutionUnit, (ResolutionUnit)conv.ToUInt16(value, 0));
else if (tag == 0x132) // DateTime
return new ExifDateTime(ExifTag.DateTime, ExifBitConverter.ToDateTime(value));
return new ExifDateTime(ExifTag.DateTime, ExifBitConverter.ToDateTime(value, out bool _), false);
else if (tag == 0x9c9b || tag == 0x9c9c || // Windows tags
tag == 0x9c9d || tag == 0x9c9e || tag == 0x9c9f)
return new WindowsByteString(etag, Encoding.Unicode.GetString(value).TrimEnd('\0'));
Expand Down Expand Up @@ -80,9 +80,9 @@ public static ExifProperty Get(ushort tag, ushort type, uint count, byte[] value
return new ExifEncodedString(ExifTag.UserComment, val, enc);
}
else if (tag == 0x9003) // DateTimeOriginal
return new ExifDateTime(ExifTag.DateTimeOriginal, ExifBitConverter.ToDateTime(value));
return new ExifDateTime(ExifTag.DateTimeOriginal, ExifBitConverter.ToDateTime(value, out bool preserveMilliseconds), preserveMilliseconds);
else if (tag == 0x9004) // DateTimeDigitized
return new ExifDateTime(ExifTag.DateTimeDigitized, ExifBitConverter.ToDateTime(value));
return new ExifDateTime(ExifTag.DateTimeDigitized, ExifBitConverter.ToDateTime(value, out bool preserveMilliseconds), preserveMilliseconds);
else if (tag == 0x8822) // ExposureProgram
return new ExifEnumProperty<ExposureProgram>(ExifTag.ExposureProgram, (ExposureProgram)conv.ToUInt16(value, 0));
else if (tag == 0x9207) // MeteringMode
Expand Down Expand Up @@ -170,7 +170,7 @@ public static ExifProperty Get(ushort tag, ushort type, uint count, byte[] value
else if (tag == 25) // GPSDestDistanceRef
return new ExifEnumProperty<GPSDistanceRef>(ExifTag.GPSDestDistanceRef, (GPSDistanceRef)value[0]);
else if (tag == 29) // GPSDateStamp
return new ExifDate(ExifTag.GPSDateStamp, ExifBitConverter.ToDateTime(value, false));
return new ExifDate(ExifTag.GPSDateStamp, ExifBitConverter.ToDateTime(value, false, out bool _));
else if (tag == 30) // GPSDifferential
return new ExifEnumProperty<GPSDifferential>(ExifTag.GPSDifferential, (GPSDifferential)conv.ToUInt16(value, 0));
}
Expand All @@ -196,7 +196,7 @@ public static ExifProperty Get(ushort tag, ushort type, uint count, byte[] value
else if (tag == 0x128) // ResolutionUnit
return new ExifEnumProperty<ResolutionUnit>(ExifTag.ThumbnailResolutionUnit, (ResolutionUnit)conv.ToUInt16(value, 0));
else if (tag == 0x132) // DateTime
return new ExifDateTime(ExifTag.ThumbnailDateTime, ExifBitConverter.ToDateTime(value));
return new ExifDateTime(ExifTag.ThumbnailDateTime, ExifBitConverter.ToDateTime(value, out bool _), false);
}

if (type == 1) // 1 = BYTE An 8-bit unsigned integer.
Expand Down

0 comments on commit 4d87cf0

Please sign in to comment.