diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifTagDescriptionAttribute.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifTagDescriptionAttribute.cs index 845e4ee734..b9bb2ee056 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifTagDescriptionAttribute.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifTagDescriptionAttribute.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; @@ -31,7 +31,8 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif /// public static string GetDescription(ExifTag tag, object value) { - FieldInfo field = tag.GetType().GetTypeInfo().GetDeclaredField(tag.ToString()); + var tagValue = (ExifTagValue)(ushort)tag; + FieldInfo field = tagValue.GetType().GetTypeInfo().GetDeclaredField(tagValue.ToString()); if (field is null) { @@ -42,7 +43,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif { object attributeValue = customAttribute.ConstructorArguments[0].Value; - if (object.Equals(attributeValue, value)) + if (Equals(attributeValue, value)) { return (string)customAttribute.ConstructorArguments[1].Value; } diff --git a/src/ImageSharp/Primitives/Number.cs b/src/ImageSharp/Primitives/Number.cs index f516c83a4e..88974e72b6 100644 --- a/src/ImageSharp/Primitives/Number.cs +++ b/src/ImageSharp/Primitives/Number.cs @@ -3,21 +3,52 @@ using System; using System.Globalization; +using System.Runtime.InteropServices; namespace SixLabors.ImageSharp.Primitives { /// /// Represents an integral number. /// + [StructLayout(LayoutKind.Explicit)] public struct Number : IEquatable, IComparable { - private readonly uint value; + [FieldOffset(0)] + private readonly int signedValue; + + [FieldOffset(0)] + private readonly uint unsignedValue; + + [FieldOffset(4)] + private readonly bool isSigned; + + /// + /// Initializes a new instance of the struct. + /// + /// The value of the number. + public Number(int value) + : this() + { + this.signedValue = value; + this.isSigned = true; + } /// /// Initializes a new instance of the struct. /// /// The value of the number. - public Number(uint value) => this.value = value; + public Number(uint value) + : this() + { + this.unsignedValue = value; + this.isSigned = false; + } + + /// + /// Converts the specified to an instance of this type. + /// + /// The value. + public static implicit operator Number(int value) => new Number(value); /// /// Converts the specified to an instance of this type. @@ -29,19 +60,40 @@ namespace SixLabors.ImageSharp.Primitives /// Converts the specified to an instance of this type. /// /// The value. - public static implicit operator Number(ushort value) => new Number(value); + public static implicit operator Number(ushort value) => new Number((uint)value); + + /// + /// Converts the specified to a . + /// + /// The to convert. + public static explicit operator int(Number number) + { + return number.isSigned + ? number.signedValue + : (int)number.unsignedValue.Clamp(0, int.MaxValue); + } /// /// Converts the specified to a . /// /// The to convert. - public static explicit operator uint(Number number) => number.value; + public static explicit operator uint(Number number) + { + return number.isSigned + ? (uint)number.signedValue.Clamp(0, int.MaxValue) + : number.unsignedValue; + } /// /// Converts the specified to a . /// /// The to convert. - public static explicit operator ushort(Number number) => (ushort)number.value; + public static explicit operator ushort(Number number) + { + return number.isSigned + ? (ushort)number.signedValue.Clamp(ushort.MinValue, ushort.MaxValue) + : (ushort)number.unsignedValue.Clamp(ushort.MinValue, ushort.MaxValue); + } /// /// Determines whether the specified instances are considered equal. @@ -86,16 +138,36 @@ namespace SixLabors.ImageSharp.Primitives public static bool operator <=(Number left, Number right) => left.CompareTo(right) <= 0; /// - public int CompareTo(Number other) => this.value.CompareTo(other.value); + public int CompareTo(Number other) + { + return this.isSigned + ? this.signedValue.CompareTo(other.signedValue) + : this.unsignedValue.CompareTo(other.unsignedValue); + } /// public override bool Equals(object obj) => obj is Number other && this.Equals(other); /// - public bool Equals(Number other) => this.value.Equals(other.value); + public bool Equals(Number other) + { + if (this.isSigned != other.isSigned) + { + return false; + } + + return this.isSigned + ? this.signedValue.Equals(other.signedValue) + : this.unsignedValue.Equals(other.unsignedValue); + } /// - public override int GetHashCode() => this.value.GetHashCode(); + public override int GetHashCode() + { + return this.isSigned + ? this.signedValue.GetHashCode() + : this.unsignedValue.GetHashCode(); + } /// public override string ToString() => this.ToString(CultureInfo.InvariantCulture); @@ -105,6 +177,11 @@ namespace SixLabors.ImageSharp.Primitives /// /// An object that supplies culture-specific formatting information. /// The string representation of the value of this instance, which consists of a sequence of digits ranging from 0 to 9, without a sign or leading zeros. - public string ToString(IFormatProvider provider) => this.value.ToString(provider); + public string ToString(IFormatProvider provider) + { + return this.isSigned + ? this.signedValue.ToString(provider) + : this.unsignedValue.ToString(provider); + } } } diff --git a/src/ImageSharp/Processing/Processors/Transforms/TransformProcessorHelpers.cs b/src/ImageSharp/Processing/Processors/Transforms/TransformProcessorHelpers.cs index 7520730737..abc8c9d430 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/TransformProcessorHelpers.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/TransformProcessorHelpers.cs @@ -29,12 +29,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms // Only set the value if it already exists. if (profile.GetValue(ExifTag.PixelXDimension) != null) { - profile.SetValue(ExifTag.PixelXDimension, new Number((uint)image.Width)); + profile.SetValue(ExifTag.PixelXDimension, image.Width); } if (profile.GetValue(ExifTag.PixelYDimension) != null) { - profile.SetValue(ExifTag.PixelYDimension, new Number((uint)image.Height)); + profile.SetValue(ExifTag.PixelYDimension, image.Height); } } } diff --git a/tests/ImageSharp.Tests/Processing/Transforms/TransformsHelpersTest.cs b/tests/ImageSharp.Tests/Processing/Transforms/TransformsHelpersTest.cs index e2a6a1204a..9f8034fa37 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/TransformsHelpersTest.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/TransformsHelpersTest.cs @@ -19,8 +19,8 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms { var profile = new ExifProfile(); img.Metadata.ExifProfile = profile; - profile.SetValue(ExifTag.PixelXDimension, (uint)xy + ushort.MaxValue); - profile.SetValue(ExifTag.PixelYDimension, (uint)xy + ushort.MaxValue); + profile.SetValue(ExifTag.PixelXDimension, xy + ushort.MaxValue); + profile.SetValue(ExifTag.PixelYDimension, xy + ushort.MaxValue); Assert.Equal(ExifDataType.Long, profile.GetValue(ExifTag.PixelXDimension).DataType); Assert.Equal(ExifDataType.Long, profile.GetValue(ExifTag.PixelYDimension).DataType);