コード例 #1
0
        private static IConvertible GetConvertibleObject([NotNull] this Directory directory, int tagType)
        {
            var o = directory.GetObject(tagType);

            if (o == null)
            {
                return(null);
            }

            var convertible = o as IConvertible;

            if (convertible != null)
            {
                return(convertible);
            }

            var array = o as Array;

            if (array != null && array.Length == 1 && array.Rank == 1)
            {
                return(array.GetValue(0) as IConvertible);
            }

            return(null);
        }
コード例 #2
0
        public static bool TryGetRational([NotNull] this Directory directory, int tagType, out Rational value)
        {
            var o = directory.GetObject(tagType);

            if (o == null)
            {
                value = default(Rational);
                return(false);
            }

            if (o is Rational r)
            {
                value = r;
                return(true);
            }

            if (o is int i)
            {
                value = new Rational(i, 1);
                return(true);
            }

            if (o is long l)
            {
                value = new Rational(l, 1);
                return(true);
            }

            // NOTE not doing conversions for real number types

            value = default(Rational);
            return(false);
        }
コード例 #3
0
        public static bool TryGetRational(this Directory directory, int tagType, out Rational value)
        {
            var o = directory.GetObject(tagType);

            if (o == null)
            {
                value = default(Rational);
                return(false);
            }

            if (o is Rational)
            {
                value = (Rational)o;
                return(true);
            }

            if (o is int?)
            {
                value = new Rational((int)o, 1);
                return(true);
            }

            if (o is long?)
            {
                value = new Rational((long)o, 1);
                return(true);
            }

            // NOTE not doing conversions for real number types

            value = default(Rational);
            return(false);
        }
