From 07e1ee385cd5ec4663dfc9db57cf547fe66ace0d Mon Sep 17 00:00:00 2001 From: Ozgur Ozcitak Date: Wed, 15 May 2019 15:15:10 +0300 Subject: [PATCH] Add missing float and double types from TIFF spec --- ExifLibrary/ExifBitConverter.cs | 64 +++++++++ ExifLibrary/ExifProperty.cs | 208 +++++++++++++++++++++++++++++ ExifLibrary/ExifPropertyFactory.cs | 27 ++++ 3 files changed, 299 insertions(+) diff --git a/ExifLibrary/ExifBitConverter.cs b/ExifLibrary/ExifBitConverter.cs index f8c1bbd..6a82435 100644 --- a/ExifLibrary/ExifBitConverter.cs +++ b/ExifLibrary/ExifBitConverter.cs @@ -234,6 +234,40 @@ public static short[] ToSShortArray(byte[] data, int count, ByteOrder frombyteor return numbers; } + /// + /// Returns an array of 32-bit floating numbers converted from + /// the given byte array. + /// Numbers are converted from the given byte-order to platform byte-order. + /// + public static float[] ToSingleArray(byte[] data, int count, ByteOrder frombyteorder) + { + float[] numbers = new float[count]; + for (int i = 0; i < count; i++) + { + byte[] num = new byte[4]; + Array.Copy(data, i * 4, num, 0, 4); + numbers[i] = ToSingle(num, 0, frombyteorder, BitConverterEx.SystemByteOrder); + } + return numbers; + } + + /// + /// Returns an array of 64-bit floating numbers converted from + /// the given byte array. + /// Numbers are converted from the given byte-order to platform byte-order. + /// + public static double[] ToDoubleArray(byte[] data, int count, ByteOrder frombyteorder) + { + double[] numbers = new double[count]; + for (int i = 0; i < count; i++) + { + byte[] num = new byte[8]; + Array.Copy(data, i * 8, num, 0, 8); + numbers[i] = ToDouble(num, 0, frombyteorder, BitConverterEx.SystemByteOrder); + } + return numbers; + } + /// /// Converts the given ascii string to an array of bytes optionally adding a null terminator. /// @@ -385,6 +419,36 @@ public static byte[] GetBytes(short[] value, ByteOrder tobyteorder) } return data; } + + /// + /// Converts the given array of 32-bit floating numbers to an array of bytes. + /// Numbers are converted from the platform byte-order to the given byte-order. + /// + public static byte[] GetBytes(float[] value, ByteOrder tobyteorder) + { + byte[] data = new byte[4 * value.Length]; + for (int i = 0; i < value.Length; i++) + { + byte[] num = GetBytes(value[i], BitConverterEx.SystemByteOrder, tobyteorder); + Array.Copy(num, 0, data, i * 4, 4); + } + return data; + } + + /// + /// Converts the given array of 64-bit floating numbers to an array of bytes. + /// Numbers are converted from the platform byte-order to the given byte-order. + /// + public static byte[] GetBytes(double[] value, ByteOrder tobyteorder) + { + byte[] data = new byte[8 * value.Length]; + for (int i = 0; i < value.Length; i++) + { + byte[] num = GetBytes(value[i], BitConverterEx.SystemByteOrder, tobyteorder); + Array.Copy(num, 0, data, i * 8, 8); + } + return data; + } #endregion } } diff --git a/ExifLibrary/ExifProperty.cs b/ExifLibrary/ExifProperty.cs index 18eb624..1e74371 100644 --- a/ExifLibrary/ExifProperty.cs +++ b/ExifLibrary/ExifProperty.cs @@ -122,6 +122,76 @@ public override ExifInterOperability Interoperability } } + /// + /// Represents an 8-bit signed integer. (EXIF Specification: SBYTE) + /// + public class ExifSByte : ExifProperty + { + protected sbyte mValue; + protected override object _Value { get { return Value; } set { Value = Convert.ToSByte(value); } } + public new sbyte Value { get { return mValue; } set { mValue = value; } } + + static public implicit operator sbyte(ExifSByte obj) { return obj.mValue; } + + public override string ToString() { return mValue.ToString(); } + + public ExifSByte(ExifTag tag, sbyte value) + : base(tag) + { + mValue = value; + } + + public override ExifInterOperability Interoperability + { + get + { + return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), InterOpType.SBYTE, 1, new byte[] { (byte)mValue }); + } + } + } + + /// + /// Represents an array of 8-bit signed integers. (EXIF Specification: SBYTE with count > 1) + /// + public class ExifSByteArray : ExifProperty + { + protected sbyte[] mValue; + protected override object _Value { get { return Value; } set { Value = (sbyte[])value; } } + public new sbyte[] Value { get { return mValue; } set { mValue = value; } } + + static public implicit operator sbyte[] (ExifSByteArray obj) { return obj.mValue; } + + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.Append('['); + foreach (sbyte b in mValue) + { + sb.Append(b); + sb.Append(' '); + } + sb.Remove(sb.Length - 1, 1); + sb.Append(']'); + return sb.ToString(); + } + + public ExifSByteArray(ExifTag tag, sbyte[] value) + : base(tag) + { + mValue = value; + } + + public override ExifInterOperability Interoperability + { + get + { + byte[] data = new byte[mValue.Length]; + Buffer.BlockCopy(mValue, 0, data, 0, mValue.Length); + return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), InterOpType.SBYTE, data.Length, data); + } + } + } + /// /// Represents an ASCII string. (EXIF Specification: ASCII) /// @@ -644,4 +714,142 @@ public override ExifInterOperability Interoperability } } } + + /// + /// Represents a 32-bit floating number. (EXIF Specification: FLOAT) + /// + public class ExifFloat : ExifProperty + { + protected float mValue; + protected override object _Value { get { return Value; } set { Value = Convert.ToSingle(value); } } + public new float Value { get { return mValue; } set { mValue = value; } } + + static public implicit operator float(ExifFloat obj) { return obj.mValue; } + + public override string ToString() { return mValue.ToString(); } + + public ExifFloat(ExifTag tag, float value) + : base(tag) + { + mValue = value; + } + + public override ExifInterOperability Interoperability + { + get + { + return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), InterOpType.FLOAT, 1, ExifBitConverter.GetBytes(mValue, BitConverterEx.SystemByteOrder, BitConverterEx.SystemByteOrder)); + } + } + } + + /// + /// Represents an array of 32-bit floating numbers. + /// (EXIF Specification: FLOAT with count > 1) + /// + public class ExifFloatArray : ExifProperty + { + protected float[] mValue; + protected override object _Value { get { return Value; } set { Value = (float[])value; } } + public new float[] Value { get { return mValue; } set { mValue = value; } } + + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.Append('['); + foreach (float b in mValue) + { + sb.Append(b); + sb.Append(' '); + } + sb.Remove(sb.Length - 1, 1); + sb.Append(']'); + return sb.ToString(); + } + + static public implicit operator float[] (ExifFloatArray obj) { return obj.mValue; } + + public ExifFloatArray(ExifTag tag, float[] value) + : base(tag) + { + mValue = value; + } + + public override ExifInterOperability Interoperability + { + get + { + return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), InterOpType.FLOAT, (uint)mValue.Length, ExifBitConverter.GetBytes(mValue, BitConverterEx.SystemByteOrder)); + } + } + } + + /// + /// Represents a 64-bit floating number. (EXIF Specification: DOUBLE) + /// + public class ExifDouble : ExifProperty + { + protected double mValue; + protected override object _Value { get { return Value; } set { Value = Convert.ToDouble(value); } } + public new double Value { get { return mValue; } set { mValue = value; } } + + static public implicit operator double(ExifDouble obj) { return obj.mValue; } + + public override string ToString() { return mValue.ToString(); } + + public ExifDouble(ExifTag tag, double value) + : base(tag) + { + mValue = value; + } + + public override ExifInterOperability Interoperability + { + get + { + return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), InterOpType.DOUBLE, 1, ExifBitConverter.GetBytes(mValue, BitConverterEx.SystemByteOrder, BitConverterEx.SystemByteOrder)); + } + } + } + + /// + /// Represents an array of 64-bit floating numbers. + /// (EXIF Specification: DOUBLE with count > 1) + /// + public class ExifDoubleArray : ExifProperty + { + protected double[] mValue; + protected override object _Value { get { return Value; } set { Value = (double[])value; } } + public new double[] Value { get { return mValue; } set { mValue = value; } } + + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.Append('['); + foreach (float b in mValue) + { + sb.Append(b); + sb.Append(' '); + } + sb.Remove(sb.Length - 1, 1); + sb.Append(']'); + return sb.ToString(); + } + + static public implicit operator double[](ExifDoubleArray obj) { return obj.mValue; } + + public ExifDoubleArray(ExifTag tag, double[] value) + : base(tag) + { + mValue = value; + } + + public override ExifInterOperability Interoperability + { + get + { + return new ExifInterOperability(ExifTagFactory.GetTagID(mTag), InterOpType.DOUBLE, (uint)mValue.Length, ExifBitConverter.GetBytes(mValue, BitConverterEx.SystemByteOrder)); + } + } + } } diff --git a/ExifLibrary/ExifPropertyFactory.cs b/ExifLibrary/ExifPropertyFactory.cs index 16d0aea..7a974da 100644 --- a/ExifLibrary/ExifPropertyFactory.cs +++ b/ExifLibrary/ExifPropertyFactory.cs @@ -231,6 +231,19 @@ public static ExifProperty Get(ushort tag, ushort type, uint count, byte[] value else return new ExifURationalArray(etag, ExifBitConverter.ToURationalArray(value, (int)count, byteOrder)); } + else if (type == 6) // 1 = SBYTE An 8-bit signed integer. + { + if (count == 1) + { + return new ExifSByte(etag, (sbyte)value[0]); + } + else + { + sbyte[] data = new sbyte[count]; + Buffer.BlockCopy(value, 0, data, 0, (int)count); + return new ExifSByteArray(etag, data); + } + } 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. @@ -254,6 +267,20 @@ public static ExifProperty Get(ushort tag, ushort type, uint count, byte[] value else return new ExifSRationalArray(etag, ExifBitConverter.ToSRationalArray(value, (int)count, byteOrder)); } + else if (type == 11) // 11 = FLOAT Single precision (4-byte) IEEE format. + { + if (count == 1) + return new ExifFloat(etag, conv.ToSingle(value, 0)); + else + return new ExifFloatArray(etag, ExifBitConverter.ToSingleArray(value, (int)count, byteOrder)); + } + else if (type == 12) // 12 = DOUBLE Double precision (8-byte) IEEE format. + { + if (count == 1) + return new ExifDouble(etag, conv.ToDouble(value, 0)); + else + return new ExifDoubleArray(etag, ExifBitConverter.ToDoubleArray(value, (int)count, byteOrder)); + } else throw new ArgumentException("Unknown property type."); }