public ExifByte(ExifTag <byte> tag, ExifDataType dataType) : base(tag) => this.DataType = dataType;
private object ConvertValue(ExifDataType dataType, ReadOnlySpan <byte> buffer, uint numberOfComponents) { if (buffer.Length == 0) { return(null); } switch (dataType) { case ExifDataType.Unknown: return(null); case ExifDataType.Ascii: return(this.ConvertToString(buffer)); case ExifDataType.Byte: if (numberOfComponents == 1) { return(this.ConvertToByte(buffer)); } return(buffer.ToArray()); case ExifDataType.DoubleFloat: if (numberOfComponents == 1) { return(this.ConvertToDouble(buffer)); } return(ToArray(dataType, buffer, this.ConvertToDouble)); case ExifDataType.Long: if (numberOfComponents == 1) { return(this.ConvertToUInt32(buffer)); } return(ToArray(dataType, buffer, this.ConvertToUInt32)); case ExifDataType.Rational: if (numberOfComponents == 1) { return(this.ToRational(buffer)); } return(ToArray(dataType, buffer, this.ToRational)); case ExifDataType.Short: if (numberOfComponents == 1) { return(this.ConvertToShort(buffer)); } return(ToArray(dataType, buffer, this.ConvertToShort)); case ExifDataType.SignedByte: if (numberOfComponents == 1) { return(this.ConvertToSignedByte(buffer)); } return(ToArray(dataType, buffer, this.ConvertToSignedByte)); case ExifDataType.SignedLong: if (numberOfComponents == 1) { return(this.ConvertToInt32(buffer)); } return(ToArray(dataType, buffer, this.ConvertToInt32)); case ExifDataType.SignedRational: if (numberOfComponents == 1) { return(this.ToSignedRational(buffer)); } return(ToArray(dataType, buffer, this.ToSignedRational)); case ExifDataType.SignedShort: if (numberOfComponents == 1) { return(this.ConvertToSignedShort(buffer)); } return(ToArray(dataType, buffer, this.ConvertToSignedShort)); case ExifDataType.SingleFloat: if (numberOfComponents == 1) { return(this.ConvertToSingle(buffer)); } return(ToArray(dataType, buffer, this.ConvertToSingle)); case ExifDataType.Undefined: if (numberOfComponents == 1) { return(this.ConvertToByte(buffer)); } return(buffer.ToArray()); default: throw new NotSupportedException(); } }
private static object ParseValue(ExifId id, ExifDataType type, byte[] data) { if (type != ExifDataType.Binary && type != ExifDataType.Undefined) { if (data == null) throw new ArgumentNullException(nameof(data), String.Format("ID: {0}. Type: {1}.", id, type)); } object temp; if (SpecialParseValue(id, type, data, out temp)) return temp; switch (type) { case ExifDataType.Binary: return data; case ExifDataType.ASCII: return Encoding.ASCII.GetString(data).RemoveNullChars(); case ExifDataType.Int16: return BitConverter.ToInt16(data, 0); case ExifDataType.Int32: return BitConverter.ToInt32(data, 0); case ExifDataType.Long: return BitConverter.ToInt64(data, 0); case ExifDataType.Float: case ExifDataType.Double: return (double)BitConverter.ToInt32(data, 0) / (double)BitConverter.ToInt32(data, 4); case ExifDataType.Undefined: return data; default: throw new NotImplementedException(String.Format("Type not implemented: {0}", type)); } }
private static bool SpecialParseValue(ExifId id, ExifDataType type, byte[] data, out object temp) { temp = null; switch (id) { // Convert to DateTime case ExifId.ImageDateTime: case ExifId.ImageDateTimeOriginal: case ExifId.ImagePreviewDateTime: case ExifId.PhotoDateTimeDigitized: //case ExifId.PhotoDateTimeOriginal: // Same value as ImageDateTimeOriginal case ExifId.ThumbnailDateTime: string datestring = Encoding.ASCII.GetString(data).RemoveNullChars(); DateTime datetime; if (DateTime.TryParse(datestring, out datetime)) { temp = datetime; return true; } // Handle special cases if (DateTime.TryParseExact(datestring, "yyyy:MM:dd HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.None, out datetime)) { temp = datetime; return true; } return false; // Convert to UCS-2 case ExifId.ImageXPAuthor: case ExifId.ImageXPComment: case ExifId.ImageXPSubject: case ExifId.ImageXPTitle: temp = Encoding.GetEncoding("ucs-2").GetString(data).RemoveNullChars(); return true; case ExifId.ImageXPKeywords: string keywords = Encoding.GetEncoding("ucs-2").GetString(data).RemoveNullChars(); if (keywords.Length > 0) temp = keywords.Split(new char[] { TagsSeparator }, StringSplitOptions.RemoveEmptyEntries); else temp = new string[0]; return true; default: return false; } }
private object ConvertValue(ExifDataType dataType, uint length, uint numberOfComponents) { if (length == 0) { return(null); } switch (dataType) { case ExifDataType.Unknown: return(null); case ExifDataType.Ascii: return(ReadString(length)); case ExifDataType.Undefined: case ExifDataType.Byte: if (numberOfComponents == 1) { return(ReadByte()); } else { return(ToArray(dataType, length, ReadByte)); } case ExifDataType.DoubleFloat: if (numberOfComponents == 1) { return(ReadDouble()); } else { return(ToArray(dataType, length, ReadDouble)); } case ExifDataType.Long: if (numberOfComponents == 1) { return(ReadLong()); } else { return(ToArray(dataType, length, ReadLong)); } case ExifDataType.Rational: if (numberOfComponents == 1) { return(ReadRational()); } else { return(ToArray(dataType, length, ReadRational)); } case ExifDataType.Short: if (numberOfComponents == 1) { return(ReadShort()); } else { return(ToArray(dataType, length, ReadShort)); } case ExifDataType.SignedByte: if (numberOfComponents == 1) { return(ReadSignedByte()); } else { return(ToArray(dataType, length, ReadSignedByte)); } case ExifDataType.SignedLong: if (numberOfComponents == 1) { return(ReadSignedLong()); } else { return(ToArray(dataType, length, ReadSignedLong)); } case ExifDataType.SignedRational: if (numberOfComponents == 1) { return(ReadSignedRational()); } else { return(ToArray(dataType, length, ReadSignedRational)); } case ExifDataType.SignedShort: if (numberOfComponents == 1) { return(ReadSignedShort()); } else { return(ToArray(dataType, length, ReadSignedShort)); } case ExifDataType.SingleFloat: if (numberOfComponents == 1) { return(ReadSingle()); } else { return(ToArray(dataType, length, ReadSingle)); } default: throw new NotSupportedException(); } }
internal ExifValue(ExifTag tag, ExifDataType dataType) { Tag = tag; DataType = dataType; }
private int WriteValue(ExifDataType dataType, object value, byte[] destination, int offset) { switch (dataType) { case ExifDataType.Ascii: return Write(Encoding.UTF8.GetBytes((string)value), destination, offset); case ExifDataType.Byte: case ExifDataType.Undefined: destination[offset] = (byte)value; return offset + 1; case ExifDataType.DoubleFloat: return Write(BitConverter.GetBytes((double)value), destination, offset); case ExifDataType.Short: return Write(BitConverter.GetBytes((ushort)value), destination, offset); case ExifDataType.Long: return Write(BitConverter.GetBytes((uint)value), destination, offset); case ExifDataType.Rational: return WriteRational((double)value, destination, offset); case ExifDataType.SignedByte: destination[offset] = unchecked((byte)((sbyte)value)); return offset + 1; case ExifDataType.SignedLong: return Write(BitConverter.GetBytes((int)value), destination, offset); case ExifDataType.SignedShort: return Write(BitConverter.GetBytes((short)value), destination, offset); case ExifDataType.SignedRational: return WriteSignedRational((double)value, destination, offset); case ExifDataType.SingleFloat: return Write(BitConverter.GetBytes((float)value), destination, offset); default: throw new NotImplementedException(); } }
public void AutoOrient_WorksWithCorruptExifData <TPixel>(TestImageProvider <TPixel> provider, ExifDataType dataType, byte[] orientation) where TPixel : unmanaged, IPixel <TPixel> { var profile = new ExifProfile(); profile.SetValue(ExifTag.JPEGTables, orientation); byte[] bytes = profile.ToByteArray(); // Change the tag into ExifTag.Orientation bytes[16] = 18; bytes[17] = 1; // Change the data type bytes[18] = (byte)dataType; // Change the number of components bytes[20] = 1; var orientationCodeData = new byte[8]; Array.Copy(orientation, orientationCodeData, orientation.Length); ulong orientationCode = BitConverter.ToUInt64(orientationCodeData, 0); using (Image <TPixel> image = provider.GetImage()) using (Image <TPixel> reference = image.Clone()) { image.Metadata.ExifProfile = new ExifProfile(bytes); image.Mutate(x => x.AutoOrient()); image.DebugSave(provider, $"{dataType}-{orientationCode}", appendPixelTypeToFileName: false); ImageComparer.Exact.VerifySimilarity(image, reference); } }
private object ReadValue(ExifDataType dataType, uint numberOfComponents) { switch (dataType) { case ExifDataType.Byte: case ExifDataType.Undefined: if (numberOfComponents == 1) { return(ReadByte()); } else { return(ReadArray(numberOfComponents, ReadByte)); } case ExifDataType.Double: if (numberOfComponents == 1) { return(ReadDouble()); } else { return(ReadArray(numberOfComponents, ReadDouble)); } case ExifDataType.Float: if (numberOfComponents == 1) { return(ReadFloat()); } else { return(ReadArray(numberOfComponents, ReadFloat)); } case ExifDataType.Long: if (numberOfComponents == 1) { return(ReadLong()); } else { return(ReadArray(numberOfComponents, ReadLong)); } case ExifDataType.Rational: if (numberOfComponents == 1) { return(ReadRational()); } else { return(ReadArray(numberOfComponents, ReadRational)); } case ExifDataType.Short: if (numberOfComponents == 1) { return(ReadShort()); } else { return(ReadArray(numberOfComponents, ReadShort)); } case ExifDataType.SignedByte: if (numberOfComponents == 1) { return(ReadSignedByte()); } else { return(ReadArray(numberOfComponents, ReadSignedByte)); } case ExifDataType.SignedLong: if (numberOfComponents == 1) { return(ReadSignedLong()); } else { return(ReadArray(numberOfComponents, ReadSignedLong)); } case ExifDataType.SignedRational: if (numberOfComponents == 1) { return(ReadSignedRational()); } else { return(ReadArray(numberOfComponents, ReadSignedRational)); } case ExifDataType.SignedShort: if (numberOfComponents == 1) { return(ReadSignedShort()); } else { return(ReadArray(numberOfComponents, ReadSignedShort)); } case ExifDataType.String: return(ReadString(numberOfComponents)); default: throw new NotSupportedException(); } }
public static ExifValue Create(ExifTagValue tag, ExifDataType dataType, ulong numberOfComponents) => Create(tag, dataType, numberOfComponents != 1);
internal static ExifByte Create(ExifTag tag, ExifDataType dataType, byte value) => new ExifByte(tag, dataType) { Value = value };
internal ExifByte(ExifTag tag, ExifDataType dataType) : base(tag, dataType) { }
private bool TryReadValue(out ExifValue exifValue) { exifValue = default; // 2 | 2 | 4 | 4 // tag | type | count | value offset if (this.RemainingLength < 12) { return(false); } var tag = (ExifTagValue)this.ReadUInt16(); ExifDataType dataType = EnumUtils.Parse(this.ReadUInt16(), ExifDataType.Unknown); // Ensure that the data type is valid if (dataType == ExifDataType.Unknown) { return(false); } uint numberOfComponents = this.ReadUInt32(); // Issue #132: ExifDataType == Undefined is treated like a byte array. // If numberOfComponents == 0 this value can only be handled as an inline value and must fallback to 4 (bytes) if (dataType == ExifDataType.Undefined && numberOfComponents == 0) { numberOfComponents = 4; } uint size = numberOfComponents * ExifDataTypes.GetSize(dataType); this.TryReadSpan(4, out ReadOnlySpan <byte> offsetBuffer); object value; if (size > 4) { int oldIndex = this.position; uint newIndex = this.ConvertToUInt32(offsetBuffer); // Ensure that the new index does not overrun the data if (newIndex > int.MaxValue) { this.AddInvalidTag(new UnkownExifTag(tag)); return(false); } this.position = (int)newIndex; if (this.RemainingLength < size) { this.AddInvalidTag(new UnkownExifTag(tag)); this.position = oldIndex; return(false); } this.TryReadSpan((int)size, out ReadOnlySpan <byte> dataBuffer); value = this.ConvertValue(dataType, dataBuffer, numberOfComponents); this.position = oldIndex; } else { value = this.ConvertValue(dataType, offsetBuffer, numberOfComponents); } exifValue = ExifValues.Create(tag) ?? ExifValues.Create(tag, dataType, numberOfComponents); if (exifValue is null) { this.AddInvalidTag(new UnkownExifTag(tag)); return(false); } if (!exifValue.TrySetValue(value)) { return(false); } return(true); }
public ExifByteArray(ExifTag <byte[]> tag, ExifDataType dataType) : base(tag) => DataType = dataType;
internal ExifValue(ExifTag tag, ExifDataType dataType, object value, bool isArray) : this(tag, dataType, isArray) { _value = value; }
private object ConvertValue(ExifDataType dataType, byte[] data, uint numberOfComponents) { if (data == null || data.Length == 0) { return(null); } switch (dataType) { case ExifDataType.Unknown: return(null); case ExifDataType.Ascii: return(ToString(data)); case ExifDataType.Byte: if (numberOfComponents == 1) { return(ToByte(data)); } else { return(data); } case ExifDataType.DoubleFloat: if (numberOfComponents == 1) { return(ToDouble(data)); } else { return(ToArray(dataType, data, ToDouble)); } case ExifDataType.Long: if (numberOfComponents == 1) { return(ToLong(data)); } else { return(ToArray(dataType, data, ToLong)); } case ExifDataType.Rational: if (numberOfComponents == 1) { return(ToRational(data)); } else { return(ToArray(dataType, data, ToRational)); } case ExifDataType.Short: if (numberOfComponents == 1) { return(ToShort(data)); } else { return(ToArray(dataType, data, ToShort)); } case ExifDataType.SignedByte: if (numberOfComponents == 1) { return(ToSignedByte(data)); } else { return(ToArray(dataType, data, ToSignedByte)); } case ExifDataType.SignedLong: if (numberOfComponents == 1) { return(ToSignedLong(data)); } else { return(ToArray(dataType, data, ToSignedLong)); } case ExifDataType.SignedRational: if (numberOfComponents == 1) { return(ToSignedRational(data)); } else { return(ToArray(dataType, data, ToSignedRational)); } case ExifDataType.SignedShort: if (numberOfComponents == 1) { return(ToSignedShort(data)); } else { return(ToArray(dataType, data, ToSignedShort)); } case ExifDataType.SingleFloat: if (numberOfComponents == 1) { return(ToSingle(data)); } else { return(ToArray(dataType, data, ToSingle)); } case ExifDataType.Undefined: if (numberOfComponents == 1) { return(ToByte(data)); } else { return(data); } default: throw new NotSupportedException(); } }
public void ImageShouldAutoRotateInvalidValues <TPixel>(TestImageProvider <TPixel> provider, ExifDataType dataType, byte[] orientation) where TPixel : struct, IPixel <TPixel> { var profile = new ExifProfile(); profile.SetValue(ExifTag.JPEGTables, orientation); byte[] bytes = profile.ToByteArray(); // Change the tag into ExifTag.Orientation bytes[16] = 18; bytes[17] = 1; // Change the data type bytes[18] = (byte)dataType; // Change the number of components bytes[20] = 1; using (Image <TPixel> image = provider.GetImage()) { image.MetaData.ExifProfile = new ExifProfile(bytes); image.AutoOrient(); } }