/// <summary> /// Gets whether a non-padded contiguous span of pixels /// can be created over the underlying memory. /// </summary> /// <remarks> /// To include padding use <see cref="IsPaddedPixelContiguous"/> /// </remarks> public static bool IsPixelContiguous(this IReadOnlyPixelMemory buffer) { if (buffer == null) { throw new ArgumentNullException(nameof(buffer)); } return(buffer.Width * buffer.ElementSize == buffer.ByteStride); }
public static ReadOnlySpan <TPixel> GetPixelSpan <TPixel>( this IReadOnlyPixelMemory <TPixel> buffer, int start) where TPixel : unmanaged, IPixel { if (buffer == null) { throw new ArgumentNullException(nameof(buffer)); } return(buffer.GetPixelSpan()[start..]);
public static int GetPixelStride(this IReadOnlyPixelMemory buffer) { if (buffer == null) { throw new ArgumentNullException(nameof(buffer)); } if (!buffer.IsPaddedPixelContiguous()) { throw new InvalidOperationException("The buffer is not pixel-contiguous."); } return(buffer.ByteStride / buffer.ElementSize); }
private static unsafe MouseCursor PlatformFromPixels( IReadOnlyPixelMemory <Color> data, int width, int height, Point origin) { var iconInfo = new IconInfo(); // bitmaps can not be constructed from Rgba directly using (var bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb)) { var rect = new System.Drawing.Rectangle(0, 0, width, height); var bmpData = bitmap.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); try { var source = data.GetPixelSpan(); int pixelStride = data.GetPixelStride(); for (int y = 0; y < bmpData.Height; y++) { var srcRow = source.Slice(y * pixelStride, width); var dstRow = new Span <Bgra32>((byte *)bmpData.Scan0 + y * bmpData.Stride, bmpData.Width); for (int x = 0; x < srcRow.Length; x++) { dstRow[x].FromColor(srcRow[x]); } } } finally { bitmap.UnlockBits(bmpData); } GetIconInfo(bitmap.GetHicon(), ref iconInfo); } iconInfo.xHotspot = origin.X; iconInfo.yHotspot = origin.Y; iconInfo.fIcon = false; var cursor = new Cursor(CreateIconIndirect(iconInfo)); return(new MouseCursor(cursor, needsDisposing: true)); }
/// <summary> /// Creates a mouse cursor from the specified pixels. /// </summary> /// <param name="pixels">Pixels to use as the cursor image.</param> /// <param name="origin">A point in the pixels that is used as the cursor position.</param> /// <param name="sourceRectangle">Optional part of the image to use as the cursor.</param> public static MouseCursor FromPixels( IReadOnlyPixelRows pixels, Point origin, Rectangle?sourceRectangle = null) { if (pixels == null) { throw new ArgumentNullException(nameof(pixels)); } Rectangle rect = sourceRectangle ?? pixels.GetBounds(); if (!pixels.GetBounds().Contains(rect)) { throw new ArgumentOutOfRangeException( nameof(sourceRectangle), "The source rectangle is outside the pixel buffer."); } IReadOnlyPixelMemory <Color>?pixelBuffer = null; try { if (rect.Position == Point.Zero && pixels is IReadOnlyPixelMemory <Color> rgbaMemory && rgbaMemory.IsPaddedPixelContiguous()) { pixelBuffer = rgbaMemory; } else { pixelBuffer = Image.LoadPixels <Color>(pixels.ProjectRows(x => x.Crop(rect))); } return(PlatformFromPixels(pixelBuffer, rect.Width, rect.Height, origin)); } finally { pixelBuffer?.Dispose(); } }
private static unsafe MouseCursor PlatformFromPixels( IReadOnlyPixelMemory <Color> data, int width, int height, Point origin) { var surface = IntPtr.Zero; var handle = IntPtr.Zero; try { fixed(Color *ptr = data.GetPixelSpan()) { surface = SDL.CreateRGBSurfaceFrom( (IntPtr)ptr, width, height, 32, data.ByteStride, 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000); } if (surface == IntPtr.Zero) { throw new InvalidOperationException( "Failed to create surface for mouse cursor.", new Exception(SDL.GetError())); } handle = SDL.Mouse.CreateColorCursor(surface, origin.X, origin.Y); if (handle == IntPtr.Zero) { throw new InvalidOperationException( "Failed to create mouse cursor from surface.", new Exception(SDL.GetError())); } } finally { if (surface != IntPtr.Zero) { SDL.FreeSurface(surface); } } return(new MouseCursor(handle)); }