diff --git a/ExifLibrary/ExifBitConverter.cs b/ExifLibrary/ExifBitConverter.cs index a2027d8..f8c1bbd 100644 --- a/ExifLibrary/ExifBitConverter.cs +++ b/ExifLibrary/ExifBitConverter.cs @@ -216,6 +216,24 @@ public static MathEx.Fraction32[] ToSRationalArray(byte[] data, int count, ByteO return numbers; } + + /// + /// Returns an array of 16-bit signed integers converted from + /// the given byte array. + /// Numbers are converted from the given byte-order to platform byte-order. + /// + public static short[] ToSShortArray(byte[] data, int count, ByteOrder frombyteorder) + { + short[] numbers = new short[count]; + for (int i = 0; i < count; i++) + { + byte[] num = new byte[2]; + Array.Copy(data, i * 2, num, 0, 2); + numbers[i] = ToInt16(num, 0, frombyteorder, BitConverterEx.SystemByteOrder); + } + return numbers; + } + /// /// Converts the given ascii string to an array of bytes optionally adding a null terminator. /// @@ -352,6 +370,21 @@ public static byte[] GetBytes(MathEx.Fraction32[] value, ByteOrder tobyteorder) } return data; } + + /// + /// Converts the given array of 16-bit signed integers to an array of bytes. + /// Numbers are converted from the platform byte-order to the given byte-order. + /// + public static byte[] GetBytes(short[] value, ByteOrder tobyteorder) + { + byte[] data = new byte[2 * value.Length]; + for (int i = 0; i < value.Length; i++) + { + byte[] num = GetBytes(value[i], BitConverterEx.SystemByteOrder, tobyteorder); + Array.Copy(num, 0, data, i * 2, 2); + } + return data; + } #endregion } } diff --git a/ExifLibrary/ExifProperty.cs b/ExifLibrary/ExifProperty.cs index 5b6558a..18eb624 100644 --- a/ExifLibrary/ExifProperty.cs +++ b/ExifLibrary/ExifProperty.cs @@ -130,7 +130,7 @@ public class ExifAscii : ExifProperty protected string mValue; protected override object _Value { get { return Value; } set { Value = (string)value; } } public new string Value { get { return mValue; } set { mValue = value; } } - + public Encoding Encoding { get; private set; } static public implicit operator string(ExifAscii obj) { return obj.mValue; } @@ -260,7 +260,7 @@ public class ExifUIntArray : ExifProperty protected override object _Value { get { return Value; } set { Value = (uint[])value; } } public new uint[] Value { get { return mValue; } set { mValue = value; } } - static public implicit operator uint[] (ExifUIntArray obj) { return obj.mValue; } + static public implicit operator uint[](ExifUIntArray obj) { return obj.mValue; } public override string ToString() { @@ -575,4 +575,73 @@ public override ExifInterOperability Interoperability } } } + + /// + /// Represents a 16-bit signed integer. (EXIF Specification: SHORT) + /// + public class ExifSShort : ExifProperty + { + protected short mValue; + protected override object _Value { get { return Value; } set { Value = Convert.ToInt16(value); } } + public new short Value { get { return mValue; } set { mValue = value; } } + + static public implicit operator short(ExifSShort obj) { return obj.mValue; } + + public override string ToString() { return mValue.ToString(); } + + public ExifSShort(ExifTag tag, short value) + : base(tag) + { + mValue = value; + } + + public override ExifInterOperability Interoperability + { + get + { + return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), InterOpType.SSHORT, 1, ExifBitConverter.GetBytes(mValue, BitConverterEx.SystemByteOrder, BitConverterEx.SystemByteOrder)); + } + } + } + + /// + /// Represents an array of 16-bit signed integers. + /// (EXIF Specification: SHORT with count > 1) + /// + public class ExifSShortArray : ExifProperty + { + protected short[] mValue; + protected override object _Value { get { return Value; } set { Value = (short[])value; } } + public new short[] Value { get { return mValue; } set { mValue = value; } } + + static public implicit operator short[] (ExifSShortArray obj) { return obj.mValue; } + + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.Append('['); + foreach (ushort b in mValue) + { + sb.Append(b); + sb.Append(' '); + } + sb.Remove(sb.Length - 1, 1); + sb.Append(']'); + return sb.ToString(); + } + + public ExifSShortArray(ExifTag tag, short[] value) + : base(tag) + { + mValue = value; + } + + public override ExifInterOperability Interoperability + { + get + { + return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), InterOpType.SSHORT, (uint)mValue.Length, ExifBitConverter.GetBytes(mValue, BitConverterEx.SystemByteOrder)); + } + } + } } diff --git a/ExifLibrary/ExifPropertyFactory.cs b/ExifLibrary/ExifPropertyFactory.cs index 7fefbe3..16d0aea 100644 --- a/ExifLibrary/ExifPropertyFactory.cs +++ b/ExifLibrary/ExifPropertyFactory.cs @@ -134,7 +134,7 @@ public static ExifProperty Get(ushort tag, ushort type, uint count, byte[] value else if (ifd == IFD.GPS) { if (tag == 0) // GPSVersionID - return new VersionID(ExifTag.GPSVersionID, value); + return new ExifVersion(ExifTag.GPSVersionID, ExifBitConverter.ToString(value)); else if (tag == 1) // GPSLatitudeRef return new ExifEnumProperty(ExifTag.GPSLatitudeRef, (GPSLatitudeRef)value[0]); else if (tag == 2) // GPSLatitude @@ -233,6 +233,13 @@ public static ExifProperty Get(ushort tag, ushort type, uint count, byte[] value } else if (type == 7) // 7 = UNDEFINED An 8-bit byte that can take any value depending on the field definition. return new ExifUndefined(etag, value); + else if (type == 8) // 8 = SSHORT A 16-bit (2-byte) signed integer. + { + if (count == 1) + return new ExifSShort(etag, conv.ToInt16(value, 0)); + else + return new ExifSShortArray(etag, ExifBitConverter.ToSShortArray(value, (int)count, byteOrder)); + } else if (type == 9) // 9 = SLONG A 32-bit (4-byte) signed integer (2's complement notation). { if (count == 1) diff --git a/ExifLibrary/JPEGFile.cs b/ExifLibrary/JPEGFile.cs index d79ab01..0e3c13e 100644 --- a/ExifLibrary/JPEGFile.cs +++ b/ExifLibrary/JPEGFile.cs @@ -495,6 +495,8 @@ private void ReadExifAPP1() int thumboffset = -1; int thumblength = 0; int thumbtype = -1; + + // Read IFDs while (ifdqueue.Count != 0) { @@ -539,12 +541,14 @@ private void ReadExifAPP1() uint baselength = 0; if (type == 1 || type == 2 || type == 7) baselength = 1; - else if (type == 3) + else if (type == 3 || type == 8) baselength = 2; else if (type == 4 || type == 9) baselength = 4; else if (type == 5 || type == 10) baselength = 8; + else // Unknown or invalid type + continue; // Skip and keep going uint totallength = count * baselength; // If field value does not fit in 4 bytes @@ -596,11 +600,13 @@ private void ReadExifAPP1() // 1st IFD pointer int firstifdoffset = ifdoffset + 2 + 12 * fieldcount; - if (firstifdoffset + 4 <= header.Length) + if (firstifdoffset + 4 <= header.Length && currentifd == IFD.Zeroth) { int firstifdpointer = (int)conv.ToUInt32(header, firstifdoffset); if (firstifdpointer != 0 && firstifdpointer + 2 <= header.Length) + { ifdqueue.Add(firstifdpointer, IFD.First); + } } // Read thumbnail if (thumboffset != -1 && thumblength != 0 && Thumbnail == null)