From 7c768e08ae8711afe4bacf7e8a465202c9aa5901 Mon Sep 17 00:00:00 2001 From: DarthAffe Date: Mon, 11 Sep 2023 21:21:21 +0000 Subject: [PATCH] Update README.md --- README.md | 105 +++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 72 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 3c716a5..cac0f24 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,14 @@ [![GitHub](https://img.shields.io/github/license/DarthAffe/ScreenCapture.NET?style=for-the-badge)](https://github.com/DarthAffe/ScreenCapture.NET/blob/master/LICENSE) [![GitHub Repo stars](https://img.shields.io/github/stars/DarthAffe/ScreenCapture.NET?style=for-the-badge)](https://github.com/DarthAffe/ScreenCapture.NET/stargazers) +## NuGet-Packages: +| Package | Description | +|---------|-------------| +| [ScreenCapture.NET](https://www.nuget.org/packages/ScreenCapture.NET)| The core-package required to use ScreenCapture.NET captures or write your own. | +| [ScreenCapture.NET.DX11](https://www.nuget.org/packages/ScreenCapture.NET.DX11) | DirectX 11 based capturing. Fast and supports the whole set of features. **This should always be used if possible!** | +| [ScreenCapture.NET.DX9](https://www.nuget.org/packages/ScreenCapture.NET.DX9) | DirectX 9 based capturing. Slower then DX 11 and does not support rotated screens and GPU-accelerated downscaling. Only useful if the DX11 package can't be used for some reason. | +| [ScreenCapture.NET.X11](https://www.nuget.org/packages/ScreenCapture.NET.X11) | libX11 based capturing for the X-Window-System. Currently the only way to use ScreenCapture.NET on linux. Quite slow and can easily break depending on the X-Server config. Works on my machine, but it's not really a high proprity to support at the moment. Does not support rotated screens and GPU-accelerated downscaling. | + ## Usage ```csharp // Create a screen-capture service @@ -18,50 +26,81 @@ IEnumerable displays = screenCaptureService.GetDisplays(graphicsCards.F // Create a screen-capture for all screens you want to capture IScreenCapture screenCapture = screenCaptureService.GetScreenCapture(displays.First()); -// Register the regions you want to capture on the screen +// Register the regions you want to capture om the screen // Capture the whole screen -CaptureZone fullscreen = screenCapture.RegisterCaptureZone(0, 0, screenCapture.Display.Width, screenCapture.Display.Height); +ICaptureZone fullscreen = screenCapture.RegisterCaptureZone(0, 0, screenCapture.Display.Width, screenCapture.Display.Height); // Capture a 100x100 region at the top left and scale it down to 50x50 -CaptureZone topLeft = screenCapture.RegisterCaptureZone(0, 0, 100, 100, downscaleLevel: 1); +ICaptureZone topLeft = screenCapture.RegisterCaptureZone(0, 0, 100, 100, downscaleLevel: 1); // Capture the screen // This should be done in a loop on a seperate thread as CaptureScreen blocks if the screen is not updated (still image). screenCapture.CaptureScreen(); // Do something with the captured image - e.g. access all pixels (same could be done with topLeft) -// Locking is not neccessary in that case as we're capturing in the same thread, -// but when using a threaded-approach (which is recommended) it prevents potential tearing of the data in the buffer. -lock (fullscreen.Buffer) + +//Lock the zone to access the data. Remember to dispose the returned disposable to unlock again. +using (fullscreen.Lock()) { - // Stride is the width in bytes of a row in the buffer (width in pixel * bytes per pixel) - int stride = fullscreen.Stride; + // You have multiple options now: + // 1. Access the raw byte-data + ReadOnlySpan rawData = fullscreen.RawBuffer; - Span data = new(fullscreen.Buffer); + // 2. Use the provided abstraction to access pixels without having to care about low-level byte handling + // Get the image captured for the zone + IImage image = fullscreen.Image; - // Iterate all rows of the image - for (int y = 0; y < fullscreen.Height; y++) - { - // Select the actual data of the row - Span row = data.Slice(y * stride, stride); + // Iterate all pixels of the image + foreach (IColor color in image) + Console.WriteLine($"A: {color.A}, R: {color.R}, G: {color.G}, B: {color.B}"); - // Iterate all pixels - for (int x = 0; x < row.Length; x += fullscreen.BytesPerPixel) - { - // Data is in BGRA format for the DX11ScreenCapture - byte b = row[x]; - byte g = row[x + 1]; - byte r = row[x + 2]; - byte a = row[x + 3]; - } - } + // Get the pixel at location (x = 10, y = 20) + IColor imageColorExample = image[10, 20]; + + // Get the first row + IImage.IImageRow row = image.Rows[0]; + // Get the 10th pixel of the row + IColor rowColorExample = row[10]; + + // Get the first column + IImage.IImageColumn column = image.Columns[0]; + // Get the 10th pixel of the column + IColor columnColorExample = column[10]; + + // Cuts a rectangle out of the original image (x = 100, y = 150, width = 400, height = 300) + IImage subImage = image[100, 150, 400, 300]; + + // All of the things above (rows, columns, sub-images) do NOT allocate new memory so they are fast and memory efficient, but for that reason don't provide raw byte access. +} +``` + +IF you know which Capture-provider you're using it performs a bit better to not use the abstraction but a more low-level approach instead. +This is the same example as above but without using the interfaces: +```csharp +DX11ScreenCaptureService screenCaptureService = new DX11ScreenCaptureService(); +IEnumerable graphicsCards = screenCaptureService.GetGraphicsCards(); +IEnumerable displays = screenCaptureService.GetDisplays(graphicsCards.First()); +DX11ScreenCapture screenCapture = screenCaptureService.GetScreenCapture(displays.First()); + +CaptureZone fullscreen = screenCapture.RegisterCaptureZone(0, 0, screenCapture.Display.Width, screenCapture.Display.Height); +CaptureZone topLeft = screenCapture.RegisterCaptureZone(0, 0, 100, 100, downscaleLevel: 1); + +screenCapture.CaptureScreen(); + +using (fullscreen.Lock()) +{ + RefImage image = fullscreen.Image; + + foreach (ColorBGRA color in image) + Console.WriteLine($"A: {color.A}, R: {color.R}, G: {color.G}, B: {color.B}"); + + ColorBGRA imageColorExample = image[10, 20]; + + ReadOnlyRefEnumerable row = image.Rows[0]; + ColorBGRA rowColorExample = row[10]; + + ReadOnlyRefEnumerable column = image.Columns[0]; + ColorBGRA columnColorExample = column[10]; + + RefImage subImage = image[100, 150, 400, 300]; } - -// Move the top left zone more towards the center -// Using the Update-method allows to move the zone without having to allocate -// new buffers and textures which yields a good performance gain if done at high framerates. -screenCapture.UpdateCaptureZone(topLeft, x: 100, y: 200); - -// Note that resizing the zone is also possible but currently reinitializes the zone -// -> no performance gain compared to removing and readding the zone. -screenCapture.UpdateCaptureZone(topLeft, width: 20, height: 20); ```