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);