diff --git a/IronSoftware.Drawing/IronSoftware.Drawing.Common/Bitmap.cs b/IronSoftware.Drawing/IronSoftware.Drawing.Common/AnyBitmap.cs similarity index 62% rename from IronSoftware.Drawing/IronSoftware.Drawing.Common/Bitmap.cs rename to IronSoftware.Drawing/IronSoftware.Drawing.Common/AnyBitmap.cs index b711cb8..1d2dc53 100644 --- a/IronSoftware.Drawing/IronSoftware.Drawing.Common/Bitmap.cs +++ b/IronSoftware.Drawing/IronSoftware.Drawing.Common/AnyBitmap.cs @@ -10,10 +10,34 @@ namespace IronSoftware.Drawing /// Implicit casting means that using this class to input and output Bitmap and image types from public API's gives full compatibility to all image type fully supported by Microsoft. /// Unlike System.Drawing.Bitmap this bitmap object is self memory managing and does not need to be explicitly 'used' or 'disposed' /// - public partial class Bitmap + public partial class AnyBitmap { private byte[] Binary { get; set; } + /// + /// Width of the image. + /// + public int Width + { + get + { + SkiaSharp.SKBitmap sKBitmap = SkiaSharp.SKBitmap.Decode(Binary); + return sKBitmap.Width; + } + } + + /// + /// Height of the image. + /// + public int Height + { + get + { + SkiaSharp.SKBitmap sKBitmap = SkiaSharp.SKBitmap.Decode(Binary); + return sKBitmap.Height; + } + } + /// /// Number of raw image bytes stored /// @@ -26,16 +50,16 @@ public int Length } /// - /// Allows Comparability and equality. + /// Allows Comparability and equality. /// - /// Another + /// Another /// True if the Bitmaps have exactly the same raw binary data. public override bool Equals(object bitmap) { - Bitmap comp = bitmap as Bitmap; + AnyBitmap comp = bitmap as AnyBitmap; if (comp == null) { return false; } - return Binary == ((Bitmap)bitmap).ExportBytes(); + return Binary == ((AnyBitmap)bitmap).ExportBytes(); } /// @@ -76,12 +100,12 @@ public System.IO.MemoryStream GetStream() } /// - /// Creates an exact duplicate + /// Creates an exact duplicate /// /// - public Bitmap Clone() + public AnyBitmap Clone() { - return new Bitmap(this.Binary); + return new AnyBitmap(this.Binary); } /// @@ -89,8 +113,8 @@ public Bitmap Clone() /// Add SkiaSharp, System.Drawing.Common or SixLabors.ImageSharp to your project to enable this feature. /// /// An image encoding format. - /// Jped and WebP encoding quality (ignored for all other values of ). Higher values return larger file sizes. 0 is lowest quality , 100 is highest. - /// Transcoded image bytes.[ + /// Jped and WebP encoding quality (ignored for all other values of ). Higher values return larger file sizes. 0 is lowest quality , 100 is highest. + /// Transcoded image bytes. public byte[] ExportBytes(ImageFormat Format = ImageFormat.Default, int Lossy = 100) { using var mem = new System.IO.MemoryStream(); @@ -102,10 +126,10 @@ public byte[] ExportBytes(ImageFormat Format = ImageFormat.Default, int Lossy = /// Exports the Bitmap as a file encoded in the of your choice. /// Add SkiaSharp, System.Drawing.Common or SixLabors.ImageSharp to your project to enable the encoding feature. /// - /// A fully qualified file path + /// A fully qualified file path. /// An image encoding format. - /// Jpeg and WebP encoding quality (ignored for all other values of ). Higher values return larger file sizes. 0 is lowest quality , 100 is highest. - /// Void. Saves a file to disk.[ + /// Jpeg and WebP encoding quality (ignored for all other values of ). Higher values return larger file sizes. 0 is lowest quality, 100 is highest. + /// Void. Saves a file to disk. public void ExportFile(string File, ImageFormat Format = ImageFormat.Default, int Lossy = 100) { @@ -120,7 +144,7 @@ public void ExportFile(string File, ImageFormat Format = ImageFormat.Default, in /// Add SkiaSharp, System.Drawing.Common or SixLabors.ImageSharp to your project to enable the encoding feature. /// /// An image encoding format. - /// Jped and WebP encoding quality (ignored for all other values of ). Higher values return larger file sizes. 0 is lowest quality , 100 is highest. + /// Jped and WebP encoding quality (ignored for all other values of ). Higher values return larger file sizes. 0 is lowest quality, 100 is highest. /// Transcoded image bytes in a . public System.IO.MemoryStream ToStream(ImageFormat Format = ImageFormat.Default, int Lossy = 100) { @@ -135,8 +159,8 @@ public System.IO.MemoryStream ToStream(ImageFormat Format = ImageFormat.Default, /// /// An image encoding format. /// An image encoding format. - /// Jpeg and WebP encoding quality (ignored for all other values of ). Higher values return larger file sizes. 0 is lowest quality , 100 is highest. - /// Void. Saves Transcoded image bytes to you . + /// Jpeg and WebP encoding quality (ignored for all other values of ). Higher values return larger file sizes. 0 is lowest quality, 100 is highest. + /// Void. Saves Transcoded image bytes to you . public void ExportStream(System.IO.Stream Stream, ImageFormat Format = ImageFormat.Default, int Lossy = 100) { if (Format == ImageFormat.Default) @@ -158,6 +182,7 @@ public void ExportStream(System.IO.Stream Stream, ImageFormat Format = ImageForm skdata.SaveTo(Stream); return; } +#if NETSTANDARD else if (Type.GetType("SixLabors.ImageSharp.Image") != null) { using SixLabors.ImageSharp.Image img = this; // magic implicit cast @@ -174,9 +199,10 @@ public void ExportStream(System.IO.Stream Stream, ImageFormat Format = ImageForm default: enc = new SixLabors.ImageSharp.Formats.Bmp.BmpEncoder(); break; } - img.Save(Stream, enc); + img.Save(Stream, enc); return; } +#endif else if (Type.GetType("System.Drawing.Imaging.ImageFormat") != null) { using System.Drawing.Bitmap img = (System.Drawing.Bitmap)this; // magic implicit cast @@ -188,7 +214,8 @@ public void ExportStream(System.IO.Stream Stream, ImageFormat Format = ImageForm case ImageFormat.Gif: exportFormat = System.Drawing.Imaging.ImageFormat.Gif; break; case ImageFormat.Png: exportFormat = System.Drawing.Imaging.ImageFormat.Png; break; case ImageFormat.Tiff: exportFormat = System.Drawing.Imaging.ImageFormat.Tiff; break; - + case ImageFormat.Wmf: exportFormat = System.Drawing.Imaging.ImageFormat.Wmf; break; + case ImageFormat.Icon: exportFormat = System.Drawing.Imaging.ImageFormat.Icon; break; default: exportFormat = System.Drawing.Imaging.ImageFormat.Bmp; break; } @@ -218,7 +245,7 @@ public void ExportStream(System.IO.Stream Stream, ImageFormat Format = ImageForm /// Saves the raw image data to a file. /// /// A fully qualified file path. - /// + /// public void SaveAs(string File) { System.IO.File.WriteAllBytes(File, Binary); @@ -226,14 +253,14 @@ public void SaveAs(string File) /// /// Saves the image data to a file. Allows for the image to be transcoded to popular image formats. - /// Add SkiaSharp, System.Drawing.Common or SixLabors.ImageSharp to your project to enable the encoding feature. + /// Add SkiaSharp, System.Drawing.Common or SixLabors.ImageSharp to your project to enable the encoding feature. /// /// A fully qualified file path. /// An image encoding format. - /// Jpeg and WebP encoding quality (ignored for all other values of ). Higher values return larger file sizes. 0 is lowest quality , 100 is highest. + /// Jpeg and WebP encoding quality (ignored for all other values of ). Higher values return larger file sizes. 0 is lowest quality , 100 is highest. /// Void. Saves Transcoded image bytes to your File. /// - /// + /// public void SaveAs(string File, ImageFormat Format, int Lossy = 100) { System.IO.File.WriteAllBytes(File, Binary); @@ -241,11 +268,11 @@ public void SaveAs(string File, ImageFormat Format, int Lossy = 100) /// /// Tries to Save the image data to a file. Allows for the image to be transcoded to popular image formats. - /// Add SkiaSharp, System.Drawing.Common or SixLabors.ImageSharp to your project to enable the encoding feature. + /// Add SkiaSharp, System.Drawing.Common or SixLabors.ImageSharp to your project to enable the encoding feature. /// /// A fully qualified file path. /// An image encoding format. - /// Jpeg and WebP encoding quality (ignored for all other values of ). Higher values return larger file sizes. 0 is lowest quality , 100 is highest. + /// Jpeg and WebP encoding quality (ignored for all other values of ). Higher values return larger file sizes. 0 is lowest quality , 100 is highest. /// returns true on success, false on failure. /// public bool TrySaveAs(string File, ImageFormat Format, int Lossy = 100) @@ -263,11 +290,11 @@ public bool TrySaveAs(string File, ImageFormat Format, int Lossy = 100) } /// - /// Tries to Save the raw image data to a file. - /// returns true on success, false on failure. + /// Tries to Save the raw image data to a file. + /// returns true on success, false on failure. /// /// A fully qualified file path. - /// + /// public bool TrySaveAs(string File) { try @@ -283,18 +310,18 @@ public bool TrySaveAs(string File) } /// - /// Generic method to convert popular image types to . - /// Support includes SixLabors.ImageSharp.Image, SkiaSharp.SKImage, SkiaSharp.SKBitmap, System.Drawing.Bitmap, System.Drawing.Image and Microsoft.Maui.Graphics formats. - /// Syntax sugar. Explicit casts already also exist to and from and all supported types. + /// Generic method to convert popular image types to . + /// Support includes SixLabors.ImageSharp.Image, SkiaSharp.SKImage, SkiaSharp.SKBitmap, System.Drawing.Bitmap, System.Drawing.Image and Microsoft.Maui.Graphics formats. + /// Syntax sugar. Explicit casts already also exist to and from and all supported types. /// - /// The Type to cast from. Support includes SixLabors.ImageSharp.Image, SkiaSharp.SKImage, SkiaSharp.SKBitmap, System.Drawing.Bitmap, System.Drawing.Image and Microsoft.Maui.Graphics formats. + /// The Type to cast from. Support includes SixLabors.ImageSharp.Image, SkiaSharp.SKImage, SkiaSharp.SKBitmap, System.Drawing.Bitmap, System.Drawing.Image and Microsoft.Maui.Graphics formats. /// A bitmap or image format from another graphics library. - /// A - public static Bitmap FromBitmap(T OtherBitmapFormat) + /// A + public static AnyBitmap FromBitmap(T OtherBitmapFormat) { try { - Bitmap result = (Bitmap)Convert.ChangeType(OtherBitmapFormat, typeof(Bitmap)); + AnyBitmap result = (AnyBitmap)Convert.ChangeType(OtherBitmapFormat, typeof(AnyBitmap)); return result; } catch (Exception e) @@ -303,13 +330,12 @@ public static Bitmap FromBitmap(T OtherBitmapFormat) } } /// - /// Generic method to convert to popular image types. - /// Support includes SixLabors.ImageSharp.Image, SkiaSharp.SKImage, SkiaSharp.SKBitmap, System.Drawing.Bitmap, System.Drawing.Image and Microsoft.Maui.Graphics formats. - /// Syntax sugar. Explicit casts already also exist to and from and all supported types. + /// Generic method to convert to popular image types. + /// Support includes SixLabors.ImageSharp.Image, SkiaSharp.SKImage, SkiaSharp.SKBitmap, System.Drawing.Bitmap, System.Drawing.Image and Microsoft.Maui.Graphics formats. + /// Syntax sugar. Explicit casts already also exist to and from and all supported types. /// - /// The Type to cast to. Support includes SixLabors.ImageSharp.Image, SkiaSharp.SKImage, SkiaSharp.SKBitmap, System.Drawing.Bitmap, System.Drawing.Image and Microsoft.Maui.Graphics formats. - - /// A + /// The Type to cast to. Support includes SixLabors.ImageSharp.Image, SkiaSharp.SKImage, SkiaSharp.SKBitmap, System.Drawing.Bitmap, System.Drawing.Image and Microsoft.Maui.Graphics formats. + /// A public T ToBitmap() { try @@ -326,43 +352,43 @@ public T ToBitmap() /// /// Create a new Bitmap from a a Byte Array. /// - /// A ByteArray of image data in any common format/ + /// A ByteArray of image data in any common format. /// - /// - public static Bitmap FromBytes(byte[] Bytes) + /// + public static AnyBitmap FromBytes(byte[] Bytes) { - return new Bitmap(Bytes); + return new AnyBitmap(Bytes); } /// - /// Construct a new Bitmap from binary data (bytes) + /// Construct a new Bitmap from binary data (bytes). /// - /// A ByteArray of image data in any common format/ + /// A ByteArray of image data in any common format. /// - /// + /// - public Bitmap(byte[] Bytes) + public AnyBitmap(byte[] Bytes) { Binary = Bytes; } /// - /// Create a new Bitmap from a (bytes) + /// Create a new Bitmap from a (bytes). /// - /// A of image data in any common format/ + /// A of image data in any common format. /// - /// - public static Bitmap FromStream(System.IO.Stream Stream) + /// + public static AnyBitmap FromStream(System.IO.Stream Stream) { - return new Bitmap(Stream); + return new AnyBitmap(Stream); } /// - /// Construct a new Bitmap from a (bytes) + /// Construct a new Bitmap from a (bytes). /// - /// A of image data in any common format/ + /// A of image data in any common format. /// - /// - public Bitmap(System.IO.Stream Stream) + /// + public AnyBitmap(System.IO.Stream Stream) { using (System.IO.MemoryStream ms = new System.IO.MemoryStream()) { @@ -371,127 +397,135 @@ public Bitmap(System.IO.Stream Stream) } /// - /// Create a new Bitmap from a file. (bytes) + /// Create a new Bitmap from a file. /// - /// A fully qualified file path./ - /// - /// /// - public static Bitmap FromFile(string File) + /// A fully qualified file path. + /// + /// + public static AnyBitmap FromFile(string File) { - return new Bitmap(File); + return new AnyBitmap(File); } /// - /// Construct a new Bitmap from a file. (bytes) + /// Construct a new Bitmap from a file. /// /// A fully qualified file path./ - /// - /// /// - public Bitmap(string File) + /// + /// + public AnyBitmap(string File) { Binary = System.IO.File.ReadAllBytes(File); } +#if NETSTANDARD /// - /// Implicitly casts ImageSharp objects to . - /// When your .NET Class methods to use as parameters and return types, you now automatically support ImageSharp as well. + /// Implicitly casts ImageSharp objects to . + /// When your .NET Class methods use as parameters and return types, you now automatically support ImageSharp as well. /// - /// SixLabors.ImageSharp.Image will automatically be cast to - public static implicit operator Bitmap(SixLabors.ImageSharp.Image Image) + /// SixLabors.ImageSharp.Image will automatically be cast to . + public static implicit operator AnyBitmap(SixLabors.ImageSharp.Image Image) { using (var memoryStream = new System.IO.MemoryStream()) { Image.Save(memoryStream, new SixLabors.ImageSharp.Formats.Bmp.BmpEncoder()); - return new Bitmap(memoryStream.ToArray()); + return new AnyBitmap(memoryStream.ToArray()); } } - /// - /// Implicitly casts ImageSharp objects from . - /// When your .NET Class methods to use as parameters and return types, you now automatically support ImageSharp as well. + /// Implicitly casts ImageSharp objects from . + /// When your .NET Class methods use as parameters and return types, you now automatically support ImageSharp as well. /// - /// is Implicitly cast to an SixLabors.ImageSharp.Image - static public implicit operator SixLabors.ImageSharp.Image(Bitmap bitmap) + /// is implicitly cast to a SixLabors.ImageSharp.Image. + static public implicit operator SixLabors.ImageSharp.Image(AnyBitmap bitmap) { return SixLabors.ImageSharp.Image.Load(bitmap.Binary); } - + +#endif /// - /// Implicitly casts SkiaSharp.SKImage objects to . - /// When your .NET Class methods to use as parameters and return types, you now automatically support SkiaSharp as well. + /// Implicitly casts SkiaSharp.SKImage objects to . + /// When your .NET Class methods use as parameters and return types, you now automatically support SkiaSharp as well. /// - /// SkiaSharp.SKImage will automatically be cast to - public static implicit operator Bitmap(SkiaSharp.SKImage Image) + /// SkiaSharp.SKImage will automatically be cast to . + public static implicit operator AnyBitmap(SkiaSharp.SKImage Image) { - return new Bitmap(SkiaSharp.SKBitmap.FromImage(Image).Encode(SkiaSharp.SKEncodedImageFormat.Bmp, 100).ToArray()); +#if NETFRAMEWORK + return new AnyBitmap(SkiaSharp.SKBitmap.FromImage(Image).Bytes); +#else + return new AnyBitmap(SkiaSharp.SKBitmap.FromImage(Image).Encode(SkiaSharp.SKEncodedImageFormat.Bmp, 100).ToArray()); +#endif } /// - /// Implicitly casts SkiaSharp.SKImage objects from . - /// When your .NET Class methods to use as parameters and return types, you now automatically support SkiaSharp.SKImage as well. + /// Implicitly casts SkiaSharp.SKImage objects from . + /// When your .NET Class methods use as parameters and return types, you now automatically support SkiaSharp.SKImage as well. /// - /// is Implicitly cast to an SkiaSharp.SKImage - static public implicit operator SkiaSharp.SKImage(Bitmap bitmap) + /// is implicitly cast to an SkiaSharp.SKImage. + static public implicit operator SkiaSharp.SKImage(AnyBitmap bitmap) { return SkiaSharp.SKImage.FromBitmap(SkiaSharp.SKBitmap.Decode(bitmap.Binary)); } - /// - /// Implicitly casts SkiaSharp.SKBitmap objects to . - /// When your .NET Class methods to use as parameters and return types, you now automatically support SkiaSharp as well. + /// Implicitly casts SkiaSharp.SKBitmap objects to . + /// When your .NET Class methods use as parameters and return types, you now automatically support SkiaSharp as well. /// - /// SkiaSharp.SKBitmap will automatically be cast to + /// SkiaSharp.SKBitmap will automatically be cast to . - public static implicit operator Bitmap(SkiaSharp.SKBitmap Image) + public static implicit operator AnyBitmap(SkiaSharp.SKBitmap Image) { - return new Bitmap(Image.Encode(SkiaSharp.SKEncodedImageFormat.Bmp, 100).ToArray()); +#if NETFRAMEWORK + return new AnyBitmap(Image.Bytes); +#else + return new AnyBitmap(Image.Encode(SkiaSharp.SKEncodedImageFormat.Bmp, 100).ToArray()); +#endif } /// - /// Implicitly casts SkiaSharp.SKBitmap objects from . - /// When your .NET Class methods to use as parameters and return types, you now automatically support SkiaSharp.SKBitmap as well. + /// Implicitly casts SkiaSharp.SKBitmap objects from . + /// When your .NET Class methods use as parameters and return types, you now automatically support SkiaSharp.SKBitmap as well. /// - /// is explicitly cast to an SkiaSharp.SKBitmap - static public implicit operator SkiaSharp.SKBitmap(Bitmap bitmap) + /// is explicitly cast to an SkiaSharp.SKBitmap. + static public implicit operator SkiaSharp.SKBitmap(AnyBitmap bitmap) { return SkiaSharp.SKBitmap.Decode(bitmap.Binary); } - +#if NETSTANDARD /// - /// Implicitly casts Microsoft.Maui.Graphics.Platform.PlatformImage objects to . - /// When your .NET Class methods to use as parameters and return types, you now automatically support Microsoft.Maui.Graphics as well. + /// Implicitly casts Microsoft.Maui.Graphics.Platform.PlatformImage objects to . + /// When your .NET Class methods use as parameters and return types, you now automatically support Microsoft.Maui.Graphics as well. /// - /// Microsoft.Maui.Graphics.Platform.PlatformImage will automatically be cast to + /// Microsoft.Maui.Graphics.Platform.PlatformImage will automatically be cast to . - public static implicit operator Bitmap(Microsoft.Maui.Graphics.Platform.PlatformImage Image) + public static implicit operator AnyBitmap(Microsoft.Maui.Graphics.Platform.PlatformImage Image) { using (var memoryStream = new System.IO.MemoryStream()) { Image.Save(memoryStream); - return new Bitmap(memoryStream.ToArray()); + return new AnyBitmap(memoryStream.ToArray()); } } /// - /// Implicitly casts Microsoft.Maui.Graphics.Platform.PlatformImage objects from . - /// When your .NET Class methods to use as parameters and return types, you now automatically support Microsoft.Maui.Graphics as well. + /// Implicitly casts Microsoft.Maui.Graphics.Platform.PlatformImage objects from . + /// When your .NET Class methods use as parameters and return types, you now automatically support Microsoft.Maui.Graphics as well. /// - /// is Implicitly cast to an Microsoft.Maui.Graphics.Platform.PlatformImage + /// is implicitly cast to an Microsoft.Maui.Graphics.Platform.PlatformImage. - static public implicit operator Microsoft.Maui.Graphics.Platform.PlatformImage(Bitmap bitmap) + static public implicit operator Microsoft.Maui.Graphics.Platform.PlatformImage(AnyBitmap bitmap) { return (Microsoft.Maui.Graphics.Platform.PlatformImage)Microsoft.Maui.Graphics.Platform.PlatformImage.FromStream(bitmap.GetStream()); } - +#endif /// - /// Implicitly casts System.Drawing.Bitmap objects to . - /// When your .NET Class methods to use as parameters and return types, you now automatically support System.Drawing.Common as well. + /// Implicitly casts System.Drawing.Bitmap objects to . + /// When your .NET Class methods use as parameters and return types, you now automatically support System.Drawing.Common as well. /// - /// System.Drawing.Bitmap will automatically be cast to + /// System.Drawing.Bitmap will automatically be cast to - public static implicit operator Bitmap(System.Drawing.Bitmap Image) + public static implicit operator AnyBitmap(System.Drawing.Bitmap Image) { Byte[] data; @@ -502,30 +536,32 @@ public static implicit operator Bitmap(System.Drawing.Bitmap Image) Image.Save(memoryStream, System.Drawing.Imaging.ImageFormat.Bmp); data = memoryStream.ToArray(); - return new Bitmap(data); + return new AnyBitmap(data); } } catch (Exception e) { if (e is PlatformNotSupportedException || e is TypeInitializationException) { +#if NETSTANDARD if (!System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows)) { throw SystemDotDrawingPlatformNotSupported(e); } +#endif } throw e; } } /// - /// Implicitly casts System.Drawing.Bitmap objects from . - /// When your .NET Class methods to use as parameters and return types, you now automatically support System.Drawing.Common as well. + /// Implicitly casts System.Drawing.Bitmap objects from . + /// When your .NET Class methods use as parameters and return types, you now automatically support System.Drawing.Common as well. /// - /// is implicitly cast to an System.Drawing.Bitmap + /// is implicitly cast to an System.Drawing.Bitmap. - static public implicit operator System.Drawing.Bitmap(Bitmap bitmap) + static public implicit operator System.Drawing.Bitmap(AnyBitmap bitmap) { try { @@ -535,10 +571,12 @@ static public implicit operator System.Drawing.Bitmap(Bitmap bitmap) { if (e is PlatformNotSupportedException || e is TypeInitializationException) { +#if NETSTANDARD if (!System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows)) { throw SystemDotDrawingPlatformNotSupported(e); } +#endif } throw e; } @@ -546,21 +584,21 @@ static public implicit operator System.Drawing.Bitmap(Bitmap bitmap) private static PlatformNotSupportedException SystemDotDrawingPlatformNotSupported(Exception innerException) { - return new PlatformNotSupportedException("Microsoft has chosen to no longer support System.Drawing.Common on Linux or MacOS. To solve this please use another Bitmap type such as {typeof(Bitmap).ToString()}, SkiaSharp or ImageSharp.\n\nhttps://docs.microsoft.com/en-us/dotnet/core/compatibility/core-libraries/6.0/system-drawing-common-windows-only", innerException); + return new PlatformNotSupportedException("Microsoft has chosen to no longer support System.Drawing.Common on Linux or MacOS. To solve this please use another Bitmap type such as {typeof(Bitmap).ToString()}, SkiaSharp or ImageSharp.\n\nhttps://docs.microsoft.com/en-us/dotnet/core/compatibility/core-libraries/6.0/system-drawing-common-windows-only", innerException); } private static InvalidCastException ImageCastException(string fullTypeName, Exception innerException) { - return new InvalidCastException($"IronSoftware.Drawing does not yet support casting {fullTypeName} to {typeof(Bitmap).FullName}. Try using System.Drawing.Common, SkiaSharp or ImageSharp.", innerException); + return new InvalidCastException($"IronSoftware.Drawing does not yet support casting {fullTypeName} to {typeof(AnyBitmap).FullName}. Try using System.Drawing.Common, SkiaSharp or ImageSharp.", innerException); } private static InvalidOperationException NoConverterException(ImageFormat Format, Exception innerException) { - return new InvalidOperationException($"{typeof(Bitmap)} is unable to convert your image data to {Format.ToString()} because it requires a suitable encoder to be added to your project via Nuget.\nPlease try SkiaSharp, System.Drawing.Common, SixLabors.ImageSharp, Microsoft.Maui.Graphics; or alternatively save using ImageFormat.Default", innerException); + return new InvalidOperationException($"{typeof(AnyBitmap)} is unable to convert your image data to {Format.ToString()} because it requires a suitable encoder to be added to your project via Nuget.\nPlease try SkiaSharp, System.Drawing.Common, SixLabors.ImageSharp, Microsoft.Maui.Graphics; or alternatively save using ImageFormat.Default", innerException); } /// - /// Popular image formats which can read and export. + /// Popular image formats which can read and export. /// /// /// @@ -581,13 +619,19 @@ public enum ImageFormat /// The PNG image format. Png = 4, - /// The WBMP image format. Will default to BMP if not supported on the runtime platform.. + /// The WBMP image format. Will default to BMP if not supported on the runtime platform. Wbmp = 5, /// The new WebP image format. Webp = 6, + /// The Icon image format. + Icon = 7, + + /// The Wmf image format. + Wmf = 8, + /// The existing raw image format. Default = -1, } diff --git a/IronSoftware.Drawing/IronSoftware.Drawing.Common/Color.cs b/IronSoftware.Drawing/IronSoftware.Drawing.Common/Color.cs new file mode 100644 index 0000000..2ca2934 --- /dev/null +++ b/IronSoftware.Drawing/IronSoftware.Drawing.Common/Color.cs @@ -0,0 +1,919 @@ +using System; +using System.Globalization; +using System.Linq; + +namespace IronSoftware.Drawing +{ + public partial class Color + { + + /// + /// Gets the alpha component value of this System.Drawing.Color structure. + /// + /// The alpha component value of this IronSoftware.Drawing.Color. + public byte A { get; internal set; } + + /// + /// Gets the green component value of this System.Drawing.Color structure. + /// + /// The green component value of this IronSoftware.Drawing.Color. + public byte G { get; internal set; } + + /// + /// Gets the blue component value of this System.Drawing.Color structure. + /// + /// The blue component value of this IronSoftware.Drawing.Color. + public byte B { get; internal set; } + + /// + /// Gets the red component value of this System.Drawing.Color structure. + /// + /// The red component value of this IronSoftware.Drawing.Color. + public byte R { get; internal set; } + + internal Color(string colorcode) + { + colorcode = colorcode.TrimStart('#'); + + if (colorcode.Length == 8) + { + this.A = (byte)int.Parse(colorcode.Substring(0, 2), NumberStyles.HexNumber); + this.R = (byte)int.Parse(colorcode.Substring(2, 2), NumberStyles.HexNumber); + this.G = (byte)int.Parse(colorcode.Substring(4, 2), NumberStyles.HexNumber); + this.B = (byte)int.Parse(colorcode.Substring(6, 2), NumberStyles.HexNumber); + } + else if (colorcode.Length == 6) + { + this.A = 255; + this.R = (byte)int.Parse(colorcode.Substring(0, 2), NumberStyles.HexNumber); + this.G = (byte)int.Parse(colorcode.Substring(2, 2), NumberStyles.HexNumber); + this.B = (byte)int.Parse(colorcode.Substring(4, 2), NumberStyles.HexNumber); + } + else if (colorcode.Length == 3) + { + this.A = 255; + this.R = (byte)int.Parse(string.Join("", Enumerable.Repeat(colorcode.Substring(0, 1), 2)), NumberStyles.HexNumber); + this.G = (byte)int.Parse(string.Join("", Enumerable.Repeat(colorcode.Substring(1, 1), 2)), NumberStyles.HexNumber); + this.B = (byte)int.Parse(string.Join("", Enumerable.Repeat(colorcode.Substring(2, 1), 2)), NumberStyles.HexNumber); + } + else + { + throw NoConverterException(colorcode, null); + } + } + + internal Color(int alpha, int red, int green, int blue) + { + this.A = (byte)alpha; + this.R = (byte)red; + this.G = (byte)green; + this.B = (byte)blue; + } + + internal Color(int red, int green, int blue) + { + this.A = 255; + this.R = (byte)red; + this.G = (byte)green; + this.B = (byte)blue; + } + + /// + /// Gets a system-defined color that has an ARGB value of #F0F8FF. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color AliceBlue = new Color("#F0F8FF"); + /// + /// Gets a system-defined color that has an ARGB value of #FAEBD7. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color AntiqueWhite = new Color("#FAEBD7"); + /// + /// Gets a system-defined color that has an ARGB value of #00FFFF. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color Aqua = new Color("#00FFFF"); + /// + /// Gets a system-defined color that has an ARGB value of #7FFFD4. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color Aquamarine = new Color("#7FFFD4"); + /// + /// Gets a system-defined color that has an ARGB value of #F0FFFF. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color Azure = new Color("#F0FFFF"); + /// + /// Gets a system-defined color that has an ARGB value of #F5F5DC. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color Beige = new Color("#F5F5DC"); + /// + /// Gets a system-defined color that has an ARGB value of #FFE4C4. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color Bisque = new Color("#FFE4C4"); + /// + /// Gets a system-defined color that has an ARGB value of #000000. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color Black = new Color("#000000"); + /// + /// Gets a system-defined color that has an ARGB value of #FFEBCD. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color BlanchedAlmond = new Color("#FFEBCD"); + /// + /// Gets a system-defined color that has an ARGB value of #0000FF. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color Blue = new Color("#0000FF"); + /// + /// Gets a system-defined color that has an ARGB value of #8A2BE2. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color BlueViolet = new Color("#8A2BE2"); + /// + /// Gets a system-defined color that has an ARGB value of #A52A2A. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color Brown = new Color("#A52A2A"); + /// + /// Gets a system-defined color that has an ARGB value of #DEB887. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color BurlyWood = new Color("#DEB887"); + /// + /// Gets a system-defined color that has an ARGB value of #5F9EA0. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color CadetBlue = new Color("#5F9EA0"); + /// + /// Gets a system-defined color that has an ARGB value of #7FFF00. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color Chartreuse = new Color("#7FFF00"); + /// + /// Gets a system-defined color that has an ARGB value of #D2691E. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color Chocolate = new Color("#D2691E"); + /// + /// Gets a system-defined color that has an ARGB value of #FF7F50. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color Coral = new Color("#FF7F50"); + /// + /// Gets a system-defined color that has an ARGB value of #6495ED. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color CornflowerBlue = new Color("#6495ED"); + /// + /// Gets a system-defined color that has an ARGB value of #FFF8DC. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color Cornsilk = new Color("#FFF8DC"); + /// + /// Gets a system-defined color that has an ARGB value of #DC143C. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color Crimson = new Color("#DC143C"); + /// + /// Gets a system-defined color that has an ARGB value of #00FFFF. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color Cyan = new Color("#00FFFF"); + /// + /// Gets a system-defined color that has an ARGB value of #00008B. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color DarkBlue = new Color("#00008B"); + /// + /// Gets a system-defined color that has an ARGB value of #008B8B. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color DarkCyan = new Color("#008B8B"); + /// + /// Gets a system-defined color that has an ARGB value of #B8860B. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color DarkGoldenrod = new Color("#B8860B"); + /// + /// Gets a system-defined color that has an ARGB value of #A9A9A9. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color DarkGray = new Color("#A9A9A9"); + /// + /// Gets a system-defined color that has an ARGB value of #006400. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color DarkGreen = new Color("#006400"); + /// + /// Gets a system-defined color that has an ARGB value of #BDB76B. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color DarkKhaki = new Color("#BDB76B"); + /// + /// Gets a system-defined color that has an ARGB value of #8B008B. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color DarkMagenta = new Color("#8B008B"); + /// + /// Gets a system-defined color that has an ARGB value of #556B2F. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color DarkOliveGreen = new Color("#556B2F"); + /// + /// Gets a system-defined color that has an ARGB value of #FF8C00. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color DarkOrange = new Color("#FF8C00"); + /// + /// Gets a system-defined color that has an ARGB value of #9932CC. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color DarkOrchid = new Color("#9932CC"); + /// + /// Gets a system-defined color that has an ARGB value of #8B0000. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color DarkRed = new Color("#8B0000"); + /// + /// Gets a system-defined color that has an ARGB value of #E9967A. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color DarkSalmon = new Color("#E9967A"); + /// + /// Gets a system-defined color that has an ARGB value of #8FBC8B. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color DarkSeaGreen = new Color("#8FBC8B"); + /// + /// Gets a system-defined color that has an ARGB value of #483D8B. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color DarkSlateBlue = new Color("#483D8B"); + /// + /// Gets a system-defined color that has an ARGB value of #2F4F4F. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color DarkSlateGray = new Color("#2F4F4F"); + /// + /// Gets a system-defined color that has an ARGB value of #00CED1. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color DarkTurquoise = new Color("#00CED1"); + /// + /// Gets a system-defined color that has an ARGB value of #9400D3. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color DarkViolet = new Color("#9400D3"); + /// + /// Gets a system-defined color that has an ARGB value of #FF1493. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color DeepPink = new Color("#FF1493"); + /// + /// Gets a system-defined color that has an ARGB value of #00BFFF. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color DeepSkyBlue = new Color("#00BFFF"); + /// + /// Gets a system-defined color that has an ARGB value of #696969. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color DimGray = new Color("#696969"); + /// + /// Gets a system-defined color that has an ARGB value of #1E90FF. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color DodgerBlue = new Color("#1E90FF"); + /// + /// Gets a system-defined color that has an ARGB value of #B22222. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color Firebrick = new Color("#B22222"); + /// + /// Gets a system-defined color that has an ARGB value of #FFFAF0. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color FloralWhite = new Color("#FFFAF0"); + /// + /// Gets a system-defined color that has an ARGB value of #228B22. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color ForestGreen = new Color("#228B22"); + /// + /// Gets a system-defined color that has an ARGB value of #FF00FF. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color Fuchsia = new Color("#FF00FF"); + /// + /// Gets a system-defined color that has an ARGB value of #DCDCDC. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color Gainsboro = new Color("#DCDCDC"); + /// + /// Gets a system-defined color that has an ARGB value of #F8F8FF. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color GhostWhite = new Color("#F8F8FF"); + /// + /// Gets a system-defined color that has an ARGB value of #FFD700. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color Gold = new Color("#FFD700"); + /// + /// Gets a system-defined color that has an ARGB value of #DAA520. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color Goldenrod = new Color("#DAA520"); + /// + /// Gets a system-defined color that has an ARGB value of #808080. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color Gray = new Color("#808080"); + /// + /// Gets a system-defined color that has an ARGB value of #008000. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color Green = new Color("#008000"); + /// + /// Gets a system-defined color that has an ARGB value of #ADFF2F. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color GreenYellow = new Color("#ADFF2F"); + /// + /// Gets a system-defined color that has an ARGB value of #F0FFF0. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color Honeydew = new Color("#F0FFF0"); + /// + /// Gets a system-defined color that has an ARGB value of #FF69B4. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color HotPink = new Color("#FF69B4"); + /// + /// Gets a system-defined color that has an ARGB value of #CD5C5C. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color IndianRed = new Color("#CD5C5C"); + /// + /// Gets a system-defined color that has an ARGB value of #4B0082. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color Indigo = new Color("#4B0082"); + /// + /// Gets a system-defined color that has an ARGB value of #FFFFF0. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color Ivory = new Color("#FFFFF0"); + /// + /// Gets a system-defined color that has an ARGB value of #F0E68C. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color Khaki = new Color("#F0E68C"); + /// + /// Gets a system-defined color that has an ARGB value of #E6E6FA. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color Lavender = new Color("#E6E6FA"); + /// + /// Gets a system-defined color that has an ARGB value of #FFF0F5. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color LavenderBlush = new Color("#FFF0F5"); + /// + /// Gets a system-defined color that has an ARGB value of #7CFC00. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color LawnGreen = new Color("#7CFC00"); + /// + /// Gets a system-defined color that has an ARGB value of #FFFACD. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color LemonChiffon = new Color("#FFFACD"); + /// + /// Gets a system-defined color that has an ARGB value of #ADD8E6. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color LightBlue = new Color("#ADD8E6"); + /// + /// Gets a system-defined color that has an ARGB value of #F08080. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color LightCoral = new Color("#F08080"); + /// + /// Gets a system-defined color that has an ARGB value of #E0FFFF. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color LightCyan = new Color("#E0FFFF"); + /// + /// Gets a system-defined color that has an ARGB value of #FAFAD2. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color LightGoldenrodYellow = new Color("#FAFAD2"); + /// + /// Gets a system-defined color that has an ARGB value of #D3D3D3. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color LightGray = new Color("#D3D3D3"); + /// + /// Gets a system-defined color that has an ARGB value of #90EE90. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color LightGreen = new Color("#90EE90"); + /// + /// Gets a system-defined color that has an ARGB value of #FFB6C1. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color LightPink = new Color("#FFB6C1"); + /// + /// Gets a system-defined color that has an ARGB value of #FFA07A. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color LightSalmon = new Color("#FFA07A"); + /// + /// Gets a system-defined color that has an ARGB value of #20B2AA. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color LightSeaGreen = new Color("#20B2AA"); + /// + /// Gets a system-defined color that has an ARGB value of #87CEFA. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color LightSkyBlue = new Color("#87CEFA"); + /// + /// Gets a system-defined color that has an ARGB value of #778899. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color LightSlateGray = new Color("#778899"); + /// + /// Gets a system-defined color that has an ARGB value of #B0C4DE. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color LightSteelBlue = new Color("#B0C4DE"); + /// + /// Gets a system-defined color that has an ARGB value of #FFFFE0. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color LightYellow = new Color("#FFFFE0"); + /// + /// Gets a system-defined color that has an ARGB value of #00FF00. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color Lime = new Color("#00FF00"); + /// + /// Gets a system-defined color that has an ARGB value of #32CD32. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color LimeGreen = new Color("#32CD32"); + /// + /// Gets a system-defined color that has an ARGB value of #FAF0E6. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color Linen = new Color("#FAF0E6"); + /// + /// Gets a system-defined color that has an ARGB value of #FF00FF. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color Magenta = new Color("#FF00FF"); + /// + /// Gets a system-defined color that has an ARGB value of #800000. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color Maroon = new Color("#800000"); + /// + /// Gets a system-defined color that has an ARGB value of #66CDAA. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color MediumAquamarine = new Color("#66CDAA"); + /// + /// Gets a system-defined color that has an ARGB value of #0000CD. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color MediumBlue = new Color("#0000CD"); + /// + /// Gets a system-defined color that has an ARGB value of #BA55D3. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color MediumOrchid = new Color("#BA55D3"); + /// + /// Gets a system-defined color that has an ARGB value of #9370DB. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color MediumPurple = new Color("#9370DB"); + /// + /// Gets a system-defined color that has an ARGB value of #3CB371. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color MediumSeaGreen = new Color("#3CB371"); + /// + /// Gets a system-defined color that has an ARGB value of #7B68EE. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color MediumSlateBlue = new Color("#7B68EE"); + /// + /// Gets a system-defined color that has an ARGB value of #00FA9A. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color MediumSpringGreen = new Color("#00FA9A"); + /// + /// Gets a system-defined color that has an ARGB value of #48D1CC. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color MediumTurquoise = new Color("#48D1CC"); + /// + /// Gets a system-defined color that has an ARGB value of #C71585. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color MediumVioletRed = new Color("#C71585"); + /// + /// Gets a system-defined color that has an ARGB value of #191970. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color MidnightBlue = new Color("#191970"); + /// + /// Gets a system-defined color that has an ARGB value of #F5FFFA. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color MintCream = new Color("#F5FFFA"); + /// + /// Gets a system-defined color that has an ARGB value of #FFE4E1. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color MistyRose = new Color("#FFE4E1"); + /// + /// Gets a system-defined color that has an ARGB value of #FFE4B5. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color Moccasin = new Color("#FFE4B5"); + /// + /// Gets a system-defined color that has an ARGB value of #FFDEAD. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color NavajoWhite = new Color("#FFDEAD"); + /// + /// Gets a system-defined color that has an ARGB value of #000080. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color Navy = new Color("#000080"); + /// + /// Gets a system-defined color that has an ARGB value of #FDF5E6. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color OldLace = new Color("#FDF5E6"); + /// + /// Gets a system-defined color that has an ARGB value of #808000. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color Olive = new Color("#808000"); + /// + /// Gets a system-defined color that has an ARGB value of #6B8E23. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color OliveDrab = new Color("#6B8E23"); + /// + /// Gets a system-defined color that has an ARGB value of #FFA500. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color Orange = new Color("#FFA500"); + /// + /// Gets a system-defined color that has an ARGB value of #FF4500. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color OrangeRed = new Color("#FF4500"); + /// + /// Gets a system-defined color that has an ARGB value of #DA70D6. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color Orchid = new Color("#DA70D6"); + /// + /// Gets a system-defined color that has an ARGB value of #EEE8AA. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color PaleGoldenrod = new Color("#EEE8AA"); + /// + /// Gets a system-defined color that has an ARGB value of #98FB98. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color PaleGreen = new Color("#98FB98"); + /// + /// Gets a system-defined color that has an ARGB value of #AFEEEE. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color PaleTurquoise = new Color("#AFEEEE"); + /// + /// Gets a system-defined color that has an ARGB value of #DB7093. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color PaleVioletRed = new Color("#DB7093"); + /// + /// Gets a system-defined color that has an ARGB value of #FFEFD5. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color PapayaWhip = new Color("#FFEFD5"); + /// + /// Gets a system-defined color that has an ARGB value of #FFDAB9. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color PeachPuff = new Color("#FFDAB9"); + /// + /// Gets a system-defined color that has an ARGB value of #CD853F. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color Peru = new Color("#CD853F"); + /// + /// Gets a system-defined color that has an ARGB value of #FFC0CB. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color Pink = new Color("#FFC0CB"); + /// + /// Gets a system-defined color that has an ARGB value of #DDA0DD. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color Plum = new Color("#DDA0DD"); + /// + /// Gets a system-defined color that has an ARGB value of #B0E0E6. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color PowderBlue = new Color("#B0E0E6"); + /// + /// Gets a system-defined color that has an ARGB value of #800080. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color Purple = new Color("#800080"); + /// + /// Gets a system-defined color that has an ARGB value of #663399. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color RebeccaPurple = new Color("#663399"); + /// + /// Gets a system-defined color that has an ARGB value of #FF0000. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color Red = new Color("#FF0000"); + /// + /// Gets a system-defined color that has an ARGB value of #BC8F8F. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color RosyBrown = new Color("#BC8F8F"); + /// + /// Gets a system-defined color that has an ARGB value of #4169E1. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color RoyalBlue = new Color("#4169E1"); + /// + /// Gets a system-defined color that has an ARGB value of #8B4513. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color SaddleBrown = new Color("#8B4513"); + /// + /// Gets a system-defined color that has an ARGB value of #FA8072. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color Salmon = new Color("#FA8072"); + /// + /// Gets a system-defined color that has an ARGB value of #F4A460. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color SandyBrown = new Color("#F4A460"); + /// + /// Gets a system-defined color that has an ARGB value of #2E8B57. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color SeaGreen = new Color("#2E8B57"); + /// + /// Gets a system-defined color that has an ARGB value of #FFF5EE. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color SeaShell = new Color("#FFF5EE"); + /// + /// Gets a system-defined color that has an ARGB value of #A0522D. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color Sienna = new Color("#A0522D"); + /// + /// Gets a system-defined color that has an ARGB value of #C0C0C0. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color Silver = new Color("#C0C0C0"); + /// + /// Gets a system-defined color that has an ARGB value of #87CEEB. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color SkyBlue = new Color("#87CEEB"); + /// + /// Gets a system-defined color that has an ARGB value of #6A5ACD. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color SlateBlue = new Color("#6A5ACD"); + /// + /// Gets a system-defined color that has an ARGB value of #708090. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color SlateGray = new Color("#708090"); + /// + /// Gets a system-defined color that has an ARGB value of #FFFAFA. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color Snow = new Color("#FFFAFA"); + /// + /// Gets a system-defined color that has an ARGB value of #00FF7F. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color SpringGreen = new Color("#00FF7F"); + /// + /// Gets a system-defined color that has an ARGB value of #4682B4. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color SteelBlue = new Color("#4682B4"); + /// + /// Gets a system-defined color that has an ARGB value of #D2B48C. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color Tan = new Color("#D2B48C"); + /// + /// Gets a system-defined color that has an ARGB value of #008080. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color Teal = new Color("#008080"); + /// + /// Gets a system-defined color that has an ARGB value of #D2B48C. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color Thistle = new Color("#D8BFD8"); + /// + /// Gets a system-defined color that has an ARGB value of #FF6347. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color Tomato = new Color("#FF6347"); + /// + /// Gets a system-defined color that has an ARGB value of #00FFFFFF. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color Transparent = new Color("#00FFFFFF"); + /// + /// Gets a system-defined color that has an ARGB value of #40E0D0. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color Turquoise = new Color("#40E0D0"); + /// + /// Gets a system-defined color that has an ARGB value of #EE82EE. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color Violet = new Color("#EE82EE"); + /// + /// Gets a system-defined color that has an ARGB value of #F5DEB3. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color Wheat = new Color("#F5DEB3"); + /// + /// Gets a system-defined color that has an ARGB value of #FFFFFF. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color White = new Color("#FFFFFF"); + /// + /// Gets a system-defined color that has an ARGB value of #F5F5F5. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color WhiteSmoke = new Color("#F5F5F5"); + /// + /// Gets a system-defined color that has an ARGB value of #FFFF00. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color Yellow = new Color("#FFFF00"); + /// + /// Gets a system-defined color that has an ARGB value of #9ACD32. + /// + /// A IronSoftware.Drawing.Color representing a system-defined color. + public static Color YellowGreen = new Color("#9ACD32"); + + /// + /// Creates a IronSoftware.Drawing.Color structure from the specified 8-bit color values + /// (red, green, and blue). The alpha value is implicitly 255 (fully opaque). Although + /// this method allows a 32-bit value to be passed for each color component, the + /// value of each component is limited to 8 bits. + /// + /// The red component value for the new System.Drawing.Color. Valid values are 0 through 255. + /// The green component value for the new System.Drawing.Color. Valid values are 0 through 255. + /// The blue component value for the new System.Drawing.Color. Valid values are 0 through 255. + /// + public static Color FromArgb(int red, int green, int blue) + { + return new Color(red, green, blue); + } + + /// + /// Creates a IronSoftware.Drawing.Color structure from the specified 8-bit color values + /// (alpha, red, green, and blue). Although this method allows a 32-bit value to be passed for each color component, + /// the value of each component is limited to 8 bits. + /// + /// The alpha value for the new System.Drawing.Color. Valid values are 0 through 255. + /// The red component value for the new System.Drawing.Color. Valid values are 0 through 255. + /// The green component value for the new System.Drawing.Color. Valid values are 0 through 255. + /// The blue component value for the new System.Drawing.Color. Valid values are 0 through 255. + /// + public static Color FromArgb(int alpha, int red, int green, int blue) + { + return new Color(alpha, red, green, blue); + } + + /// + /// Creates a IronSoftware.Drawing.Color structure from a 32-bit ARGB value. + /// + /// A value specifying the 32-bit ARGB value. + /// IronSoftware.Drawing.Color + public static Color FromArgb(int argb) + { + return new Color(argb.ToString("X")); + } + + /// + /// Luminance is a value from 0 (black) to 100 (white) where 50 is the perceptual "middle grey". + /// Luminance = 50 is the equivalent of Y = 18.4, or in other words an 18% grey card, representing the middle of a photographic exposure(Ansel Adams zone V). + /// + /// Preceived Lightness + public double GetLuminance() + { + int vR = R / 255; + int vG = G / 255; + int vB = B / 255; + + double Y = (0.2126 * SRGBtoLin(vR) + 0.7152 * SRGBtoLin(vG) + 0.0722 * SRGBtoLin(vB)); + + if (Y <= (216 / 24389)) + { // The CIE standard states 0.008856 but 216/24389 is the intent for 0.008856451679036 + return Y * (24389 / 27); // The CIE standard states 903.3, but 24389/27 is the intent, making 903.296296296296296 + } + else + { + return Math.Pow(Y, (1 / 3)) * 116 - 16; + } + } + + /// + /// Implicitly casts System.Drawing.Color objects to . + /// When your .NET Class methods to use as parameters and return types, you now automatically support Color as well. + /// + /// System.Drawing.Color will automatically be cast to + public static implicit operator Color(System.Drawing.Color Color) + { + return new Color(Color.A, Color.R, Color.G, Color.B); + } + + /// + /// Implicitly casts System.Drawing.Color objects from . + /// When your .NET Class methods to use as parameters and return types, you now automatically support SKColor as well. + /// + /// is explicitly cast to an System.Drawing.Rectangle + static public implicit operator System.Drawing.Color(Color Color) + { + return System.Drawing.Color.FromArgb(Color.A, Color.R, Color.G, Color.B); + } + + /// + /// Implicitly casts SkiaSharp.SKColor objects to . + /// When your .NET Class methods to use as parameters and return types, you now automatically support SKColor as well. + /// + /// System.Drawing.Color will automatically be cast to + public static implicit operator Color(SkiaSharp.SKColor Color) + { + return new Color(Color.Alpha, Color.Red, Color.Green, Color.Blue); + } + + /// + /// Implicitly casts SkiaSharp.SKColor objects from . + /// When your .NET Class methods to use as parameters and return types, you now automatically support SKColor as well. + /// + /// is explicitly cast to an SkiaSharp.SKColor + static public implicit operator SkiaSharp.SKColor(Color Color) + { + return new SkiaSharp.SKColor(Color.A, Color.R, Color.G, Color.B); + } + + #region Private Method + + private static InvalidOperationException NoConverterException(string color, Exception innerException) + { + return new InvalidOperationException($"{color} is unable to convert to {typeof(Color)} because it requires a suitable length of string.", innerException); + } + + private static double SRGBtoLin(int colorChannel) + { + // Send this function a decimal sRGB gamma encoded color value + // between 0.0 and 1.0, and it returns a linearized value. + + if (colorChannel <= 0.04045) + { + return colorChannel / 12.92; + } + else + { + return Math.Pow(((colorChannel + 0.055) / 1.055), 2.4); + } + } + + #endregion + } +} diff --git a/IronSoftware.Drawing/IronSoftware.Drawing.Common/CropRectangle.cs b/IronSoftware.Drawing/IronSoftware.Drawing.Common/CropRectangle.cs new file mode 100644 index 0000000..19222c1 --- /dev/null +++ b/IronSoftware.Drawing/IronSoftware.Drawing.Common/CropRectangle.cs @@ -0,0 +1,95 @@ +namespace IronSoftware.Drawing +{ + public partial class CropRectangle + { + public CropRectangle() { } + + public CropRectangle(int x, int y, int width, int height) + { + this.X = x; + this.Y = y; + this.Width = width; + this.Height = height; + } + + /// + /// The x-coordinate of the upper-left corner of this Rectangle. The default is 0. + /// + public int X { get; set; } + /// + /// The y-coordinate of the upper-left corner of this Rectangle. The default is 0. + /// + public int Y { get; set; } + /// + /// The width of this Rectangle. The default is 0. + /// + public int Width { get; set; } + /// + /// The height of this Rectangle. The default is 0. + /// + public int Height { get; set; } + + /// + /// 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. + /// + /// System.Drawing.Rectangle will automatically be cast to . + + public static implicit operator CropRectangle(System.Drawing.Rectangle Rectangle) + { + return new CropRectangle(Rectangle.X, Rectangle.Y, Rectangle.Width, Rectangle.Height); + } + + /// + /// Implicitly casts System.Drawing.Rectangle objects from . + /// When your .NET Class methods use as parameters and return types, you now automatically support Rectangle as well. + /// + /// is explicitly cast to an System.Drawing.Rectangle. + static public implicit operator System.Drawing.Rectangle(CropRectangle CropRectangle) + { + return new System.Drawing.Rectangle(CropRectangle.X, CropRectangle.Y, CropRectangle.Width, CropRectangle.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 CropRectangle(SkiaSharp.SKRect SKRect) + { + return new CropRectangle((int)SKRect.Left, (int)SKRect.Bottom, (int)SKRect.Width, (int)SKRect.Height); + } + + /// + /// Implicitly casts 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 an SkiaSharp.SKRect. + static public implicit operator SkiaSharp.SKRect(CropRectangle CropRectangle) + { + return SkiaSharp.SKRect.Create(CropRectangle.X, CropRectangle.Y, CropRectangle.Width, CropRectangle.Height); + } + + /// + /// Implicitly casts SkiaSharp.SKRectI objects to . + /// When your .NET Class methods use as parameters and return types, you now automatically support SkiaSharp.SKRectI as well. + /// + /// SkiaSharp.SKRectI will automatically be cast to . + + public static implicit operator CropRectangle(SkiaSharp.SKRectI SKRectI) + { + return new CropRectangle((int)SKRectI.Left, (int)SKRectI.Bottom, (int)SKRectI.Width, (int)SKRectI.Height); + } + + /// + /// Implicitly casts SkiaSharp.SKRectI objects from . + /// When your .NET Class methods use as parameters and return types, you now automatically support SkiaSharp.SKRectI as well. + /// + /// is explicitly cast to a SkiaSharp.SKRectI. + static public implicit operator SkiaSharp.SKRectI(CropRectangle CropRectangle) + { + return SkiaSharp.SKRectI.Create(CropRectangle.X, CropRectangle.Y, CropRectangle.Width, CropRectangle.Height); + } + } +} diff --git a/IronSoftware.Drawing/IronSoftware.Drawing.Common/IronBitmap.cs b/IronSoftware.Drawing/IronSoftware.Drawing.Common/IronBitmap.cs new file mode 100644 index 0000000..125f857 --- /dev/null +++ b/IronSoftware.Drawing/IronSoftware.Drawing.Common/IronBitmap.cs @@ -0,0 +1,307 @@ +using SkiaSharp; +using System; + +namespace IronSoftware.Drawing +{ + public static class IronBitmap + { + /// + /// Resize an image with scaling. + /// + /// Original bitmap to resize. + /// Scale of new image 0 - 1. + /// IronSoftware.Drawing.AnyBitmap. + public static AnyBitmap Resize(this AnyBitmap bitmap, float scale) + { + SKBitmap originalBitmap = bitmap; + SKBitmap toBitmap = new SKBitmap((int)(originalBitmap.Width * scale), (int)(originalBitmap.Height * scale), originalBitmap.ColorType, originalBitmap.AlphaType); + + using (SKCanvas canvas = new SKCanvas(toBitmap)) + { + // Draw a bitmap rescaled +#if NETFRAMEWORK + canvas.SetMatrix(SKMatrix.MakeScale(scale, scale)); +#else + canvas.SetMatrix(SKMatrix.CreateScale(scale, scale)); +#endif + canvas.DrawBitmap(originalBitmap, 0, 0); + canvas.ResetMatrix(); + canvas.Flush(); + } + + return toBitmap; + } + + /// + /// Resize an image with width and height. + /// + /// Original bitmap to resize. + /// Width of the new resized image. + /// Height of the new resized image. + /// IronSoftware.Drawing.AnyBitmap. + public static AnyBitmap Resize(this AnyBitmap bitmap, int width, int height) + { + SKBitmap originalBitmap = bitmap; + SKBitmap toBitmap = new SKBitmap(width, height, originalBitmap.ColorType, originalBitmap.AlphaType); + originalBitmap.ExtractSubset(toBitmap, new CropRectangle(0, 0, width, height)); + + return toBitmap; + } + + /// + /// Resize an image with width and height. + /// + /// Original bitmap to resize. + /// Width of the new resized image. + /// Height of the new resized image. + /// Scale of new image 0 - 1. + /// IronSoftware.Drawing.AnyBitmap. + public static AnyBitmap Resize(this AnyBitmap bitmap, int width, int height, float scale) + { + SKBitmap originalBitmap = bitmap; + SKBitmap toBitmap = new SKBitmap(width, height, originalBitmap.ColorType, originalBitmap.AlphaType); + + using (SKCanvas canvas = new SKCanvas(toBitmap)) + { + // Draw a bitmap rescaled +#if NETFRAMEWORK + canvas.SetMatrix(SKMatrix.MakeScale(scale, scale)); +#else + canvas.SetMatrix(SKMatrix.CreateScale(scale, scale)); +#endif + canvas.DrawBitmap(originalBitmap, 0, 0); + canvas.ResetMatrix(); + canvas.Flush(); + } + + return toBitmap; + } + + /// + /// Resize an image with width and height. + /// + /// Original bitmap to resize. + /// CropArea to crop an image. + /// IronSoftware.Drawing.AnyBitmap. + public static AnyBitmap CropImage(this AnyBitmap bitmap, CropRectangle cropRect) + { + if (cropRect != null) + { + CropRectangle dest = ValidateCropArea(bitmap, cropRect); + SKBitmap croppedBitmap = new SKBitmap((int)dest.Width, (int)dest.Height); + try + { + using (SKCanvas canvas = new SKCanvas(croppedBitmap)) + { + canvas.DrawBitmap(bitmap, cropRect, dest); + canvas.Flush(); + } + + return croppedBitmap; + } + catch (OutOfMemoryException) + { + try { croppedBitmap.Dispose(); } catch { } + throw new Exception("Crop Rectangle is larger than the input image."); + } + } + else + { + return bitmap; + } + } + + /// + /// Rotate an image. + /// + /// Original bitmap to resize. + /// Angle for rotate image. Default (null): Will try to determine the image's rotation angle. + /// IronSoftware.Drawing.AnyBitmap. + public static AnyBitmap RotateImage(this AnyBitmap bitmap, double? angle = null) + { + double skewAngle = angle ?? SkewImageLib.GetSkewAngle(bitmap); + double radians = Math.PI * skewAngle / 180; + float sine = (float)Math.Abs(Math.Sin(radians)); + float cosine = (float)Math.Abs(Math.Cos(radians)); + + int originalWidth = ((SKBitmap)bitmap).Width; + int originalHeight = ((SKBitmap)bitmap).Height; + int rotatedWidth = (int)(cosine * originalWidth + sine * originalHeight); + int rotatedHeight = (int)(cosine * originalHeight + sine * originalWidth); + + SKBitmap rotatedBitmap = new SKBitmap(rotatedWidth, rotatedHeight); + + using (SKCanvas canvas = new SKCanvas(rotatedBitmap)) + { + canvas.Clear(SKColors.LightPink); + canvas.Translate(rotatedWidth / 2, rotatedHeight / 2); + canvas.RotateDegrees((float)angle); + canvas.Translate(-originalWidth / 2, -originalHeight / 2); + canvas.DrawBitmap(bitmap, new SKPoint()); + } + + return rotatedBitmap; + } + + /// + /// Determine the image's skew angle. + /// + /// Original bitmap to get skew angle from. + /// Image's angle of skew. + public static double GetSkewAngle(this AnyBitmap bitmap) + { + return SkewImageLib.GetSkewAngle(bitmap); + } + + /// + /// Trim white space of the image. + /// + /// Original bitmap to trim. + /// IronSoftware.Drawing.AnyBitmap. + public static SKBitmap Trim(this AnyBitmap bitmap) + { + + try + { + SKBitmap originalBitmap = bitmap; + int[] rgbValues = new int[originalBitmap.Height * originalBitmap.Width]; + + // Determine Left + int newLeft = -1; + for (int x = 0; x < originalBitmap.Width; x++) + { + for (int y = 0; y < originalBitmap.Height; y++) + { + SKColor color = originalBitmap.GetPixel(x, y); + if (color != SKColors.White) + { + newLeft = x; + break; + } + } + if (newLeft != -1) + break; + } + // Determine Right + int newRight = -1; + for (int x = originalBitmap.Width - 1; x >= 0; x--) + { + for (int y = 0; y < originalBitmap.Height; y++) + { + SKColor color = originalBitmap.GetPixel(x, y); + if (color != SKColors.White) + { + newRight = x; + break; + } + } + if (newRight != -1) + break; + } + // Determine Bottom + int newBottom = -1; + for (int y = 0; y < originalBitmap.Height; y++) + { + for (int x = 0; x < originalBitmap.Width; x++) + { + SKColor color = originalBitmap.GetPixel(x, y); + if (color != SKColors.White) + { + newBottom = x; + break; + } + } + if (newBottom != -1) + break; + } + // Determine Top + int newTop = -1; + for (int y = originalBitmap.Height - 1; y >= 0; y--) + { + for (int x = 0; x < originalBitmap.Width; x++) + { + SKColor color = originalBitmap.GetPixel(x, y); + if (color != SKColors.White) + { + newTop = x; + break; + } + } + if (newTop != -1) + break; + } + + return CropImage(bitmap, new SKRect(newLeft, newTop, newRight, newBottom)); + } + catch + { + return bitmap.Clone(); + } + } + + /// + /// Add a colored border around the image. + /// + /// Original bitmap to add a border to. + /// Color of the border. + /// Width of the border in pixel. + /// IronSoftware.Drawing.AnyBitmap. + public static AnyBitmap AddBorder(this AnyBitmap bitmap, IronSoftware.Drawing.Color color, int width) + { + SKBitmap originalBitmap = bitmap; + int maxWidth = originalBitmap.Width + width * 2; + int maxHeight = originalBitmap.Height + width * 2; + SKBitmap toBitmap = new SKBitmap(maxWidth, maxHeight); + + var ratioX = (double)maxWidth / originalBitmap.Width; + var ratioY = (double)maxHeight / originalBitmap.Height; + var scale = (float)Math.Min(ratioX, ratioY); + + using (SKCanvas canvas = new SKCanvas(toBitmap)) + { +#if NETFRAMEWORK + canvas.SetMatrix(SKMatrix.MakeScale(scale, scale)); +#else + canvas.SetMatrix(SKMatrix.CreateScale(scale, scale)); +#endif + canvas.Clear(color); + int x = (toBitmap.Width - originalBitmap.Width) / 2; + int y = (toBitmap.Height - originalBitmap.Height) / 2; + canvas.DrawBitmap(bitmap, x, y); + canvas.ResetMatrix(); + canvas.Flush(); + } + + return toBitmap; + } + +#region Private Method + + private static CropRectangle ValidateCropArea(SKBitmap img, CropRectangle CropArea) + { + int maxWidth = img.Width; + int maxHeight = img.Height; + + int cropAreaX = CropArea.X > 0 ? CropArea.X : 0; + int cropAreaY = CropArea.Y > 0 ? CropArea.Y : 0; + int cropAreaWidth = CropArea.Width > 0 ? CropArea.Width : img.Width; + int cropAreaHeight = CropArea.Height > 0 ? CropArea.Height : img.Height; + + int croppedWidth = cropAreaX + cropAreaWidth; + int croppedHeight = cropAreaY + cropAreaHeight; + + int newWidth = cropAreaWidth; + int newHeight = cropAreaHeight; + if (croppedWidth > maxWidth) + { + newWidth = maxWidth - cropAreaX; + } + if (croppedHeight > maxHeight) + { + newHeight = maxHeight - cropAreaY; + } + return new CropRectangle(cropAreaX, cropAreaY, newWidth, newHeight); + } +#endregion + } +} diff --git a/IronSoftware.Drawing/IronSoftware.Drawing.Common/IronSoftware.Drawing.Common.csproj b/IronSoftware.Drawing/IronSoftware.Drawing.Common/IronSoftware.Drawing.Common.csproj index d69ef66..7144590 100644 --- a/IronSoftware.Drawing/IronSoftware.Drawing.Common/IronSoftware.Drawing.Common.csproj +++ b/IronSoftware.Drawing/IronSoftware.Drawing.Common/IronSoftware.Drawing.Common.csproj @@ -1,16 +1,24 @@  - - netstandard2.0 - 8 - True - + + net45;netstandard2.0 + 8 + True + 2022.6.2 + 2022.6.2 + 2022.6.2 + + + + + + + + + + + + - - - - - - diff --git a/IronSoftware.Drawing/IronSoftware.Drawing.Common/SkewImageLib.cs b/IronSoftware.Drawing/IronSoftware.Drawing.Common/SkewImageLib.cs new file mode 100644 index 0000000..54badb5 --- /dev/null +++ b/IronSoftware.Drawing/IronSoftware.Drawing.Common/SkewImageLib.cs @@ -0,0 +1,181 @@ +using SkiaSharp; +using System; + +namespace IronSoftware.Drawing +{ + internal class SkewImageLib + { + // Representation of a line in the image. + private class HougLine + { + // Count of points in the line. + public int Count; + // Index in Matrix. + public int Index; + // The line is represented as all x,y that solve y*cos(alpha)-x*sin(alpha)=d + public double Alpha; + } + + + // The Bitmap + private static SKBitmap _internalBmp; + + // The range of angles to search for lines + const double ALPHA_START = -20; + const double ALPHA_STEP = 0.2; + const int STEPS = 40 * 5; + const double STEP = 1; + + // Precalculation of sin and cos. + private static double[] _sinA; + private static double[] _cosA; + + // Range of d + private static double _min; + + + private static int _count; + // Count of points that fit in a line. + private static int[] _hMatrix; + + // Calculate the skew angle of the image cBmp. + internal static double GetSkewAngle(SKBitmap bitmap) + { + _internalBmp = bitmap; + + // Hough Transformation + Calc(); + + // Top 20 of the detected lines in the image. + HougLine[] hl = GetTop(20); + + // Average angle of the lines + double sum = 0; + int count = 0; + for (int i = 0; i <= 19; i++) + { + sum += hl[i].Alpha; + count += 1; + } + return sum / count; + } + + // Calculate the Count lines in the image with most points. + private static HougLine[] GetTop(int count) + { + HougLine[] hl = new HougLine[count]; + + for (int i = 0; i <= count - 1; i++) + { + hl[i] = new HougLine(); + } + for (int i = 0; i <= _hMatrix.Length - 1; i++) + { + if (_hMatrix[i] > hl[count - 1].Count) + { + hl[count - 1].Count = _hMatrix[i]; + hl[count - 1].Index = i; + int j = count - 1; + while (j > 0 && hl[j].Count > hl[j - 1].Count) + { + HougLine tmp = hl[j]; + hl[j] = hl[j - 1]; + hl[j - 1] = tmp; + j -= 1; + } + } + } + + for (int i = 0; i <= count - 1; i++) + { + int dIndex = hl[i].Index / STEPS; + int alphaIndex = hl[i].Index - dIndex * STEPS; + hl[i].Alpha = GetAlpha(alphaIndex); + //hl[i].D = dIndex + _min; + } + + return hl; + } + + + // Hough Transforamtion: + private static void Calc() + { + int hMin = _internalBmp.Height / 4; + int hMax = _internalBmp.Height * 3 / 4; + + Init(); + for (int y = hMin; y <= hMax; y++) + { + for (int x = 1; x <= _internalBmp.Width - 2; x++) + { + // Only lower edges are considered. + if (IsBlack(x, y)) + { + if (!IsBlack(x, y + 1)) + { + Calc(x, y); + } + } + } + } + } + + // Calculate all lines through the point (x,y). + private static void Calc(int x, int y) + { + int alpha; + + for (alpha = 0; alpha <= STEPS - 1; alpha++) + { + double d = y * _cosA[alpha] - x * _sinA[alpha]; + int calculatedIndex = (int)CalcDIndex(d); + int index = calculatedIndex * STEPS + alpha; + try + { + _hMatrix[index] += 1; + } + catch (Exception ex) + { + System.Diagnostics.Debug.WriteLine(ex.ToString()); + } + } + } + private static double CalcDIndex(double d) + { + return Convert.ToInt32(d - _min); + } + private static bool IsBlack(int x, int y) + { + SKColor c = _internalBmp.GetPixel(x, y); + double luminance = (c.Red * 0.299) + (c.Green * 0.587) + (c.Blue * 0.114); + return luminance < 140; + } + + private static void Init() + { + // Precalculation of sin and cos. + _cosA = new double[STEPS]; + _sinA = new double[STEPS]; + + for (int i = 0; i < STEPS; i++) + { + double angle = GetAlpha(i) * Math.PI / 180.0; + _sinA[i] = Math.Sin(angle); + _cosA[i] = Math.Cos(angle); + } + + // Range of d: + _min = -_internalBmp.Width; + _count = (int)(2 * (_internalBmp.Width + _internalBmp.Height) / STEP); + _hMatrix = new int[_count * STEPS]; + + + } + + private static double GetAlpha(int index) + { + return ALPHA_START + index * ALPHA_STEP; + } + } +}