using SixLabors.ImageSharp; using System; using System.IO; using System.Threading.Tasks; namespace OpenMacroBoard.SDK { /// /// Collection of factory extension methods for s. /// /// /// You typically don't want to invoke the static methods directly, but instead use them /// as extension methods by calling .XYZ(); /// public static class KeyBitmapBasicFactoryExtensions { /// /// Creates a new object. /// /// The builder that is used to create the /// width of the bitmap /// height of the bitmap /// raw bitmap data (Bgr24) /// /// Either or are smaller than one. /// /// /// Provided and doesn't match the /// expected array length of . /// public static KeyBitmap FromBgr24Array( this IKeyBitmapFactory keyFactory, int width, int height, ReadOnlySpan bitmapDataBgr24 ) { if(width < 1) { throw new ArgumentOutOfRangeException(nameof(width)); } if(height < 1) { throw new ArgumentOutOfRangeException(nameof(height)); } var expectedLength = width * height * 3; if(bitmapDataBgr24.Length != expectedLength) { throw new ArgumentException($"{nameof(bitmapDataBgr24)}.Length does not match it's expected size ({nameof(width)} x {nameof(height)} x 3)", nameof(bitmapDataBgr24)); } var data = new byte[expectedLength]; bitmapDataBgr24.CopyTo(data); return new KeyBitmap(width, height, data); } /// /// Creates a new object. /// /// The builder that is used to create the /// width of the bitmap /// height of the bitmap /// raw bitmap data (Bgra32). The alpha channel will be ignored. /// /// Either or are smaller than one. /// /// /// Provided and doesn't match the /// expected array length of . /// public static KeyBitmap FromBgra32Array( this IKeyBitmapFactory keyFactory, int width, int height, ReadOnlySpan bitmapDataBgra32 ) { if(width < 1) { throw new ArgumentOutOfRangeException(nameof(width)); } if(height < 1) { throw new ArgumentOutOfRangeException(nameof(height)); } var pixelCount = width * height; var expectedLength = pixelCount * 4; if(bitmapDataBgra32.Length != expectedLength) { throw new ArgumentException($"{nameof(bitmapDataBgra32)}.Length does not match it's expected size ({nameof(width)} x {nameof(height)} x 4)", nameof(bitmapDataBgra32)); } var data = new byte[expectedLength]; for(int i = 0; i < pixelCount; i++) { var i3 = i * 3; var i4 = i * 4; // Copy BGR and ignore alpha channel data[i3 + 0] = bitmapDataBgra32[i4 + 0]; data[i3 + 1] = bitmapDataBgra32[i4 + 1]; data[i3 + 2] = bitmapDataBgra32[i4 + 2]; } return new KeyBitmap(width, height, data); } /// /// Creates a new object. /// /// The builder that is used to create the /// width of the bitmap /// height of the bitmap /// raw bitmap data (Bgra32). The alpha channel will be ignored. /// /// Either or are smaller than one. /// /// /// Provided and doesn't match the /// expected array length of . /// public static KeyBitmap FromRgba32Array( this IKeyBitmapFactory keyFactory, int width, int height, ReadOnlySpan bitmapDataRgba32 ) { if(width < 1) { throw new ArgumentOutOfRangeException(nameof(width)); } if(height < 1) { throw new ArgumentOutOfRangeException(nameof(height)); } var pixelCount = width * height; var expectedLength = pixelCount * 4; if(bitmapDataRgba32.Length != expectedLength) { throw new ArgumentException($"{nameof(bitmapDataRgba32)}.Length does not match it's expected size ({nameof(width)} x {nameof(height)} x 4)", nameof(bitmapDataRgba32)); } var data = new byte[expectedLength]; for(int i = 0; i < pixelCount; i++) { var i3 = i * 3; var i4 = i * 4; // Copy BGR and ignore alpha channel data[i3 + 2] = bitmapDataRgba32[i4 + 0]; data[i3 + 1] = bitmapDataRgba32[i4 + 1]; data[i3 + 0] = bitmapDataRgba32[i4 + 2]; } return new KeyBitmap(width, height, data); } /// /// Creates a new object. /// /// The builder that is used to create the /// width of the bitmap /// height of the bitmap /// /// Either or are smaller than one. /// public static KeyBitmap Empty( this IKeyBitmapFactory keyFactory, int width, int height ) { if(width < 1) { throw new ArgumentOutOfRangeException(nameof(width)); } if(height < 1) { throw new ArgumentOutOfRangeException(nameof(height)); } return new KeyBitmap(width, height, Array.Empty()); } /// /// Creates a single color (single pixel) with a given color. /// /// The builder that is used to create the /// Red channel. /// Green channel. /// Blue channel. public static KeyBitmap FromRgb(this IKeyBitmapFactory keyFactory, byte r, byte g, byte b) { // If everything is 0 (black) take a shortcut ;-) if(r == 0 && g == 0 && b == 0) { return KeyBitmap.Black; } var buffer = new byte[3] { b, g, r }; return KeyBitmap.Create.FromBgr24Array(1, 1, buffer); } /// /// Creates a single color (single pixel) with a given color. /// /// The builder that is used to create the /// The color. public static KeyBitmap FromColor(this IKeyBitmapFactory keyFactory, OmbColor color) { return keyFactory.FromRgb(color.R, color.G, color.B); } /// /// Create a bitmap from an encoded given image stream. /// public static KeyBitmap FromStream(this IKeyBitmapFactory builder, Stream bitmapStream) { return builder.FromImageSharpImage(Image.Load(bitmapStream)); } /// /// Create a bitmap from an encoded given image stream. /// public static async Task FromStreamAsync(this IKeyBitmapFactory builder, Stream bitmapStream) { return builder.FromImageSharpImage(await Image.LoadAsync(bitmapStream)); } /// /// Create a bitmap from an encoded given image file. /// public static KeyBitmap FromFile(this IKeyBitmapFactory builder, string bitmapFile) { return builder.FromImageSharpImage(Image.Load(bitmapFile)); } /// /// Create a bitmap from an encoded given image file. /// public static async Task FromFileAsync(this IKeyBitmapFactory builder, string bitmapFile) { return builder.FromImageSharpImage(await Image.LoadAsync(bitmapFile)); } /// /// Creates a from a given . /// /// The provided bitmap is null. /// The pixel format of the image is not supported. public static KeyBitmap FromImageSharpImage(this IKeyBitmapFactory keyFactory, Image image) { if(image is null) { throw new ArgumentNullException(nameof(image)); } using var ctx = image.WithBgr24(); var pixelData = ctx.Item.ToBgr24PixelArray(); return KeyBitmap.Create.FromBgr24Array(image.Width, image.Height, pixelData); } } }