コード例 #4
0
        public static StringValue GetStringValue(this Directory directory, int tagType)
        {
            var o = directory.GetObject(tagType);

            if (o is StringValue value)
            {
                return(value);
            }

            return(default);
コード例 #5
0
        public static StringValue GetStringValue([NotNull] this Directory directory, int tagType)
        {
            var o = directory.GetObject(tagType);

            if (o is StringValue)
            {
                return((StringValue)o);
            }

            return(default(StringValue));
        }
コード例 #6
0
        private static T ThrowValueNotPossible <T>([NotNull] Directory directory, int tagType)
        {
            var o = directory.GetObject(tagType);

            if (o == null)
            {
                throw new MetadataException($"No value exists for tag {directory.GetTagName(tagType)}.");
            }

            throw new MetadataException($"Tag {tagType} cannot be converted to {typeof(T).Name}.  It is of type {o.GetType()} with value: {o}");
        }
コード例 #7
0
        private void AddQuickTimeMetaCreationDate(MetadataExtractor.Directory quickTimeMeta, Photo photo)
        {
            var tag = quickTimeMeta.Tags.SingleOrDefault(t => t.Name == QuickTimeMetaDataCreationDateTag);

            if (tag != null)
            {
                var tagValue = (StringValue)quickTimeMeta.GetObject(tag.Type);
                if (DateTime.TryParse(tagValue.ToString(), out DateTime creationDate))
                {
                    photo.TakenDate = creationDate;
                }
            }
        }
コード例 #8
0
        private static void AddQuickTimeMetaCreationDate(MetadataExtractor.Directory quickTimeMeta, Photo photo)
        {
            var tag = quickTimeMeta.Tags.SingleOrDefault(t => t.Name == "mdta.com.apple.quicktime.creationdate");

            if (tag != null)
            {
                var tagValue = quickTimeMeta.GetObject(tag.Type) as QuickTimeMetadataValue;
                if (DateTime.TryParse(tagValue.Value, out DateTime creationDate))
                {
                    photo.TakenDate = creationDate;
                }
            }
        }
コード例 #9
0
        public static bool TryGetDateTime([NotNull] this Directory directory, int tagType /*, [CanBeNull] TimeZoneInfo timeZone = null*/, out DateTime dateTime)
        {
            var o = directory.GetObject(tagType);

            if (o == null)
            {
                dateTime = default(DateTime);
                return(false);
            }

            if (o is DateTime)
            {
                dateTime = (DateTime)o;
                return(true);
            }

            var s = o as string;

            if (o is StringValue)
            {
                s = ((StringValue)o).ToString();
            }

            if (s != null)
            {
                if (DateTime.TryParseExact(s, _datePatterns, null, DateTimeStyles.AllowWhiteSpaces, out dateTime))
                {
                    return(true);
                }

                dateTime = default(DateTime);
                return(false);
            }

            var convertible = o as IConvertible;

            if (convertible != null)
            {
                try
                {
                    dateTime = convertible.ToDateTime(null);
                    return(true);
                }
                catch (FormatException)
                { }
            }

            dateTime = default(DateTime);
            return(false);
        }
コード例 #10
0
        public static bool TryGetDateTime(this Directory directory, int tagType /*, TimeZoneInfo? timeZone = null*/, out DateTime dateTime)
        {
            var o = directory.GetObject(tagType);

            if (o == null)
            {
                dateTime = default;
                return(false);
            }

            if (o is DateTime dt)
            {
                dateTime = dt;
                return(true);
            }

            var s = o as string;

            if (o is StringValue sv)
            {
                s = sv.ToString();
            }

            if (s != null)
            {
                if (DateTime.TryParseExact(s, _datePatterns, null, DateTimeStyles.AllowWhiteSpaces | DateTimeStyles.AdjustToUniversal, out dateTime))
                {
                    return(true);
                }

                dateTime = default;
                return(false);
            }

            if (o is IConvertible convertible)
            {
                try
                {
                    dateTime = convertible.ToDateTime(null);
                    return(true);
                }
                catch (FormatException)
                { }
            }

            dateTime = default;
            return(false);
        }
コード例 #11
0
        /// <summary>Attempts to return the specified tag's value as a DateTime.</summary>
        /// <remarks>If the underlying value is a <see cref="string"/>, then attempts will be made to parse it.</remarks>
        /// <returns><c>true</c> if a DateTime was returned, otherwise <c>false</c>.</returns>
        public static bool TryGetDateTime(this Directory directory, int tagType /*, [CanBeNull] TimeZoneInfo timeZone = null*/, out DateTime dateTime)
        {
            var o = directory.GetObject(tagType);

            if (o == null)
            {
                dateTime = default(DateTime);
                return(false);
            }

            if (o is DateTime)
            {
                dateTime = (DateTime)o;
                return(true);
            }

            var s = o as string;

            if (s == null)
            {
                dateTime = default(DateTime);
                return(false);
            }

            // This seems to cover all known Exif date strings
            // Note that "    :  :     :  :  " is a valid date string according to the Exif spec (which means 'unknown date'): http://www.awaresystems.be/imaging/tiff/tifftags/privateifd/exif/datetimeoriginal.html
            var datePatterns = new[] { "yyyy:MM:dd HH:mm:ss", "yyyy:MM:dd HH:mm", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm" };

            foreach (var datePattern in datePatterns)
            {
                if (DateTime.TryParseExact(s, datePattern, null, DateTimeStyles.AllowWhiteSpaces, out dateTime))
                {
                    return(true);
                }
            }

            if (o is IConvertible)
            {
                dateTime = ((IConvertible)o).ToDateTime(null);
                return(true);
            }

            dateTime = default(DateTime);
            return(false);
        }
コード例 #12
0
        public static StringValue[] GetStringValueArray([NotNull] this Directory directory, int tagType)
        {
            var o = directory.GetObject(tagType);

            if (o == null)
            {
                return(null);
            }
            if (o is StringValue[] stringValues)
            {
                return(stringValues);
            }
            if (o is StringValue sv)
            {
                return new [] { sv }
            }
            ;

            return(null);
        }
コード例 #13
0
        public static string GetString([NotNull] this Directory directory, int tagType)
        {
            var o = directory.GetObject(tagType);

            if (o == null)
            {
                return(null);
            }

            if (o is Rational r)
            {
                return(r.ToSimpleString());
            }

            if (o is DateTime dt)
            {
                return(dt.ToString(
                           dt.Kind != DateTimeKind.Unspecified
                        ? "ddd MMM dd HH:mm:ss zzz yyyy"
                        : "ddd MMM dd HH:mm:ss yyyy"));
            }

            if (o is bool b)
            {
                return(b ? "true" : "false");
            }

            // handle arrays of objects and primitives
            if (o is Array array)
            {
                var componentType = array.GetType().GetElementType();
                var str           = new StringBuilder();

                if (componentType == typeof(float))
                {
                    var vals = (float[])array;
                    for (var i = 0; i < vals.Length; i++)
                    {
                        if (i != 0)
                        {
                            str.Append(' ');
                        }
                        str.AppendFormat("{0:0.###}", vals[i]);
                    }
                }
                else if (componentType == typeof(double))
                {
                    var vals = (double[])array;
                    for (var i = 0; i < vals.Length; i++)
                    {
                        if (i != 0)
                        {
                            str.Append(' ');
                        }
                        str.AppendFormat("{0:0.###}", vals[i]);
                    }
                }
                else if (componentType == typeof(int))
                {
                    var vals = (int[])array;
                    for (var i = 0; i < vals.Length; i++)
                    {
                        if (i != 0)
                        {
                            str.Append(' ');
                        }
                        str.Append(vals[i]);
                    }
                }
                else if (componentType == typeof(uint))
                {
                    var vals = (uint[])array;
                    for (var i = 0; i < vals.Length; i++)
                    {
                        if (i != 0)
                        {
                            str.Append(' ');
                        }
                        str.Append(vals[i]);
                    }
                }
                else if (componentType == typeof(short))
                {
                    var vals = (short[])array;
                    for (var i = 0; i < vals.Length; i++)
                    {
                        if (i != 0)
                        {
                            str.Append(' ');
                        }
                        str.Append(vals[i]);
                    }
                }
                else if (componentType == typeof(ushort))
                {
                    var vals = (ushort[])array;
                    for (var i = 0; i < vals.Length; i++)
                    {
                        if (i != 0)
                        {
                            str.Append(' ');
                        }
                        str.Append(vals[i]);
                    }
                }
                else if (componentType == typeof(byte))
                {
                    var vals = (byte[])array;
                    for (var i = 0; i < vals.Length; i++)
                    {
                        if (i != 0)
                        {
                            str.Append(' ');
                        }
                        str.Append(vals[i]);
                    }
                }
                else if (componentType == typeof(sbyte))
                {
                    var vals = (sbyte[])array;
                    for (var i = 0; i < vals.Length; i++)
                    {
                        if (i != 0)
                        {
                            str.Append(' ');
                        }
                        str.Append(vals[i]);
                    }
                }
                else if (componentType == typeof(Rational))
                {
                    var vals = (Rational[])array;
                    for (var i = 0; i < vals.Length; i++)
                    {
                        if (i != 0)
                        {
                            str.Append(' ');
                        }
                        str.Append(vals[i]);
                    }
                }
                else if (componentType == typeof(string))
                {
                    var vals = (string[])array;
                    for (var i = 0; i < vals.Length; i++)
                    {
                        if (i != 0)
                        {
                            str.Append(' ');
                        }
                        str.Append(vals[i]);
                    }
                }
                else if (componentType.IsByRef)
                {
                    var vals = (object[])array;
                    for (var i = 0; i < vals.Length; i++)
                    {
                        if (i != 0)
                        {
                            str.Append(' ');
                        }
                        str.Append(vals[i]);
                    }
                }
                else
                {
                    for (var i = 0; i < array.Length; i++)
                    {
                        if (i != 0)
                        {
                            str.Append(' ');
                        }
                        str.Append(array.GetValue(i));
                    }
                }

                return(str.ToString());
            }

            if (o is IEnumerable <string> strings)
            {
#if NET35
                var sb = new StringBuilder();
                foreach (var s in strings)
                {
                    if (sb.Length != 0)
                    {
                        sb.Append(' ');
                    }
                    sb.Append(s);
                }
                return(sb.ToString());
#else
                return(string.Join(" ", strings));
#endif
            }

            if (o is double d)
            {
                return(d.ToString("0.###"));
            }

            if (o is float f)
            {
                return(f.ToString("0.###"));
            }

            // Note that several cameras leave trailing spaces (Olympus, Nikon) but this library is intended to show
            // the actual data within the file.  It is not inconceivable that whitespace may be significant here, so we
            // do not trim.  Also, if support is added for writing data back to files, this may cause issues.
            // We leave trimming to the presentation layer.
            return(o.ToString());
        }
コード例 #14
0
 public static Rational[] GetRationalArray([NotNull] this Directory directory, int tagType)
 {
     return(directory.GetObject(tagType) as Rational[]);
 }
コード例 #15
0
        public static string?GetString(this Directory directory, int tagType)
        {
            var o = directory.GetObject(tagType);

            if (o == null)
            {
                return(null);
            }

            if (o is Rational r)
            {
                return(r.ToSimpleString());
            }

            if (o is DateTime dt)
            {
                return(dt.ToString(
                           dt.Kind != DateTimeKind.Unspecified
                        ? "ddd MMM dd HH:mm:ss zzz yyyy"
                        : "ddd MMM dd HH:mm:ss yyyy"));
            }

            if (o is bool b)
            {
                return(b ? "true" : "false");
            }

            // handle arrays of objects and primitives
            if (o is Array array)
            {
                var componentType = array.GetType().GetElementType();
                var str           = new StringBuilder();

                if (componentType == typeof(float))
                {
                    var vals = (float[])array;
                    for (var i = 0; i < vals.Length; i++)
                    {
                        if (i != 0)
                        {
                            str.Append(' ');
                        }
                        str.AppendFormat("{0:0.###}", vals[i]);
                    }
                }
                else if (componentType == typeof(double))
                {
                    var vals = (double[])array;
                    for (var i = 0; i < vals.Length; i++)
                    {
                        if (i != 0)
                        {
                            str.Append(' ');
                        }
                        str.AppendFormat("{0:0.###}", vals[i]);
                    }
                }
                else if (componentType == typeof(int))
                {
                    var vals = (int[])array;
                    for (var i = 0; i < vals.Length; i++)
                    {
                        if (i != 0)
                        {
                            str.Append(' ');
                        }
                        str.Append(vals[i]);
                    }
                }
                else if (componentType == typeof(uint))
                {
                    var vals = (uint[])array;
                    for (var i = 0; i < vals.Length; i++)
                    {
                        if (i != 0)
                        {
                            str.Append(' ');
                        }
                        str.Append(vals[i]);
                    }
                }
                else if (componentType == typeof(short))
                {
                    var vals = (short[])array;
                    for (var i = 0; i < vals.Length; i++)
                    {
                        if (i != 0)
                        {
                            str.Append(' ');
                        }
                        str.Append(vals[i]);
                    }
                }
                else if (componentType == typeof(ushort))
                {
                    var vals = (ushort[])array;
                    for (var i = 0; i < vals.Length; i++)
                    {
                        if (i != 0)
                        {
                            str.Append(' ');
                        }
                        str.Append(vals[i]);
                    }
                }
                else if (componentType == typeof(byte))
                {
                    var vals = (byte[])array;
                    for (var i = 0; i < vals.Length; i++)
                    {
                        if (i != 0)
                        {
                            str.Append(' ');
                        }
                        str.Append(vals[i]);
                    }
                }
                else if (componentType == typeof(sbyte))
                {
                    var vals = (sbyte[])array;
                    for (var i = 0; i < vals.Length; i++)
                    {
                        if (i != 0)
                        {
                            str.Append(' ');
                        }
                        str.Append(vals[i]);
                    }
                }
                else if (componentType == typeof(Rational))
                {
                    var vals = (Rational[])array;
                    for (var i = 0; i < vals.Length; i++)
                    {
                        if (i != 0)
                        {
                            str.Append(' ');
                        }
                        str.Append(vals[i]);
                    }
                }
                else if (componentType == typeof(string))
                {
                    var vals = (string[])array;
                    for (var i = 0; i < vals.Length; i++)
                    {
                        if (i != 0)
                        {
                            str.Append(' ');
                        }
                        str.Append(vals[i]);
                    }
                }
                else if (componentType is { IsByRef : true })
コード例 #16
0
        public static byte[] GetByteArray([NotNull] this Directory directory, int tagType)
        {
            var o = directory.GetObject(tagType);

            if (o == null)
            {
                return(null);
            }

            if (o is StringValue value)
            {
                return(value.Bytes);
            }

            byte[] bytes;

            if (o is Rational[] rationals)
            {
                bytes = new byte[rationals.Length];
                for (var i = 0; i < bytes.Length; i++)
                {
                    bytes[i] = rationals[i].ToByte();
                }
                return(bytes);
            }

            bytes = o as byte[];
            if (bytes != null)
            {
                return(bytes);
            }

            if (o is int[] ints)
            {
                bytes = new byte[ints.Length];
                for (var i = 0; i < ints.Length; i++)
                {
                    bytes[i] = unchecked ((byte)ints[i]);
                }
                return(bytes);
            }

            if (o is short[] shorts)
            {
                bytes = new byte[shorts.Length];
                for (var i = 0; i < shorts.Length; i++)
                {
                    bytes[i] = unchecked ((byte)shorts[i]);
                }
                return(bytes);
            }

            if (o is string str)
            {
                bytes = new byte[str.Length];
                for (var i = 0; i < str.Length; i++)
                {
                    bytes[i] = unchecked ((byte)str[i]);
                }
                return(bytes);
            }

            var nullableInt = o as int?;

            if (nullableInt != null)
            {
                return new[] { (byte)nullableInt.Value }
            }
            ;

            return(null);
        }
コード例 #17
0
        public static int[] GetInt32Array([NotNull] this Directory directory, int tagType)
        {
            var o = directory.GetObject(tagType);

            if (o == null)
            {
                return(null);
            }

            if (o is int[] ints)
            {
                return(ints);
            }

            if (o is Rational[] rationals)
            {
                ints = new int[rationals.Length];
                for (var i = 0; i < ints.Length; i++)
                {
                    ints[i] = rationals[i].ToInt32();
                }
                return(ints);
            }

            if (o is short[] shorts)
            {
                ints = new int[shorts.Length];
                for (var i = 0; i < shorts.Length; i++)
                {
                    ints[i] = shorts[i];
                }
                return(ints);
            }

            if (o is sbyte[] sbytes)
            {
                ints = new int[sbytes.Length];
                for (var i = 0; i < sbytes.Length; i++)
                {
                    ints[i] = sbytes[i];
                }
                return(ints);
            }

            if (o is byte[] bytes)
            {
                ints = new int[bytes.Length];
                for (var i = 0; i < bytes.Length; i++)
                {
                    ints[i] = bytes[i];
                }
                return(ints);
            }

            if (o is string str)
            {
                ints = new int[str.Length];
                for (var i = 0; i < str.Length; i++)
                {
                    ints[i] = str[i];
                }
                return(ints);
            }

            var nullableInt = o as int?;

            if (nullableInt != null)
            {
                return new[] { (int)o }
            }
            ;

            return(null);
        }
コード例 #18
0
        public static string[] GetStringArray([NotNull] this Directory directory, int tagType)
        {
            var o = directory.GetObject(tagType);

            if (o == null)
            {
                return(null);
            }

            if (o is string[] strings)
            {
                return(strings);
            }

            if (o is string s)
            {
                return new[] { s }
            }
            ;

            if (o is StringValue)
            {
                return new[] { o.ToString() }
            }
            ;

            if (o is StringValue[] stringValues)
            {
                var strs = new string[stringValues.Length];

                for (var i = 0; i < strs.Length; i++)
                {
                    strs[i] = stringValues[i].ToString();
                }
                return(strs);
            }

            if (o is int[] ints)
            {
                strings = new string[ints.Length];
                for (var i = 0; i < strings.Length; i++)
                {
                    strings[i] = ints[i].ToString();
                }
                return(strings);
            }

            if (o is byte[] bytes)
            {
                strings = new string[bytes.Length];
                for (var i = 0; i < strings.Length; i++)
                {
                    strings[i] = ((int)bytes[i]).ToString();
                }
                return(strings);
            }

            if (o is Rational[] rationals)
            {
                strings = new string[rationals.Length];
                for (var i = 0; i < strings.Length; i++)
                {
                    strings[i] = rationals[i].ToSimpleString(false);
                }
                return(strings);
            }

            return(null);
        }
コード例 #19
0
        public static string[] GetStringArray(this Directory directory, int tagType)
        {
            var o = directory.GetObject(tagType);

            if (o == null)
            {
                return(null);
            }

            var strings = o as string[];

            if (strings != null)
            {
                return(strings);
            }

            var s = o as string;

            if (s != null)
            {
                return new[] { s }
            }
            ;

            var ints = o as int[];

            if (ints != null)
            {
                strings = new string[ints.Length];

                for (var i = 0; i < strings.Length; i++)
                {
                    strings[i] = ints[i].ToString();
                }
                return(strings);
            }

            var bytes = o as byte[];

            if (bytes != null)
            {
                strings = new string[bytes.Length];
                for (var i = 0; i < strings.Length; i++)
                {
                    strings[i] = ((int)bytes[i]).ToString();
                }
                return(strings);
            }

            var rationals = o as Rational[];

            if (rationals != null)
            {
                strings = new string[rationals.Length];
                for (var i = 0; i < strings.Length; i++)
                {
                    strings[i] = rationals[i].ToSimpleString(false);
                }
                return(strings);
            }

            return(null);
        }
コード例 #20
0
        public static int[] GetInt32Array(this Directory directory, int tagType)
        {
            var o = directory.GetObject(tagType);

            if (o == null)
            {
                return(null);
            }

            var ints = o as int[];

            if (ints != null)
            {
                return(ints);
            }

            var rationals = o as Rational[];

            if (rationals != null)
            {
                ints = new int[rationals.Length];
                for (var i = 0; i < ints.Length; i++)
                {
                    ints[i] = rationals[i].ToInt32();
                }
                return(ints);
            }

            var shorts = o as short[];

            if (shorts != null)
            {
                ints = new int[shorts.Length];
                for (var i = 0; i < shorts.Length; i++)
                {
                    ints[i] = shorts[i];
                }
                return(ints);
            }

            if (o.GetType() == typeof(sbyte[]))
            {
                var bytes = (sbyte[])o;
                ints = new int[bytes.Length];
                for (var i = 0; i < bytes.Length; i++)
                {
                    ints[i] = bytes[i];
                }
                return(ints);
            }

            if (o.GetType() == typeof(byte[]))
            {
                var bytes = (byte[])o;
                ints = new int[bytes.Length];
                for (var i = 0; i < bytes.Length; i++)
                {
                    ints[i] = bytes[i];
                }
                return(ints);
            }

            var str = o as string;

            if (str != null)
            {
                ints = new int[str.Length];
                for (var i = 0; i < str.Length; i++)
                {
                    ints[i] = str[i];
                }
                return(ints);
            }

            var nullableInt = o as int?;

            if (nullableInt != null)
            {
                return new[] { (int)o }
            }
            ;

            return(null);
        }
コード例 #21
0
        public static byte[] GetByteArray(this Directory directory, int tagType)
        {
            var o = directory.GetObject(tagType);

            if (o == null)
            {
                return(null);
            }

            byte[] bytes;

            var rationals = o as Rational[];

            if (rationals != null)
            {
                bytes = new byte[rationals.Length];
                for (var i = 0; i < bytes.Length; i++)
                {
                    bytes[i] = rationals[i].ToByte();
                }
                return(bytes);
            }

            bytes = o as byte[];
            if (bytes != null)
            {
                return(bytes);
            }

            var ints = o as int[];

            if (ints != null)
            {
                bytes = new byte[ints.Length];
                for (var i = 0; i < ints.Length; i++)
                {
                    bytes[i] = unchecked ((byte)ints[i]);
                }
                return(bytes);
            }

            var shorts = o as short[];

            if (shorts != null)
            {
                bytes = new byte[shorts.Length];
                for (var i = 0; i < shorts.Length; i++)
                {
                    bytes[i] = unchecked ((byte)shorts[i]);
                }
                return(bytes);
            }

            var str = o as string;

            if (str != null)
            {
                bytes = new byte[str.Length];
                for (var i = 0; i < str.Length; i++)
                {
                    bytes[i] = unchecked ((byte)str[i]);
                }
                return(bytes);
            }

            var nullableInt = o as int?;

            if (nullableInt != null)
            {
                return new[] { (byte)nullableInt.Value }
            }
            ;

            return(null);
        }
コード例 #22
0
        public static string GetString(this Directory directory, int tagType)
        {
            var o = directory.GetObject(tagType);

            if (o == null)
            {
                return(null);
            }

            if (o is Rational)
            {
                return(((Rational)o).ToSimpleString());
            }

            if (o is DateTime)
            {
                var dateTime = (DateTime)o;
                return(dateTime.ToString(
                           dateTime.Kind == DateTimeKind.Utc
                        ? "ddd MMM dd HH:mm:ss yyyy"
                        : "ddd MMM dd HH:mm:ss zzz yyyy"));
            }

            if (o is bool)
            {
                return((bool)o ? "true" : "false");
            }

            // handle arrays of objects and primitives
            var array = o as Array;

            if (array != null)
            {
                var componentType = array.GetType().GetElementType();
                var str           = new StringBuilder();

                if (componentType == typeof(float))
                {
                    var vals = (float[])array;
                    for (var i = 0; i < vals.Length; i++)
                    {
                        if (i != 0)
                        {
                            str.Append(' ');
                        }
                        str.AppendFormat("{0:0.###}", vals[i]);
                    }
                }
                else if (componentType == typeof(double))
                {
                    var vals = (double[])array;
                    for (var i = 0; i < vals.Length; i++)
                    {
                        if (i != 0)
                        {
                            str.Append(' ');
                        }
                        str.AppendFormat("{0:0.###}", vals[i]);
                    }
                }
                else if (componentType == typeof(int))
                {
                    var vals = (int[])array;
                    for (var i = 0; i < vals.Length; i++)
                    {
                        if (i != 0)
                        {
                            str.Append(' ');
                        }
                        str.Append(vals[i]);
                    }
                }
                else if (componentType == typeof(uint))
                {
                    var vals = (uint[])array;
                    for (var i = 0; i < vals.Length; i++)
                    {
                        if (i != 0)
                        {
                            str.Append(' ');
                        }
                        str.Append(vals[i]);
                    }
                }
                else if (componentType == typeof(short))
                {
                    var vals = (short[])array;
                    for (var i = 0; i < vals.Length; i++)
                    {
                        if (i != 0)
                        {
                            str.Append(' ');
                        }
                        str.Append(vals[i]);
                    }
                }
                else if (componentType == typeof(ushort))
                {
                    var vals = (ushort[])array;
                    for (var i = 0; i < vals.Length; i++)
                    {
                        if (i != 0)
                        {
                            str.Append(' ');
                        }
                        str.Append(vals[i]);
                    }
                }
                else if (componentType == typeof(byte))
                {
                    var vals = (byte[])array;
                    for (var i = 0; i < vals.Length; i++)
                    {
                        if (i != 0)
                        {
                            str.Append(' ');
                        }
                        str.Append(vals[i]);
                    }
                }
                else if (componentType == typeof(sbyte))
                {
                    var vals = (sbyte[])array;
                    for (var i = 0; i < vals.Length; i++)
                    {
                        if (i != 0)
                        {
                            str.Append(' ');
                        }
                        str.Append(vals[i]);
                    }
                }
                else if (componentType == typeof(Rational))
                {
                    var vals = (Rational[])array;
                    for (var i = 0; i < vals.Length; i++)
                    {
                        if (i != 0)
                        {
                            str.Append(' ');
                        }
                        str.Append(vals[i]);
                    }
                }
                else if (componentType == typeof(string))
                {
                    var vals = (string[])array;
                    for (var i = 0; i < vals.Length; i++)
                    {
                        if (i != 0)
                        {
                            str.Append(' ');
                        }
                        str.Append(vals[i]);
                    }
                }
                else if (componentType.IsByRef)
                {
                    var vals = (object[])array;
                    for (var i = 0; i < vals.Length; i++)
                    {
                        if (i != 0)
                        {
                            str.Append(' ');
                        }
                        str.Append(vals[i]);
                    }
                }
                else
                {
                    for (var i = 0; i < array.Length; i++)
                    {
                        if (i != 0)
                        {
                            str.Append(' ');
                        }
                        str.Append(array.GetValue(i));
                    }
                }

                return(str.ToString());
            }

            if (o is double)
            {
                return(((double)o).ToString("0.###"));
            }

            if (o is float)
            {
                return(((float)o).ToString("0.###"));
            }

            // Note that several cameras leave trailing spaces (Olympus, Nikon) but this library is intended to show
            // the actual data within the file.  It is not inconceivable that whitespace may be significant here, so we
            // do not trim.  Also, if support is added for writing data back to files, this may cause issues.
            // We leave trimming to the presentation layer.
            return(o.ToString());
        }