public void SRational3() { var r3 = new SRational(0, -17); Assert.AreEqual(0, r3.Numerator); Assert.AreEqual(-17, r3.Denominator); Assert.AreEqual(0.0d / -17.0d, (double)r3); Assert.AreEqual("0/1", r3.ToString()); Assert.AreEqual(0, r3.Reduce().Numerator); Assert.AreEqual(1, r3.Reduce().Denominator); }
public void SRational4() { var r4 = new SRational(-108, -46); Assert.AreEqual(-108, r4.Numerator); Assert.AreEqual(-46, r4.Denominator); Assert.AreEqual(-108.0d / -46.0d, (double)r4); Assert.AreEqual("54/23", r4.ToString()); Assert.AreEqual(54, r4.Reduce().Numerator); Assert.AreEqual(23, r4.Reduce().Denominator); }
public void SRational1() { var r1 = new SRational(5, 3); Assert.AreEqual(5, r1.Numerator); Assert.AreEqual(3, r1.Denominator); Assert.AreEqual(5.0d / 3.0d, (double)r1); Assert.AreEqual("5/3", r1.ToString()); Assert.AreEqual(5, r1.Reduce().Numerator); Assert.AreEqual(3, r1.Reduce().Denominator); }
public void SRational2() { var r2 = new SRational(48, 18); Assert.AreEqual(48, r2.Numerator); Assert.AreEqual(18, r2.Denominator); Assert.AreEqual(48.0d / 18.0d, (double)r2); Assert.AreEqual("8/3", r2.ToString()); Assert.AreEqual(8, r2.Reduce().Numerator); Assert.AreEqual(3, r2.Reduce().Denominator); }
public void SRational5() { var r5 = new SRational(-256, 96); Assert.AreEqual(-256, r5.Numerator); Assert.AreEqual(96, r5.Denominator); Assert.AreEqual(-256.0d / 96.0d, (double)r5); Assert.AreEqual("-8/3", r5.ToString()); Assert.AreEqual(-8, r5.Reduce().Numerator); Assert.AreEqual(3, r5.Reduce().Denominator); }
/// <summary> /// Creates an IFDEntry from the given values. This method is used for /// every entry. Custom parsing can be hooked in by overriding the /// <see cref="ParseIFDEntry(ushort,ushort,uint,long,uint)"/> method. /// </summary> /// <param name="tag"> /// A <see cref="System.UInt16"/> with the tag of the entry. /// </param> /// <param name="type"> /// A <see cref="System.UInt16"/> with the type of the entry. /// </param> /// <param name="count"> /// A <see cref="System.UInt32"/> with the data count of the entry. /// </param> /// <param name="baseOffset"> /// A <see cref="System.Int64"/> with the base offset which every /// offsets in the IFD are relative to. /// </param> /// <param name="offsetData"> /// A <see cref="ByteVector"/> containing exactly 4 byte with the data /// of the offset of the entry. Since this field isn't interpreted as /// an offset if the data can be directly stored in the 4 byte, we /// pass the <see cref="ByteVector"/> to easier interpret it. /// </param> /// <param name="maxOffset"> /// A <see cref="System.UInt32"/> with the maximal offset to consider for /// the IFD. /// </param> /// <returns> /// A <see cref="IFDEntry"/> with the given parameter. /// </returns> IFDEntry CreateIFDEntry(ushort tag, ushort type, uint count, long baseOffset, ByteVector offsetData, uint maxOffset) { uint offset = offsetData.ToUInt(is_bigendian); // Fix the type for the IPTC tag. // From http://www.awaresystems.be/imaging/tiff/tifftags/iptc.html // "Often times, the datatype is incorrectly specified as LONG. " if (tag == (ushort)IFDEntryTag.IPTC && type == (ushort)IFDEntryType.Long) { type = (ushort)IFDEntryType.Byte; } var ifd_entry = ParseIFDEntry(tag, type, count, baseOffset, offset); if (ifd_entry != null) { return(ifd_entry); } if (count > 0x10000000) { // Some Nikon files are known to exhibit this corruption (or "feature"). file.MarkAsCorrupt("Impossibly large item count"); return(null); } // then handle the values stored in the offset data itself if (count == 1) { if (type == (ushort)IFDEntryType.Byte) { return(new ByteIFDEntry(tag, offsetData[0])); } if (type == (ushort)IFDEntryType.SByte) { return(new SByteIFDEntry(tag, (sbyte)offsetData[0])); } if (type == (ushort)IFDEntryType.Short) { return(new ShortIFDEntry(tag, offsetData.Mid(0, 2).ToUShort(is_bigendian))); } if (type == (ushort)IFDEntryType.SShort) { return(new SShortIFDEntry(tag, offsetData.Mid(0, 2).ToUShort(is_bigendian))); } if (type == (ushort)IFDEntryType.Long) { return(new LongIFDEntry(tag, offsetData.ToUInt(is_bigendian))); } if (type == (ushort)IFDEntryType.SLong) { return(new SLongIFDEntry(tag, offsetData.ToInt(is_bigendian))); } } if (count == 2) { if (type == (ushort)IFDEntryType.Short) { ushort[] data = new[] { offsetData.Mid(0, 2).ToUShort(is_bigendian), offsetData.Mid(2, 2).ToUShort(is_bigendian) }; return(new ShortArrayIFDEntry(tag, data)); } if (type == (ushort)IFDEntryType.SShort) { short[] data = new[] { (short)offsetData.Mid(0, 2).ToUShort(is_bigendian), (short)offsetData.Mid(2, 2).ToUShort(is_bigendian) }; return(new SShortArrayIFDEntry(tag, data)); } } if (count <= 4) { if (type == (ushort)IFDEntryType.Undefined) { return(new UndefinedIFDEntry(tag, offsetData.Mid(0, (int)count))); } if (type == (ushort)IFDEntryType.Ascii) { string data = offsetData.Mid(0, (int)count).ToString(); int term = data.IndexOf('\0'); if (term > -1) { data = data.Substring(0, term); } return(new StringIFDEntry(tag, data)); } if (type == (ushort)IFDEntryType.Byte) { return(new ByteVectorIFDEntry(tag, offsetData.Mid(0, (int)count))); } } // FIXME: create correct type. if (offset > maxOffset) { return(new UndefinedIFDEntry(tag, new ByteVector())); } // then handle data referenced by the offset file.Seek(baseOffset + offset, SeekOrigin.Begin); if (count == 1) { if (type == (ushort)IFDEntryType.Rational) { return(new RationalIFDEntry(tag, ReadRational())); } if (type == (ushort)IFDEntryType.SRational) { return(new SRationalIFDEntry(tag, ReadSRational())); } } if (count > 1) { if (type == (ushort)IFDEntryType.Long) { uint[] data = ReadUIntArray(count); return(new LongArrayIFDEntry(tag, data)); } if (type == (ushort)IFDEntryType.SLong) { int[] data = ReadIntArray(count); return(new SLongArrayIFDEntry(tag, data)); } if (type == (ushort)IFDEntryType.Rational) { var entries = new Rational[count]; for (int i = 0; i < count; i++) { entries[i] = ReadRational(); } return(new RationalArrayIFDEntry(tag, entries)); } if (type == (ushort)IFDEntryType.SRational) { var entries = new SRational[count]; for (int i = 0; i < count; i++) { entries[i] = ReadSRational(); } return(new SRationalArrayIFDEntry(tag, entries)); } } if (count > 2) { if (type == (ushort)IFDEntryType.Short) { ushort[] data = ReadUShortArray(count); return(new ShortArrayIFDEntry(tag, data)); } if (type == (ushort)IFDEntryType.SShort) { short[] data = ReadShortArray(count); return(new SShortArrayIFDEntry(tag, data)); } } if (count > 4) { if (type == (ushort)IFDEntryType.Long) { uint[] data = ReadUIntArray(count); return(new LongArrayIFDEntry(tag, data)); } if (type == (ushort)IFDEntryType.Byte) { ByteVector data = file.ReadBlock((int)count); return(new ByteVectorIFDEntry(tag, data)); } if (type == (ushort)IFDEntryType.Ascii) { string data = ReadAsciiString((int)count); return(new StringIFDEntry(tag, data)); } if (tag == (ushort)ExifEntryTag.UserComment) { ByteVector data = file.ReadBlock((int)count); return(new UserCommentIFDEntry(tag, data, file)); } if (type == (ushort)IFDEntryType.Undefined) { ByteVector data = file.ReadBlock((int)count); return(new UndefinedIFDEntry(tag, data)); } } if (type == (ushort)IFDEntryType.Float) { return(null); } if (type == 0 || type > 12) { // Invalid type file.MarkAsCorrupt("Invalid item type"); return(null); } throw new NotImplementedException($"Unknown type/count {type}/{count} ({offset})"); }
/// <summary> /// Construcor. /// </summary> /// <param name="tag"> /// A <see cref="System.UInt16"/> with the tag ID of the entry this instance /// represents /// </param> /// <param name="value"> /// A <see cref="SRational"/> to be stored /// </param> public SRationalIFDEntry (ushort tag, SRational value) { Tag = tag; Value = value; }
public static T GetQuery <T>(this BitmapMetadata bitmapMetadata, string query) { // Return default if the BitmapMetadata doesn't contain the query // Would prefer to return null if (!bitmapMetadata.ContainsQuery(query)) { return(default(T)); } // Grab object object unknownObject = bitmapMetadata.GetQuery(query); if (unknownObject == null) { return(default(T)); } else if (typeof(T) == typeof(SRational)) { if (unknownObject.GetType() == bitmapMetadata.GetStorageType(typeof(SRational))) { // Create new Rational, casting the unknownobject as an Int64 SRational rational = new SRational((Int64)unknownObject); // Convert back to typeof(T) return((T)Convert.ChangeType(rational, typeof(T))); } else { return(default(T)); } } else if (typeof(T) == typeof(URational)) { if (unknownObject.GetType() == bitmapMetadata.GetStorageType(typeof(URational))) { // Create new URational, casting the unknownobject as an UInt64 URational urational = new URational((UInt64)unknownObject); // Convert back to typeof(T) return((T)Convert.ChangeType(urational, typeof(T))); } else { return(default(T)); } } else if (typeof(T) == typeof(URationalTriplet)) { if (unknownObject.GetType() == bitmapMetadata.GetStorageType(typeof(URationalTriplet))) { // Create new GpsRational, casting the unknownobject as an Int64[] URationalTriplet gpsRational = new URationalTriplet((UInt64[])unknownObject); // Convert back to typeof(T) return((T)Convert.ChangeType(gpsRational, typeof(T))); } else { return(default(T)); } } else if (typeof(T) == typeof(ExifDateTime)) { // Create new ExifDateTime, casting the unknownobject as a string ExifDateTime exifDateTime = new ExifDateTime(unknownObject.ToString()); // Convert back to typeof(T) return((T)Convert.ChangeType(exifDateTime, typeof(T))); } else if (typeof(T) == typeof(TimeSpan)) { string timespanString = (unknownObject as string); if (!timespanString.EndsWith("+0000")) { throw new NotImplementedException("Timespan contains timezone, need to implement the right code"); } else if (timespanString.Length > 6) { int hour = Convert.ToInt32(timespanString.Substring(0, 2)); int minute = Convert.ToInt32(timespanString.Substring(2, 2)); int second = Convert.ToInt32(timespanString.Substring(4, 2)); TimeSpan timeSpan = new TimeSpan(hour, minute, second); return((T)Convert.ChangeType(timeSpan, typeof(T))); } else { return(default(T)); } } else if (typeof(T) == typeof(DateTime)) { // Split the string into date & time // Convert T to a space string[] dateTimeString = (unknownObject as string).Replace("T", " ").Split(' '); if (dateTimeString.Length == 1 && dateTimeString[0].Length == 8) { int year = Convert.ToInt32(dateTimeString[0].Substring(0, 4)); int month = Convert.ToInt32(dateTimeString[0].Substring(4, 2)); int day = Convert.ToInt32(dateTimeString[0].Substring(6, 2)); DateTime dateTime = new DateTime(year, month, day); return((T)Convert.ChangeType(dateTime, typeof(T))); } else if (dateTimeString.Length == 2) { // Ensure seperate is dash for Date dateTimeString[0] = dateTimeString[0].Replace(":", "-"); // Strip the Z from the Time dateTimeString[1] = dateTimeString[1].TrimEnd('Z'); DateTime dateTime = DateTime.Parse(dateTimeString[0] + " " + dateTimeString[1]); // Parse as local time DateTime localDateTime = new DateTime(dateTime.Ticks, DateTimeKind.Local); // Convert back to typeof(T) return((T)Convert.ChangeType(localDateTime, typeof(T))); } return(default(T)); } else if (typeof(T) == typeof(string)) { // Trim the string return((T)Convert.ChangeType(unknownObject.ToString().Trim(), typeof(T))); } else if (!typeof(T).IsAssignableFrom(unknownObject.GetType())) { // Throw exception if the object is the wrong type throw new System.ArgumentException("Query \"" + query + "\" has type \"" + unknownObject.GetType().ToString() + "\" not expected type \"" + typeof(T).ToString() + "\""); } return((T)unknownObject); }
/// <summary> /// Construcor. /// </summary> /// <param name="tag"> /// A <see cref="System.UInt16"/> with the tag ID of the entry this instance /// represents /// </param> /// <param name="value"> /// A <see cref="SRational"/> to be stored /// </param> public SRationalIFDEntry(ushort tag, SRational value) { Tag = tag; Value = value; }
private object[] ReadFieldValuesAsObjects(BinaryReader2 reader, FieldType fieldType, int numValues) { var array = new object[numValues]; switch (fieldType) { case FieldType.Int64: { for (int i = 0; i < numValues; i++) { array[i] = reader.ReadInt64(); } } break; case FieldType.UInt64: { for (int i = 0; i < numValues; i++) { array[i] = reader.ReadInt64(); } } break; case FieldType.Int32: { for (int i = 0; i < numValues; i++) { array[i] = reader.ReadInt32(); } } break; case FieldType.UInt32: { for (int i = 0; i < numValues; i++) { array[i] = reader.ReadUInt32(); } } break; case FieldType.Int16: { for (int i = 0; i < numValues; i++) { array[i] = reader.ReadInt16(); } } break; case FieldType.UInt16: { for (int i = 0; i < numValues; i++) { array[i] = reader.ReadUInt16(); } } break; case FieldType.SByte: { for (int i = 0; i < numValues; i++) { array[i] = reader.ReadSByte(); } } break; case FieldType.Byte: { for (int i = 0; i < numValues; i++) { array[i] = reader.ReadByte(); } } break; case FieldType.Float: { for (int i = 0; i < numValues; i++) { array[i] = reader.ReadSingle(); } } break; case FieldType.Double: { for (int i = 0; i < numValues; i++) { array[i] = reader.ReadDouble(); } } break; case FieldType.Rational: { for (int i = 0; i < numValues; i++) { array[i] = new Rational(reader.ReadUInt32(), reader.ReadUInt32()); } } break; case FieldType.SRational: { for (int i = 0; i < numValues; i++) { array[i] = new SRational(reader.ReadInt32(), reader.ReadInt32()); } } break; default: throw new Exception($"Unknown field type {fieldType}"); } return(array); }
private IFDEntry CreateIFDEntry(ushort tag, ushort type, uint count, long base_offset, ByteVector offset_data, uint max_offset) { uint offset = offset_data.ToUInt(is_bigendian); if (tag == (ushort)IFDEntryTag.IPTC && type == (ushort)IFDEntryType.Long) { type = (ushort)IFDEntryType.Byte; } var ifd_entry = ParseIFDEntry(tag, type, count, base_offset, offset); if (ifd_entry != null) { return(ifd_entry); } if (count > 0x10000000) { file.MarkAsCorrupt("Impossibly large item count"); return(null); } if (count == 1) { if (type == (ushort)IFDEntryType.Byte) { return(new ByteIFDEntry(tag, offset_data[0])); } if (type == (ushort)IFDEntryType.SByte) { return(new SByteIFDEntry(tag, (sbyte)offset_data[0])); } if (type == (ushort)IFDEntryType.Short) { return(new ShortIFDEntry(tag, offset_data.Mid(0, 2).ToUShort(is_bigendian))); } if (type == (ushort)IFDEntryType.SShort) { return(new SShortIFDEntry(tag, (ushort)offset_data.Mid(0, 2).ToUShort(is_bigendian))); } if (type == (ushort)IFDEntryType.Long) { return(new LongIFDEntry(tag, offset_data.ToUInt(is_bigendian))); } if (type == (ushort)IFDEntryType.SLong) { return(new SLongIFDEntry(tag, offset_data.ToInt(is_bigendian))); } } if (count == 2) { if (type == (ushort)IFDEntryType.Short) { ushort[] data = new ushort[] { offset_data.Mid(0, 2).ToUShort(is_bigendian), offset_data.Mid(2, 2).ToUShort(is_bigendian) }; return(new ShortArrayIFDEntry(tag, data)); } if (type == (ushort)IFDEntryType.SShort) { short[] data = new short[] { (short)offset_data.Mid(0, 2).ToUShort(is_bigendian), (short)offset_data.Mid(2, 2).ToUShort(is_bigendian) }; return(new SShortArrayIFDEntry(tag, data)); } } if (count <= 4) { if (type == (ushort)IFDEntryType.Undefined) { return(new UndefinedIFDEntry(tag, offset_data.Mid(0, (int)count))); } if (type == (ushort)IFDEntryType.Ascii) { string data = offset_data.Mid(0, (int)count).ToString(); int term = data.IndexOf('\0'); if (term > -1) { data = data.Substring(0, term); } return(new StringIFDEntry(tag, data)); } if (type == (ushort)IFDEntryType.Byte) { return(new ByteVectorIFDEntry(tag, offset_data.Mid(0, (int)count))); } } if (offset > max_offset) { return(new UndefinedIFDEntry(tag, new ByteVector())); } file.Seek(base_offset + offset, SeekOrigin.Begin); if (count == 1) { if (type == (ushort)IFDEntryType.Rational) { return(new RationalIFDEntry(tag, ReadRational())); } if (type == (ushort)IFDEntryType.SRational) { return(new SRationalIFDEntry(tag, ReadSRational())); } } if (count > 1) { if (type == (ushort)IFDEntryType.Long) { uint[] data = ReadUIntArray(count); return(new LongArrayIFDEntry(tag, data)); } if (type == (ushort)IFDEntryType.SLong) { int[] data = ReadIntArray(count); return(new SLongArrayIFDEntry(tag, data)); } if (type == (ushort)IFDEntryType.Rational) { Rational[] entries = new Rational[count]; for (int i = 0; i < count; i++) { entries[i] = ReadRational(); } return(new RationalArrayIFDEntry(tag, entries)); } if (type == (ushort)IFDEntryType.SRational) { SRational[] entries = new SRational[count]; for (int i = 0; i < count; i++) { entries[i] = ReadSRational(); } return(new SRationalArrayIFDEntry(tag, entries)); } } if (count > 2) { if (type == (ushort)IFDEntryType.Short) { ushort[] data = ReadUShortArray(count); return(new ShortArrayIFDEntry(tag, data)); } if (type == (ushort)IFDEntryType.SShort) { short[] data = ReadShortArray(count); return(new SShortArrayIFDEntry(tag, data)); } } if (count > 4) { if (type == (ushort)IFDEntryType.Long) { uint[] data = ReadUIntArray(count); return(new LongArrayIFDEntry(tag, data)); } if (type == (ushort)IFDEntryType.Byte) { ByteVector data = file.ReadBlock((int)count); return(new ByteVectorIFDEntry(tag, data)); } if (type == (ushort)IFDEntryType.Ascii) { string data = ReadAsciiString((int)count); return(new StringIFDEntry(tag, data)); } if (tag == (ushort)ExifEntryTag.UserComment) { ByteVector data = file.ReadBlock((int)count); return(new UserCommentIFDEntry(tag, data, file)); } if (type == (ushort)IFDEntryType.Undefined) { ByteVector data = file.ReadBlock((int)count); return(new UndefinedIFDEntry(tag, data)); } } if (type == (ushort)IFDEntryType.Float) { return(null); } if (type == 0 || type > 12) { file.MarkAsCorrupt("Invalid item type"); return(null); } throw new NotImplementedException(String.Format("Unknown type/count {0}/{1} ({2})", type, count, offset)); }
private void WriteSRational(SRational value) { WriteLong(value.Numerator); WriteLong(value.Denominator); }