diff --git a/IronSoftware.Drawing/IronSoftware.Drawing.Common.Tests/UnitTests/RectangleFunctionality.cs b/IronSoftware.Drawing/IronSoftware.Drawing.Common.Tests/UnitTests/RectangleFunctionality.cs
index 41b2f56..5e96ae8 100644
--- a/IronSoftware.Drawing/IronSoftware.Drawing.Common.Tests/UnitTests/RectangleFunctionality.cs
+++ b/IronSoftware.Drawing/IronSoftware.Drawing.Common.Tests/UnitTests/RectangleFunctionality.cs
@@ -333,6 +333,242 @@ public void CastMaui_RectF_from_Rectangle()
Assert.Equal(215, rect.Right);
Assert.Equal(215, rect.Bottom);
}
+#endif
+ [FactWithAutomaticDisplayName]
+ public void Create_new_RectangleF()
+ {
+ RectangleF RectangleF = new RectangleF();
+ Assert.NotNull(RectangleF);
+ Assert.Equal(0, RectangleF.Width);
+ Assert.Equal(0, RectangleF.Height);
+ Assert.Equal(0, RectangleF.X);
+ Assert.Equal(0, RectangleF.Y);
+
+ RectangleF.Width = 100;
+ RectangleF.Height = 100;
+ RectangleF.X = 25;
+ RectangleF.Y = 50;
+ Assert.Equal(100, RectangleF.Width);
+ Assert.Equal(100, RectangleF.Height);
+ Assert.Equal(25, RectangleF.X);
+ Assert.Equal(50, RectangleF.Y);
+
+ RectangleF = new RectangleF(5, 5, 50, 50);
+ Assert.NotNull(RectangleF);
+ Assert.Equal(50, RectangleF.Width);
+ Assert.Equal(50, RectangleF.Height);
+ Assert.Equal(5, RectangleF.X);
+ Assert.Equal(5, RectangleF.Y);
+ }
+
+ [FactWithAutomaticDisplayName]
+ public void CastRectangleF_to_RectangleF()
+ {
+ System.Drawing.RectangleF RectangleF = new System.Drawing.RectangleF(10, 10, 150, 150);
+ RectangleF Rectangle = RectangleF;
+ Assert.NotNull(Rectangle);
+ Assert.Equal(150, Rectangle.Width);
+ Assert.Equal(150, Rectangle.Height);
+ Assert.Equal(10, Rectangle.X);
+ Assert.Equal(10, Rectangle.Y);
+
+ RectangleF = new System.Drawing.RectangleF(new System.Drawing.Point(15, 15), new System.Drawing.Size(75, 75));
+ Rectangle = RectangleF;
+ Assert.NotNull(Rectangle);
+ Assert.Equal(75, Rectangle.Width);
+ Assert.Equal(75, Rectangle.Height);
+ Assert.Equal(15, Rectangle.X);
+ Assert.Equal(15, Rectangle.Y);
+ }
+
+ [FactWithAutomaticDisplayName]
+ public void CastRectangleF_from_RectangleF()
+ {
+ RectangleF RectangleF = new RectangleF(5, 5, 50, 50);
+
+ System.Drawing.RectangleF Rectangle = RectangleF;
+
+ Assert.NotNull(Rectangle);
+ Assert.Equal(50, Rectangle.Width);
+ Assert.Equal(50, Rectangle.Height);
+ Assert.Equal(5, Rectangle.X);
+ Assert.Equal(5, Rectangle.Y);
+ }
+
+ [FactWithAutomaticDisplayName]
+ public void CastImageSharp_RectangleF_to_RectangleF()
+ {
+ SixLabors.ImageSharp.RectangleF RectangleF = new SixLabors.ImageSharp.RectangleF(10, 10, 150, 150);
+ RectangleF Rectangle = RectangleF;
+ Assert.NotNull(Rectangle);
+ Assert.Equal(150, Rectangle.Width);
+ Assert.Equal(150, Rectangle.Height);
+ Assert.Equal(10, Rectangle.X);
+ Assert.Equal(10, Rectangle.Y);
+
+ RectangleF = new SixLabors.ImageSharp.RectangleF(new SixLabors.ImageSharp.Point(15, 15), new SixLabors.ImageSharp.Size(75, 75));
+ Rectangle = RectangleF;
+ Assert.NotNull(Rectangle);
+ Assert.Equal(75, Rectangle.Width);
+ Assert.Equal(75, Rectangle.Height);
+ Assert.Equal(15, Rectangle.X);
+ Assert.Equal(15, Rectangle.Y);
+ }
+
+ [FactWithAutomaticDisplayName]
+ public void CastImageSharp_RectangleF_from_RectangleF()
+ {
+ RectangleF RectangleF = new RectangleF(5, 5, 50, 50);
+
+ SixLabors.ImageSharp.RectangleF Rectangle = RectangleF;
+
+ Assert.Equal(50, Rectangle.Width);
+ Assert.Equal(50, Rectangle.Height);
+ Assert.Equal(5, Rectangle.X);
+ Assert.Equal(5, Rectangle.Y);
+ }
+
+ [FactWithAutomaticDisplayName]
+ public void CastSKRect_to_RectangleF()
+ {
+ SkiaSharp.SKRect rect = new SkiaSharp.SKRect(50, 100, 150, 25);
+ RectangleF RectangleF = rect;
+ Assert.NotNull(RectangleF);
+ Assert.Equal(100, RectangleF.Width);
+ Assert.Equal(75, RectangleF.Height);
+ Assert.Equal(50, RectangleF.X);
+ Assert.Equal(25, RectangleF.Y);
+
+ rect = new SkiaSharp.SKRect(150, 25, 50, 100);
+ RectangleF = rect;
+ Assert.NotNull(RectangleF);
+ Assert.Equal(100, RectangleF.Width);
+ Assert.Equal(75, RectangleF.Height);
+ Assert.Equal(50, RectangleF.X);
+ Assert.Equal(25, RectangleF.Y);
+
+ rect = SkiaSharp.SKRect.Create(200, 200);
+ RectangleF = rect;
+ Assert.NotNull(RectangleF);
+ Assert.Equal(200, RectangleF.Width);
+ Assert.Equal(200, RectangleF.Height);
+ Assert.Equal(0, RectangleF.X);
+ Assert.Equal(0, RectangleF.Y);
+
+ rect = SkiaSharp.SKRect.Create(15, 15, 200, 200);
+ RectangleF = rect;
+ Assert.NotNull(RectangleF);
+ Assert.Equal(200, RectangleF.Width);
+ Assert.Equal(200, RectangleF.Height);
+ Assert.Equal(15, RectangleF.X);
+ Assert.Equal(15, RectangleF.Y);
+ }
+
+ [FactWithAutomaticDisplayName]
+ public void CastSKRect_from_RectangleF()
+ {
+ RectangleF RectangleF = new RectangleF(50, 25, 50, 50);
+ SkiaSharp.SKRect rect = RectangleF;
+ Assert.Equal(50, rect.Left);
+ Assert.Equal(25, rect.Top);
+ Assert.Equal(100, rect.Right);
+ Assert.Equal(75, rect.Bottom);
+
+ RectangleF = new RectangleF(15, 15, 200, 200);
+ rect = RectangleF;
+ Assert.Equal(15, rect.Left);
+ Assert.Equal(15, rect.Top);
+ Assert.Equal(215, rect.Right);
+ Assert.Equal(215, rect.Bottom);
+ }
+
+ [FactWithAutomaticDisplayName]
+ public void ConvertMeasurementF()
+ {
+ RectangleF pxCropRect = new RectangleF(15, 25, 150, 175);
+ RectangleF mmCropRect = pxCropRect.ConvertTo(MeasurementUnits.Millimeters, 96);
+ Assert.Equal(3.96875f, mmCropRect.X);
+ Assert.Equal(6.61458302f, mmCropRect.Y);
+ Assert.Equal(39.6875f, mmCropRect.Width);
+ Assert.Equal(46.3020821f, mmCropRect.Height);
+ }
+
+#if !NETFRAMEWORK
+
+ [FactWithAutomaticDisplayName]
+ public void CastMaui_Rect_to_RectangleF()
+ {
+ Microsoft.Maui.Graphics.RectF rect = new Microsoft.Maui.Graphics.RectF(50, 100, 150, 25);
+ RectangleF RectangleF = rect;
+ Assert.NotNull(RectangleF);
+ Assert.Equal(150, RectangleF.Width);
+ Assert.Equal(25, RectangleF.Height);
+ Assert.Equal(50, RectangleF.X);
+ Assert.Equal(100, RectangleF.Y);
+
+ rect = new Microsoft.Maui.Graphics.RectF(150, 25, 50, 100);
+ RectangleF = rect;
+ Assert.NotNull(RectangleF);
+ Assert.Equal(50, RectangleF.Width);
+ Assert.Equal(100, RectangleF.Height);
+ Assert.Equal(150, RectangleF.X);
+ Assert.Equal(25, RectangleF.Y);
+ }
+
+ [FactWithAutomaticDisplayName]
+ public void CastMaui_Rect_from_RectangleF()
+ {
+ RectangleF RectangleF = new RectangleF(50, 25, 50, 50);
+ Microsoft.Maui.Graphics.Rect rect = RectangleF;
+ Assert.Equal(50, rect.Left);
+ Assert.Equal(25, rect.Top);
+ Assert.Equal(100, rect.Right);
+ Assert.Equal(75, rect.Bottom);
+
+ RectangleF = new RectangleF(15, 15, 200, 200);
+ rect = RectangleF;
+ Assert.Equal(15, rect.Left);
+ Assert.Equal(15, rect.Top);
+ Assert.Equal(215, rect.Right);
+ Assert.Equal(215, rect.Bottom);
+ }
+ [FactWithAutomaticDisplayName]
+ public void CastMaui_RectF_to_RectangleF()
+ {
+ Microsoft.Maui.Graphics.RectF rect = new Microsoft.Maui.Graphics.RectF(50, 100, 150, 25);
+ RectangleF RectangleF = rect;
+ Assert.NotNull(RectangleF);
+ Assert.Equal(150, RectangleF.Width);
+ Assert.Equal(25, RectangleF.Height);
+ Assert.Equal(50, RectangleF.X);
+ Assert.Equal(100, RectangleF.Y);
+
+ rect = new Microsoft.Maui.Graphics.RectF(150, 25, 50, 100);
+ RectangleF = rect;
+ Assert.NotNull(RectangleF);
+ Assert.Equal(50, RectangleF.Width);
+ Assert.Equal(100, RectangleF.Height);
+ Assert.Equal(150, RectangleF.X);
+ Assert.Equal(25, RectangleF.Y);
+ }
+
+ [FactWithAutomaticDisplayName]
+ public void CastMaui_RectF_from_RectangleF()
+ {
+ RectangleF RectangleF = new RectangleF(50, 25, 50, 50);
+ Microsoft.Maui.Graphics.RectF rect = RectangleF;
+ Assert.Equal(50, rect.Left);
+ Assert.Equal(25, rect.Top);
+ Assert.Equal(100, rect.Right);
+ Assert.Equal(75, rect.Bottom);
+
+ RectangleF = new RectangleF(15, 15, 200, 200);
+ rect = RectangleF;
+ Assert.Equal(15, rect.Left);
+ Assert.Equal(15, rect.Top);
+ Assert.Equal(215, rect.Right);
+ Assert.Equal(215, rect.Bottom);
+ }
#endif
}
}
diff --git a/IronSoftware.Drawing/IronSoftware.Drawing.Common/Rectangle.cs b/IronSoftware.Drawing/IronSoftware.Drawing.Common/Rectangle.cs
index 8b13aae..0670812 100644
--- a/IronSoftware.Drawing/IronSoftware.Drawing.Common/Rectangle.cs
+++ b/IronSoftware.Drawing/IronSoftware.Drawing.Common/Rectangle.cs
@@ -132,6 +132,16 @@ public bool Contains(int x, int y)
return X <= x && x < Right && Y <= y && y < Bottom;
}
+ ///
+ /// Implicitly casts to RectangleF objects from .
+ /// When your .NET Class methods use as parameters and return types, you now automatically support RectangleF as well.
+ ///
+ /// is explicitly cast to a RectangleF.
+ public static implicit operator RectangleF(Rectangle Rectangle)
+ {
+ return new RectangleF(Rectangle.X, Rectangle.Y, Rectangle.Width, Rectangle.Height);
+ }
+
///
/// Implicitly casts System.Drawing.Rectangle objects to .
/// When your .NET Class methods use as parameters and return types, you now automatically support Rectangle as well.
diff --git a/IronSoftware.Drawing/IronSoftware.Drawing.Common/RectangleF.cs b/IronSoftware.Drawing/IronSoftware.Drawing.Common/RectangleF.cs
new file mode 100644
index 0000000..62c7215
--- /dev/null
+++ b/IronSoftware.Drawing/IronSoftware.Drawing.Common/RectangleF.cs
@@ -0,0 +1,245 @@
+using System;
+
+namespace IronSoftware.Drawing
+{
+ ///
+ /// A universally compatible RectangleF for .NET 7, .NET 6, .NET 5, and .NET Core. As well as compatibility with Windows, NanoServer, IIS, macOS, Mobile, Xamarin, iOS, Android, Google Compute, Azure, AWS, and Linux.
+ /// Works nicely with popular Image RectangleF such as System.Drawing.RectangleF, SkiaSharp.SKRect, SixLabors.ImageSharp.RectangleF, Microsoft.Maui.Graphics.Rect.
+ /// Implicit casting means that using this class to input and output RectangleF from public APIs gives full compatibility to all RectangleF type fully supported by Microsoft.
+ ///
+ public class RectangleF
+ {
+ ///
+ /// Construct a new RectangleF.
+ ///
+ ///
+ public RectangleF() { }
+
+ ///
+ /// Construct a new RectangleF.
+ ///
+ /// The x-coordinate of the upper-left corner of this RectangleF
+ /// The y-coordinate of the upper-left corner of this RectangleF
+ /// The width of this RectangleF
+ /// The height of this RectangleF
+ /// The measurement unit of this RectangleF
+ ///
+ public RectangleF(float x, float y, float width, float height, MeasurementUnits units = MeasurementUnits.Pixels)
+ {
+ X = x;
+ Y = y;
+ Width = width;
+ Height = height;
+ Units = units;
+ }
+
+ ///
+ /// The x-coordinate of the upper-left corner of this RectangleF. The default is 0
+ ///
+ public float X { get; set; }
+ ///
+ /// The y-coordinate of the upper-left corner of this RectangleF. The default is 0
+ ///
+ public float Y { get; set; }
+ ///
+ /// The width of this RectangleF. The default is 0
+ ///
+ public float Width { get; set; }
+ ///
+ /// The height of this RectangleF. The default is 0
+ ///
+ public float Height { get; set; }
+ ///
+ /// The measurement unit of this RectangleF. The default is Pixels
+ ///
+ public MeasurementUnits Units
+ {
+ get;
+ set;
+ } = MeasurementUnits.Pixels;
+
+ ///
+ /// Convert this RectangleF to the specified units of measurement using the specified DPI
+ ///
+ /// Unit of measurement
+ /// DPI (Dots per inch) for conversion
+ /// A new RectangleF which uses the desired units of measurement
+ /// Conversion not implemented
+ public RectangleF ConvertTo(MeasurementUnits units, int dpi = 96)
+ {
+ // no conversion
+ if (units == Units)
+ {
+ return this;
+ }
+ // convert mm to pixels
+ if (units == MeasurementUnits.Pixels)
+ {
+ float x = X / 25.4f * dpi;
+ float y = Y / 25.4f * dpi;
+ float width = Width / 25.4f * dpi;
+ float height = Height / 25.4f * dpi;
+ return new RectangleF(x, y, width, height, MeasurementUnits.Pixels);
+ }
+ // convert pixels to mm
+ if (units == MeasurementUnits.Millimeters)
+ {
+ float x = X / dpi * 25.4f;
+ float y = Y / dpi * 25.4f;
+ float width = Width / dpi * 25.4f;
+ float height = Height / dpi * 25.4f;
+ return new RectangleF(x, y, width, height, MeasurementUnits.Millimeters);
+
+ }
+
+ throw new NotImplementedException($"RectangleF conversion from {Units} to {units} is not implemented");
+ }
+
+ ///
+ /// Gets the y-coordinate of the top edge of this .
+ ///
+ public float Top => Y;
+
+ ///
+ /// Gets the x-coordinate of the right edge of this .
+ ///
+ public float Right
+ {
+ get => X + Width;
+ }
+
+ ///
+ /// Gets the y-coordinate of the bottom edge of this .
+ ///
+ public float Bottom
+ {
+ get => Y + Height;
+ }
+
+ ///
+ /// Gets the x-coordinate of the left edge of this .
+ ///
+ public float Left => X;
+
+ ///
+ /// Determines if the specified point is contained within the rectangular region defined by
+ /// this .
+ ///
+ /// The x-coordinate of the given point.
+ /// The y-coordinate of the given point.
+ public bool Contains(int x, int y)
+ {
+ return X <= x && x < Right && Y <= y && y < Bottom;
+ }
+
+ ///
+ /// Implicitly casts System.Drawing.RectangleF objects to .
+ /// When your .NET Class methods use as parameters and return types, you now automatically support RectangleF as well.
+ ///
+ /// System.Drawing.RectangleF will automatically be cast to .
+ public static implicit operator RectangleF(System.Drawing.RectangleF RectangleF)
+ {
+ return new RectangleF(RectangleF.X, RectangleF.Y, RectangleF.Width, RectangleF.Height);
+ }
+
+ ///
+ /// Implicitly casts to System.Drawing.RectangleF objects from .
+ /// When your .NET Class methods use as parameters and return types, you now automatically support RectangleF as well.
+ ///
+ /// is explicitly cast to a System.Drawing.RectangleF.
+ public static implicit operator System.Drawing.RectangleF(RectangleF RectangleF)
+ {
+ return new System.Drawing.RectangleF(RectangleF.X, RectangleF.Y, RectangleF.Width, RectangleF.Height);
+ }
+
+ ///
+ /// Implicitly casts SkiaSharp.SKRect objects to .
+ /// When your .NET Class methods use as parameters and return types, you now automatically support SkiaSharp.SKRect as well.
+ ///
+ /// SkiaSharp.SKRect will automatically be cast to .
+ public static implicit operator RectangleF(SkiaSharp.SKRect sKRect)
+ {
+ SkiaSharp.SKRect standardizedSKRect = sKRect.Standardized;
+ return CreateRectangleF(standardizedSKRect.Left, standardizedSKRect.Top, standardizedSKRect.Right, standardizedSKRect.Bottom);
+ }
+
+ ///
+ /// Implicitly casts to SkiaSharp.SKRect objects from .
+ /// When your .NET Class methods use as parameters and return types, you now automatically support SkiaSharp.SKRect as well.
+ ///
+ /// is explicitly cast to a SkiaSharp.SKRect.
+ public static implicit operator SkiaSharp.SKRect(RectangleF RectangleF)
+ {
+ return SkiaSharp.SKRect.Create(RectangleF.X, RectangleF.Y, RectangleF.Width, RectangleF.Height);
+ }
+
+ ///
+ /// Implicitly casts SixLabors.ImageSharp.RectangleF objects to .
+ /// When your .NET Class methods use as parameters and return types, you now automatically support SixLabors.ImageSharp.RectangleF as well.
+ ///
+ /// SixLabors.ImageSharp.RectangleF will automatically be cast to .
+ public static implicit operator RectangleF(SixLabors.ImageSharp.RectangleF RectangleF)
+ {
+ return new RectangleF(RectangleF.X, RectangleF.Y, RectangleF.Width, RectangleF.Height);
+ }
+
+ ///
+ /// Implicitly casts to SixLabors.ImageSharp.RectangleF objects from .
+ /// When your .NET Class methods use as parameters and return types, you now automatically support SixLabors.ImageSharp.RectangleF as well.
+ ///
+ /// is explicitly cast to a SixLabors.ImageSharp.RectangleF.
+ public static implicit operator SixLabors.ImageSharp.RectangleF(RectangleF RectangleF)
+ {
+ return new SixLabors.ImageSharp.RectangleF(RectangleF.X, RectangleF.Y, RectangleF.Width, RectangleF.Height);
+ }
+
+ ///
+ /// Implicitly casts Microsoft.Maui.Graphics.Rect objects to .
+ /// When your .NET Class methods use as parameters and return types, you now automatically support Microsoft.Maui.Graphics.Rect as well.
+ ///
+ /// Microsoft.Maui.Graphics.Rect will automatically be cast to .
+ public static implicit operator RectangleF(Microsoft.Maui.Graphics.Rect RectangleF)
+ {
+ return new RectangleF((float)RectangleF.X, (float)RectangleF.Y, (float)RectangleF.Width, (float)RectangleF.Height);
+ }
+
+ ///
+ /// Implicitly casts to Microsoft.Maui.Graphics.Rect objects from .
+ /// When your .NET Class methods use as parameters and return types, you now automatically support Microsoft.Maui.Graphics.Rect as well.
+ ///
+ /// is explicitly cast to a Microsoft.Maui.Graphics.Rect.
+ public static implicit operator Microsoft.Maui.Graphics.Rect(RectangleF RectangleF)
+ {
+ return new Microsoft.Maui.Graphics.Rect(RectangleF.X, RectangleF.Y, RectangleF.Width, RectangleF.Height);
+ }
+
+ ///
+ /// Implicitly casts Microsoft.Maui.Graphics.RectF objects to .
+ /// When your .NET Class methods use as parameters and return types, you now automatically support Microsoft.Maui.Graphics.RectF as well.
+ ///
+ /// Microsoft.Maui.Graphics.RectF will automatically be cast to .
+ public static implicit operator RectangleF(Microsoft.Maui.Graphics.RectF RectangleF)
+ {
+ return new RectangleF(RectangleF.X, RectangleF.Y, RectangleF.Width, RectangleF.Height);
+ }
+
+ ///
+ /// Implicitly casts to Microsoft.Maui.Graphics.RectF objects from .
+ /// When your .NET Class methods use as parameters and return types, you now automatically support Microsoft.Maui.Graphics.RectF as well.
+ ///
+ /// is explicitly cast to a Microsoft.Maui.Graphics.RectF.
+ public static implicit operator Microsoft.Maui.Graphics.RectF(RectangleF RectangleF)
+ {
+ return new Microsoft.Maui.Graphics.RectF(RectangleF.X, RectangleF.Y, RectangleF.Width, RectangleF.Height);
+ }
+
+ #region Private Method
+
+ private static RectangleF CreateRectangleF(float left, float top, float right, float bottom)
+ {
+ return new RectangleF(left, top, right - left, bottom - top);
+ }
+
+ #endregion
+ }
+}