Added some missing doc-comments

This commit is contained in:
Darth Affe 2023-09-10 22:20:06 +02:00
parent a1a43ddcfc
commit bcb92eb422
19 changed files with 406 additions and 45 deletions

View File

@ -68,7 +68,7 @@ public sealed class DX11ScreenCapture : AbstractScreenCapture<ColorBGRA>
/// <param name="factory">The <see cref="IDXGIFactory1"/> used to create underlying objects.</param> /// <param name="factory">The <see cref="IDXGIFactory1"/> used to create underlying objects.</param>
/// <param name="display">The <see cref="Display"/> to duplicate.</param> /// <param name="display">The <see cref="Display"/> to duplicate.</param>
/// <param name="useNewDuplicationAdapter">Indicates if the DuplicateOutput1 interface should be used instead of the older DuplicateOutput. Currently there's no real use in setting this to true.</param> /// <param name="useNewDuplicationAdapter">Indicates if the DuplicateOutput1 interface should be used instead of the older DuplicateOutput. Currently there's no real use in setting this to true.</param>
public DX11ScreenCapture(IDXGIFactory1 factory, Display display, bool useNewDuplicationAdapter = false) internal DX11ScreenCapture(IDXGIFactory1 factory, Display display, bool useNewDuplicationAdapter = false)
: base(display) : base(display)
{ {
this._factory = factory; this._factory = factory;
@ -81,6 +81,7 @@ public sealed class DX11ScreenCapture : AbstractScreenCapture<ColorBGRA>
#region Methods #region Methods
/// <inheritdoc />
protected override bool PerformScreenCapture() protected override bool PerformScreenCapture()
{ {
bool result = false; bool result = false;
@ -133,6 +134,7 @@ public sealed class DX11ScreenCapture : AbstractScreenCapture<ColorBGRA>
return result; return result;
} }
/// <inheritdoc />
protected override void PerformCaptureZoneUpdate(CaptureZone<ColorBGRA> captureZone, in Span<byte> buffer) protected override void PerformCaptureZoneUpdate(CaptureZone<ColorBGRA> captureZone, in Span<byte> buffer)
{ {
if (_context == null) return; if (_context == null) return;
@ -299,6 +301,7 @@ public sealed class DX11ScreenCapture : AbstractScreenCapture<ColorBGRA>
} }
} }
/// <inheritdoc />
protected override void ValidateCaptureZoneAndThrow(int x, int y, int width, int height, int downscaleLevel) protected override void ValidateCaptureZoneAndThrow(int x, int y, int width, int height, int downscaleLevel)
{ {
if (_device == null) throw new ApplicationException("ScreenCapture isn't initialized."); if (_device == null) throw new ApplicationException("ScreenCapture isn't initialized.");
@ -429,10 +432,13 @@ public sealed class DX11ScreenCapture : AbstractScreenCapture<ColorBGRA>
} }
} }
/// <inheritdoc />
protected override void Dispose(bool disposing) protected override void Dispose(bool disposing)
{ {
base.Dispose(disposing); base.Dispose(disposing);
DisposeDX();
lock (_captureLock)
DisposeDX();
} }
private void DisposeDX() private void DisposeDX()

View File

@ -9,8 +9,8 @@ using Vortice.Direct3D9;
namespace ScreenCapture.NET; namespace ScreenCapture.NET;
/// <summary> /// <summary>
/// Represents a ScreenCapture using DirectX 11 desktop duplicaton. /// Represents a ScreenCapture using DirectX 9.
/// https://docs.microsoft.com/en-us/windows/win32/direct3ddxgi/desktop-dup-api /// https://learn.microsoft.com/en-us/windows/win32/api/d3d9/nf-d3d9-idirect3ddevice9-getfrontbufferdata
/// </summary> /// </summary>
// ReSharper disable once InconsistentNaming // ReSharper disable once InconsistentNaming
public sealed class DX9ScreenCapture : AbstractScreenCapture<ColorBGRA> public sealed class DX9ScreenCapture : AbstractScreenCapture<ColorBGRA>
@ -32,8 +32,9 @@ public sealed class DX9ScreenCapture : AbstractScreenCapture<ColorBGRA>
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="DX9ScreenCapture"/> class. /// Initializes a new instance of the <see cref="DX9ScreenCapture"/> class.
/// </summary> /// </summary>
/// <param name="direct3D9">The D3D9 instance used.</param>
/// <param name="display">The <see cref="Display"/> to duplicate.</param> /// <param name="display">The <see cref="Display"/> to duplicate.</param>
public DX9ScreenCapture(IDirect3D9 direct3D9, Display display) internal DX9ScreenCapture(IDirect3D9 direct3D9, Display display)
: base(display) : base(display)
{ {
this._direct3D9 = direct3D9; this._direct3D9 = direct3D9;
@ -45,6 +46,7 @@ public sealed class DX9ScreenCapture : AbstractScreenCapture<ColorBGRA>
#region Methods #region Methods
/// <inheritdoc />
protected override bool PerformScreenCapture() protected override bool PerformScreenCapture()
{ {
bool result = false; bool result = false;
@ -89,6 +91,7 @@ public sealed class DX9ScreenCapture : AbstractScreenCapture<ColorBGRA>
return result; return result;
} }
/// <inheritdoc />
protected override void PerformCaptureZoneUpdate(CaptureZone<ColorBGRA> captureZone, in Span<byte> buffer) protected override void PerformCaptureZoneUpdate(CaptureZone<ColorBGRA> captureZone, in Span<byte> buffer)
{ {
if (_buffer == null) return; if (_buffer == null) return;
@ -195,10 +198,13 @@ public sealed class DX9ScreenCapture : AbstractScreenCapture<ColorBGRA>
} }
} }
/// <inheritdoc />
protected override void Dispose(bool disposing) protected override void Dispose(bool disposing)
{ {
base.Dispose(disposing); base.Dispose(disposing);
DisposeDX();
lock (_captureLock)
DisposeDX();
} }
private void DisposeDX() private void DisposeDX()

View File

@ -43,8 +43,12 @@ internal readonly ref struct SamplerInfo<T>
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="SamplerInfo{T}" /> class. /// Initializes a new instance of the <see cref="SamplerInfo{T}" /> class.
/// </summary> /// </summary>
/// <param name="x">The X-location of the region the data comes from.</param>
/// <param name="y">The Y-location of the region the data comes from.</param>
/// <param name="width">The width of the region the data comes from.</param> /// <param name="width">The width of the region the data comes from.</param>
/// <param name="height">The height of region the data comes from.</param> /// <param name="height">The height of region the data comes from.</param>
/// <param name="stride">The number of pixels in a row of data.</param>
/// <param name="dataPerPixel">The number of {T} representing a single pixel.</param>
/// <param name="data">The data to sample.</param> /// <param name="data">The data to sample.</param>
public SamplerInfo(int x, int y, int width, int height, int stride, int dataPerPixel, in ReadOnlySpan<T> data) public SamplerInfo(int x, int y, int width, int height, int stride, int dataPerPixel, in ReadOnlySpan<T> data)
{ {

View File

@ -43,8 +43,12 @@ internal readonly ref struct SamplerInfo<T>
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="SamplerInfo{T}" /> class. /// Initializes a new instance of the <see cref="SamplerInfo{T}" /> class.
/// </summary> /// </summary>
/// <param name="x">The X-location of the region the data comes from.</param>
/// <param name="y">The Y-location of the region the data comes from.</param>
/// <param name="width">The width of the region the data comes from.</param> /// <param name="width">The width of the region the data comes from.</param>
/// <param name="height">The height of region the data comes from.</param> /// <param name="height">The height of region the data comes from.</param>
/// <param name="stride">The number of pixels in a row of data.</param>
/// <param name="dataPerPixel">The number of {T} representing a single pixel.</param>
/// <param name="data">The data to sample.</param> /// <param name="data">The data to sample.</param>
public SamplerInfo(int x, int y, int width, int height, int stride, int dataPerPixel, in ReadOnlySpan<T> data) public SamplerInfo(int x, int y, int width, int height, int stride, int dataPerPixel, in ReadOnlySpan<T> data)
{ {

View File

@ -7,7 +7,7 @@ namespace ScreenCapture.NET;
/// <summary> /// <summary>
/// Represents a ScreenCapture using libX11. /// Represents a ScreenCapture using libX11.
/// https://docs.microsoft.com/en-us/windows/win32/direct3ddxgi/desktop-dup-api /// https://x.org/releases/current/doc/libX11/libX11/libX11.html#XGetImage
/// </summary> /// </summary>
// ReSharper disable once InconsistentNaming // ReSharper disable once InconsistentNaming
public sealed class X11ScreenCapture : AbstractScreenCapture<ColorBGRA> public sealed class X11ScreenCapture : AbstractScreenCapture<ColorBGRA>
@ -31,7 +31,7 @@ public sealed class X11ScreenCapture : AbstractScreenCapture<ColorBGRA>
/// Initializes a new instance of the <see cref="X11ScreenCapture"/> class. /// Initializes a new instance of the <see cref="X11ScreenCapture"/> class.
/// </summary> /// </summary>
/// <param name="display">The <see cref="Display"/> to duplicate.</param> /// <param name="display">The <see cref="Display"/> to duplicate.</param>
public X11ScreenCapture(Display display) internal X11ScreenCapture(Display display)
: base(display) : base(display)
{ {
Restart(); Restart();
@ -41,6 +41,7 @@ public sealed class X11ScreenCapture : AbstractScreenCapture<ColorBGRA>
#region Methods #region Methods
/// <inheritdoc />
protected override bool PerformScreenCapture() protected override bool PerformScreenCapture()
{ {
lock (_captureLock) lock (_captureLock)
@ -57,6 +58,7 @@ public sealed class X11ScreenCapture : AbstractScreenCapture<ColorBGRA>
} }
} }
/// <inheritdoc />
protected override void PerformCaptureZoneUpdate(CaptureZone<ColorBGRA> captureZone, in Span<byte> buffer) protected override void PerformCaptureZoneUpdate(CaptureZone<ColorBGRA> captureZone, in Span<byte> buffer)
{ {
using IDisposable @lock = captureZone.Lock(); using IDisposable @lock = captureZone.Lock();
@ -158,6 +160,7 @@ public sealed class X11ScreenCapture : AbstractScreenCapture<ColorBGRA>
} }
} }
/// <inheritdoc />
protected override void Dispose(bool disposing) protected override void Dispose(bool disposing)
{ {
base.Dispose(disposing); base.Dispose(disposing);

View File

@ -75,6 +75,8 @@ public class X11ScreenCaptureService : IScreenCaptureService
/// <inheritdoc /> /// <inheritdoc />
IScreenCapture IScreenCaptureService.GetScreenCapture(Display display) => GetScreenCapture(display); IScreenCapture IScreenCaptureService.GetScreenCapture(Display display) => GetScreenCapture(display);
/// <inheritdoc cref="IScreenCaptureService.GetScreenCapture"/>
public X11ScreenCapture GetScreenCapture(Display display) public X11ScreenCapture GetScreenCapture(Display display)
{ {
if (_isDisposed) throw new ObjectDisposedException(GetType().FullName); if (_isDisposed) throw new ObjectDisposedException(GetType().FullName);

View File

@ -4,6 +4,7 @@ using System.Linq;
namespace ScreenCapture.NET; namespace ScreenCapture.NET;
/// <inheritdoc />
public abstract class AbstractScreenCapture<TColor> : IScreenCapture public abstract class AbstractScreenCapture<TColor> : IScreenCapture
where TColor : struct, IColor where TColor : struct, IColor
{ {
@ -11,20 +12,29 @@ public abstract class AbstractScreenCapture<TColor> : IScreenCapture
private bool _isDisposed; private bool _isDisposed;
/// <summary>
/// Gets a list of <see cref="CaptureZone{TColol}"/> registered on this ScreenCature.
/// </summary>
protected HashSet<CaptureZone<TColor>> CaptureZones { get; } = new(); protected HashSet<CaptureZone<TColor>> CaptureZones { get; } = new();
/// <inheritdoc />
public Display Display { get; } public Display Display { get; }
#endregion #endregion
#region Events #region Events
/// <inheritdoc />
public event EventHandler<ScreenCaptureUpdatedEventArgs>? Updated; public event EventHandler<ScreenCaptureUpdatedEventArgs>? Updated;
#endregion #endregion
#region Constructors #region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="AbstractScreenCapture{T}"/> class.
/// </summary>
/// <param name="display">The <see cref="Display"/> to duplicate.</param>
protected AbstractScreenCapture(Display display) protected AbstractScreenCapture(Display display)
{ {
this.Display = display; this.Display = display;
@ -36,6 +46,7 @@ public abstract class AbstractScreenCapture<TColor> : IScreenCapture
#region Methods #region Methods
/// <inheritdoc />
public virtual bool CaptureScreen() public virtual bool CaptureScreen()
{ {
if (_isDisposed) throw new ObjectDisposedException(GetType().FullName); if (_isDisposed) throw new ObjectDisposedException(GetType().FullName);
@ -67,10 +78,23 @@ public abstract class AbstractScreenCapture<TColor> : IScreenCapture
return result; return result;
} }
/// <summary>
/// Performs the actual screen capture.
/// </summary>
/// <returns><c>true</c> if the screen was captured sucessfully; otherwise, <c>false</c>.</returns>
protected abstract bool PerformScreenCapture(); protected abstract bool PerformScreenCapture();
/// <summary>
/// Performs an update of the given capture zone.
/// </summary>
/// <param name="captureZone">The capture zone to update.</param>
/// <param name="buffer">The buffer containing the current pixel-data of the capture zone.</param>
protected abstract void PerformCaptureZoneUpdate(CaptureZone<TColor> captureZone, in Span<byte> buffer); protected abstract void PerformCaptureZoneUpdate(CaptureZone<TColor> captureZone, in Span<byte> buffer);
/// <summary>
/// Raises the <see cref="Updated"/>-event.
/// </summary>
/// <param name="result">A bool indicating whether the update was successful or not.</param>
protected virtual void OnUpdated(bool result) protected virtual void OnUpdated(bool result)
{ {
try try
@ -80,7 +104,10 @@ public abstract class AbstractScreenCapture<TColor> : IScreenCapture
catch { /**/ } catch { /**/ }
} }
/// <inheritdoc />
ICaptureZone IScreenCapture.RegisterCaptureZone(int x, int y, int width, int height, int downscaleLevel) => RegisterCaptureZone(x, y, width, height, downscaleLevel); ICaptureZone IScreenCapture.RegisterCaptureZone(int x, int y, int width, int height, int downscaleLevel) => RegisterCaptureZone(x, y, width, height, downscaleLevel);
/// <inheritdoc cref="IScreenCapture.RegisterCaptureZone" />
public virtual CaptureZone<TColor> RegisterCaptureZone(int x, int y, int width, int height, int downscaleLevel = 0) public virtual CaptureZone<TColor> RegisterCaptureZone(int x, int y, int width, int height, int downscaleLevel = 0)
{ {
if (_isDisposed) throw new ObjectDisposedException(GetType().FullName); if (_isDisposed) throw new ObjectDisposedException(GetType().FullName);
@ -100,6 +127,15 @@ public abstract class AbstractScreenCapture<TColor> : IScreenCapture
} }
} }
/// <summary>
/// Validates the given values of a capture zone.
/// </summary>
/// <param name="x">The X-location of the zone.</param>
/// <param name="y">The Y-location of the zone.</param>
/// <param name="width">The width of the zone.</param>
/// <param name="height">The height of the zone.</param>
/// <param name="downscaleLevel">The downscale-level of the zone.</param>
/// <exception cref="ArgumentException">Throws if some of the provided data is not valid.</exception>
protected virtual void ValidateCaptureZoneAndThrow(int x, int y, int width, int height, int downscaleLevel) protected virtual void ValidateCaptureZoneAndThrow(int x, int y, int width, int height, int downscaleLevel)
{ {
if (x < 0) throw new ArgumentException("x < 0"); if (x < 0) throw new ArgumentException("x < 0");
@ -110,6 +146,13 @@ public abstract class AbstractScreenCapture<TColor> : IScreenCapture
if ((y + height) > Display.Height) throw new ArgumentException("y + height > Display height"); if ((y + height) > Display.Height) throw new ArgumentException("y + height > Display height");
} }
/// <summary>
/// Calculates the actual size when downscaling is used.
/// </summary>
/// <param name="width">The original width.</param>
/// <param name="height">The original height.</param>
/// <param name="downscaleLevel">The level of downscaling to be used.</param>
/// <returns>A tuple containing the scaled width, the scaled height and the downscale-level used. (This can be smaller then the one provided if the image is not big enough to scale down that often.)</returns>
protected virtual (int width, int height, int downscaleLevel) CalculateScaledSize(int width, int height, int downscaleLevel) protected virtual (int width, int height, int downscaleLevel) CalculateScaledSize(int width, int height, int downscaleLevel)
{ {
if (downscaleLevel > 0) if (downscaleLevel > 0)
@ -131,7 +174,10 @@ public abstract class AbstractScreenCapture<TColor> : IScreenCapture
return (width, height, downscaleLevel); return (width, height, downscaleLevel);
} }
/// <inheritdoc />
bool IScreenCapture.UnregisterCaptureZone(ICaptureZone captureZone) => UnregisterCaptureZone(captureZone as CaptureZone<TColor> ?? throw new ArgumentException("Invalid capture-zone.")); bool IScreenCapture.UnregisterCaptureZone(ICaptureZone captureZone) => UnregisterCaptureZone(captureZone as CaptureZone<TColor> ?? throw new ArgumentException("Invalid capture-zone."));
/// <inheritdoc cref="IScreenCapture.UnregisterCaptureZone" />
public virtual bool UnregisterCaptureZone(CaptureZone<TColor> captureZone) public virtual bool UnregisterCaptureZone(CaptureZone<TColor> captureZone)
{ {
if (_isDisposed) throw new ObjectDisposedException(GetType().FullName); if (_isDisposed) throw new ObjectDisposedException(GetType().FullName);
@ -139,8 +185,11 @@ public abstract class AbstractScreenCapture<TColor> : IScreenCapture
return CaptureZones.Remove(captureZone); return CaptureZones.Remove(captureZone);
} }
/// <inheritdoc />
void IScreenCapture.UpdateCaptureZone(ICaptureZone captureZone, int? x, int? y, int? width, int? height, int? downscaleLevel) void IScreenCapture.UpdateCaptureZone(ICaptureZone captureZone, int? x, int? y, int? width, int? height, int? downscaleLevel)
=> UpdateCaptureZone(captureZone as CaptureZone<TColor> ?? throw new ArgumentException("Invalid capture-zone."), x, y, width, height, downscaleLevel); => UpdateCaptureZone(captureZone as CaptureZone<TColor> ?? throw new ArgumentException("Invalid capture-zone."), x, y, width, height, downscaleLevel);
/// <inheritdoc cref="IScreenCapture.UpdateCaptureZone" />
public virtual void UpdateCaptureZone(CaptureZone<TColor> captureZone, int? x = null, int? y = null, int? width = null, int? height = null, int? downscaleLevel = null) public virtual void UpdateCaptureZone(CaptureZone<TColor> captureZone, int? x = null, int? y = null, int? width = null, int? height = null, int? downscaleLevel = null)
{ {
if (_isDisposed) throw new ObjectDisposedException(GetType().FullName); if (_isDisposed) throw new ObjectDisposedException(GetType().FullName);
@ -169,6 +218,7 @@ public abstract class AbstractScreenCapture<TColor> : IScreenCapture
} }
} }
/// <inheritdoc />
public virtual void Restart() public virtual void Restart()
{ {
if (_isDisposed) throw new ObjectDisposedException(GetType().FullName); if (_isDisposed) throw new ObjectDisposedException(GetType().FullName);
@ -190,6 +240,7 @@ public abstract class AbstractScreenCapture<TColor> : IScreenCapture
_isDisposed = true; _isDisposed = true;
} }
/// <inheritdoc cref="Dispose" />
protected virtual void Dispose(bool disposing) { } protected virtual void Dispose(bool disposing) { }
#endregion #endregion

View File

@ -17,98 +17,89 @@ public sealed class CaptureZone<TColor> : ICaptureZone
private readonly object _lock = new(); private readonly object _lock = new();
/// <inheritdoc />
public Display Display { get; } public Display Display { get; }
/// <inheritdoc />
public ColorFormat ColorFormat public ColorFormat ColorFormat
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
get => TColor.ColorFormat; get => TColor.ColorFormat;
} }
/// <summary> /// <inheritdoc />
/// Gets the x-location of the region on the screen.
/// </summary>
public int X { get; internal set; } public int X { get; internal set; }
/// <summary> /// <inheritdoc />
/// Gets the y-location of the region on the screen.
/// </summary>
public int Y { get; internal set; } public int Y { get; internal set; }
/// <summary> /// <inheritdoc />
/// Gets the width of the captured region.
/// </summary>
public int Width { get; private set; } public int Width { get; private set; }
/// <summary> /// <inheritdoc />
/// Gets the height of the captured region.
/// </summary>
public int Height { get; private set; } public int Height { get; private set; }
/// <inheritdoc />
public int Stride public int Stride
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
get => Width * ColorFormat.BytesPerPixel; get => Width * ColorFormat.BytesPerPixel;
} }
/// <summary> /// <inheritdoc />
/// Gets the level of downscaling applied to the image of this region before copying to local memory. The calculation is (width and height)/2^downscaleLevel.
/// </summary>
public int DownscaleLevel { get; private set; } public int DownscaleLevel { get; private set; }
/// <summary> /// <inheritdoc />
/// Gets the original width of the region (this equals <see cref="Width"/> if <see cref="DownscaleLevel"/> is 0).
/// </summary>
public int UnscaledWidth { get; private set; } public int UnscaledWidth { get; private set; }
/// <summary> /// <inheritdoc />
/// Gets the original height of the region (this equals <see cref="Height"/> if <see cref="DownscaleLevel"/> is 0).
/// </summary>
public int UnscaledHeight { get; private set; } public int UnscaledHeight { get; private set; }
internal byte[] InternalBuffer { get; set; } internal byte[] InternalBuffer { get; set; }
/// <inheritdoc />
public ReadOnlySpan<byte> RawBuffer public ReadOnlySpan<byte> RawBuffer
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
get => InternalBuffer; get => InternalBuffer;
} }
/// <summary>
/// Gets the pixel-data of this zone.
/// </summary>
public ReadOnlySpan<TColor> Pixels public ReadOnlySpan<TColor> Pixels
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
get => MemoryMarshal.Cast<byte, TColor>(RawBuffer); get => MemoryMarshal.Cast<byte, TColor>(RawBuffer);
} }
/// <summary>
/// Gets a <see cref="RefImage{TColor}"/>. Basically the same as <see cref="Image"/> but with better performance.
/// </summary>
public RefImage<TColor> Image public RefImage<TColor> Image
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
get => new(Pixels, 0, 0, Width, Height, Width); get => new(Pixels, 0, 0, Width, Height, Width);
} }
/// <inheritdoc />
IImage ICaptureZone.Image IImage ICaptureZone.Image
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
get => new Image<TColor>(InternalBuffer, 0, 0, Width, Height, Width); get => new Image<TColor>(InternalBuffer, 0, 0, Width, Height, Width);
} }
/// <summary> /// <inheritdoc />
/// Gets or sets if the <see cref="CaptureZone{T}"/> should be automatically updated on every captured frame.
/// </summary>
public bool AutoUpdate { get; set; } = true; public bool AutoUpdate { get; set; } = true;
/// <summary> /// <inheritdoc />
/// Gets if an update for the <see cref="CaptureZone{T}"/> is requested on the next captured frame.
/// </summary>
public bool IsUpdateRequested { get; private set; } public bool IsUpdateRequested { get; private set; }
#endregion #endregion
#region Events #region Events
/// <summary> /// <inheritdoc />
/// Occurs when the <see cref="CaptureZone{T}"/> is updated.
/// </summary>
public event EventHandler? Updated; public event EventHandler? Updated;
#endregion #endregion
@ -146,6 +137,7 @@ public sealed class CaptureZone<TColor> : ICaptureZone
#region Methods #region Methods
/// <inheritdoc />
public RefImage<T> GetRefImage<T>() public RefImage<T> GetRefImage<T>()
where T : struct, IColor where T : struct, IColor
{ {
@ -154,16 +146,14 @@ public sealed class CaptureZone<TColor> : ICaptureZone
return new RefImage<T>(MemoryMarshal.Cast<byte, T>(RawBuffer), 0, 0, Width, Height, Width); return new RefImage<T>(MemoryMarshal.Cast<byte, T>(RawBuffer), 0, 0, Width, Height, Width);
} }
/// <inheritdoc />
public IDisposable Lock() public IDisposable Lock()
{ {
Monitor.Enter(_lock); Monitor.Enter(_lock);
return new UnlockDisposable(_lock); return new UnlockDisposable(_lock);
} }
/// <summary> /// <inheritdoc />
/// Requests to update this <see cref="CaptureZone{T}"/> when the next frame is captured.
/// Only necessary if <see cref="AutoUpdate"/> is set to <c>false</c>.
/// </summary>
public void RequestUpdate() => IsUpdateRequested = true; public void RequestUpdate() => IsUpdateRequested = true;
/// <summary> /// <summary>
@ -209,6 +199,7 @@ public sealed class CaptureZone<TColor> : ICaptureZone
#region Methods #region Methods
/// <inheritdoc />
public void Dispose() public void Dispose()
{ {
if (_disposed) throw new ObjectDisposedException("The lock is already released"); if (_disposed) throw new ObjectDisposedException("The lock is already released");

View File

@ -5,12 +5,16 @@ using System.Runtime.InteropServices;
namespace ScreenCapture.NET; namespace ScreenCapture.NET;
/// <summary>
/// Represents a color in 32 bit ABGR-format.
/// </summary>
[DebuggerDisplay("[A: {A}, R: {R}, G: {G}, B: {B}]")] [DebuggerDisplay("[A: {A}, R: {R}, G: {G}, B: {B}]")]
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public readonly struct ColorABGR : IColor public readonly struct ColorABGR : IColor
{ {
#region Properties & Fields #region Properties & Fields
/// <inheritdoc />
public static ColorFormat ColorFormat => ColorFormat.ABGR; public static ColorFormat ColorFormat => ColorFormat.ABGR;
private readonly byte _a; private readonly byte _a;
@ -19,16 +23,30 @@ public readonly struct ColorABGR : IColor
private readonly byte _r; private readonly byte _r;
// ReSharper disable ConvertToAutoPropertyWhenPossible // ReSharper disable ConvertToAutoPropertyWhenPossible
/// <inheritdoc />
public byte A => _a; public byte A => _a;
/// <inheritdoc />
public byte B => _b; public byte B => _b;
/// <inheritdoc />
public byte G => _g; public byte G => _g;
/// <inheritdoc />
public byte R => _r; public byte R => _r;
// ReSharper restore ConvertToAutoPropertyWhenPossible // ReSharper restore ConvertToAutoPropertyWhenPossible
#endregion #endregion
#region Constructors #region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="ColorABGR"/> class.
/// </summary>
/// <param name="a">The alpha-component of the color.</param>
/// <param name="b">The blue-component of the color.</param>
/// <param name="g">The green-component of the color.</param>
/// <param name="r">The red-component of the color.</param>
public ColorABGR(byte a, byte b, byte g, byte r) public ColorABGR(byte a, byte b, byte g, byte r)
{ {
this._a = a; this._a = a;
@ -41,6 +59,7 @@ public readonly struct ColorABGR : IColor
#region Methods #region Methods
/// <inheritdoc />
public override string ToString() => $"[A: {_a}, R: {_r}, G: {_g}, B: {_b}]"; public override string ToString() => $"[A: {_a}, R: {_r}, G: {_g}, B: {_b}]";
#endregion #endregion

View File

@ -5,12 +5,16 @@ using System.Runtime.InteropServices;
namespace ScreenCapture.NET; namespace ScreenCapture.NET;
/// <summary>
/// Represents a color in 32 bit ARGB-format.
/// </summary>
[DebuggerDisplay("[A: {A}, R: {R}, G: {G}, B: {B}]")] [DebuggerDisplay("[A: {A}, R: {R}, G: {G}, B: {B}]")]
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public readonly struct ColorARGB : IColor public readonly struct ColorARGB : IColor
{ {
#region Properties & Fields #region Properties & Fields
/// <inheritdoc />
public static ColorFormat ColorFormat => ColorFormat.ARGB; public static ColorFormat ColorFormat => ColorFormat.ARGB;
private readonly byte _a; private readonly byte _a;
@ -19,9 +23,16 @@ public readonly struct ColorARGB : IColor
private readonly byte _b; private readonly byte _b;
// ReSharper disable ConvertToAutoPropertyWhenPossible // ReSharper disable ConvertToAutoPropertyWhenPossible
/// <inheritdoc />
public byte A => _a; public byte A => _a;
/// <inheritdoc />
public byte R => _r; public byte R => _r;
/// <inheritdoc />
public byte G => _g; public byte G => _g;
/// <inheritdoc />
public byte B => _b; public byte B => _b;
// ReSharper restore ConvertToAutoPropertyWhenPossible // ReSharper restore ConvertToAutoPropertyWhenPossible
@ -29,6 +40,13 @@ public readonly struct ColorARGB : IColor
#region Constructors #region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="ColorARGB"/> class.
/// </summary>
/// <param name="a">The alpha-component of the color.</param>
/// <param name="r">The red-component of the color.</param>
/// <param name="g">The green-component of the color.</param>
/// <param name="b">The blue-component of the color.</param>
public ColorARGB(byte a, byte r, byte g, byte b) public ColorARGB(byte a, byte r, byte g, byte b)
{ {
this._a = a; this._a = a;
@ -41,6 +59,7 @@ public readonly struct ColorARGB : IColor
#region Methods #region Methods
/// <inheritdoc />
public override string ToString() => $"[A: {_a}, R: {_r}, G: {_g}, B: {_b}]"; public override string ToString() => $"[A: {_a}, R: {_r}, G: {_g}, B: {_b}]";
#endregion #endregion

View File

@ -5,12 +5,16 @@ using System.Runtime.InteropServices;
namespace ScreenCapture.NET; namespace ScreenCapture.NET;
/// <summary>
/// Represents a color in 24 bit BGR-format.
/// </summary>
[DebuggerDisplay("[A: {A}, R: {R}, G: {G}, B: {B}]")] [DebuggerDisplay("[A: {A}, R: {R}, G: {G}, B: {B}]")]
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public readonly struct ColorBGR : IColor public readonly struct ColorBGR : IColor
{ {
#region Properties & Fields #region Properties & Fields
/// <inheritdoc />
public static ColorFormat ColorFormat => ColorFormat.BGR; public static ColorFormat ColorFormat => ColorFormat.BGR;
private readonly byte _b; private readonly byte _b;
@ -18,9 +22,16 @@ public readonly struct ColorBGR : IColor
private readonly byte _r; private readonly byte _r;
// ReSharper disable ConvertToAutoPropertyWhenPossible // ReSharper disable ConvertToAutoPropertyWhenPossible
/// <inheritdoc />
public byte A => byte.MaxValue; public byte A => byte.MaxValue;
/// <inheritdoc />
public byte B => _b; public byte B => _b;
/// <inheritdoc />
public byte G => _g; public byte G => _g;
/// <inheritdoc />
public byte R => _r; public byte R => _r;
// ReSharper restore ConvertToAutoPropertyWhenPossible // ReSharper restore ConvertToAutoPropertyWhenPossible
@ -28,6 +39,12 @@ public readonly struct ColorBGR : IColor
#region Constructors #region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="ColorBGR"/> class.
/// </summary>
/// <param name="b">The blue-component of the color.</param>
/// <param name="g">The green-component of the color.</param>
/// <param name="r">The red-component of the color.</param>
public ColorBGR(byte b, byte g, byte r) public ColorBGR(byte b, byte g, byte r)
{ {
this._b = b; this._b = b;
@ -39,6 +56,7 @@ public readonly struct ColorBGR : IColor
#region Methods #region Methods
/// <inheritdoc />
public override string ToString() => $"[A: {A}, R: {_r}, G: {_g}, B: {_b}]"; public override string ToString() => $"[A: {A}, R: {_r}, G: {_g}, B: {_b}]";
#endregion #endregion

View File

@ -5,12 +5,16 @@ using System.Runtime.InteropServices;
namespace ScreenCapture.NET; namespace ScreenCapture.NET;
/// <summary>
/// Represents a color in 32 bit BGRA-format.
/// </summary>
[DebuggerDisplay("[A: {A}, R: {R}, G: {G}, B: {B}]")] [DebuggerDisplay("[A: {A}, R: {R}, G: {G}, B: {B}]")]
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public readonly struct ColorBGRA : IColor public readonly struct ColorBGRA : IColor
{ {
#region Properties & Fields #region Properties & Fields
/// <inheritdoc />
public static ColorFormat ColorFormat => ColorFormat.BGRA; public static ColorFormat ColorFormat => ColorFormat.BGRA;
private readonly byte _b; private readonly byte _b;
@ -19,9 +23,16 @@ public readonly struct ColorBGRA : IColor
private readonly byte _a; private readonly byte _a;
// ReSharper disable ConvertToAutoPropertyWhenPossible // ReSharper disable ConvertToAutoPropertyWhenPossible
/// <inheritdoc />
public byte B => _b; public byte B => _b;
/// <inheritdoc />
public byte G => _g; public byte G => _g;
/// <inheritdoc />
public byte R => _r; public byte R => _r;
/// <inheritdoc />
public byte A => _a; public byte A => _a;
// ReSharper restore ConvertToAutoPropertyWhenPossible // ReSharper restore ConvertToAutoPropertyWhenPossible
@ -29,6 +40,13 @@ public readonly struct ColorBGRA : IColor
#region Constructors #region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="ColorBGRA"/> class.
/// </summary>
/// <param name="b">The blue-component of the color.</param>
/// <param name="g">The green-component of the color.</param>
/// <param name="r">The red-component of the color.</param>
/// <param name="a">The alpha-component of the color.</param>
public ColorBGRA(byte b, byte g, byte r, byte a) public ColorBGRA(byte b, byte g, byte r, byte a)
{ {
this._b = b; this._b = b;
@ -41,6 +59,7 @@ public readonly struct ColorBGRA : IColor
#region Methods #region Methods
/// <inheritdoc />
public override string ToString() => $"[A: {_a}, R: {_r}, G: {_g}, B: {_b}]"; public override string ToString() => $"[A: {_a}, R: {_r}, G: {_g}, B: {_b}]";
#endregion #endregion

View File

@ -1,5 +1,8 @@
namespace ScreenCapture.NET; namespace ScreenCapture.NET;
/// <summary>
/// Represents a color format.
/// </summary>
public readonly struct ColorFormat public readonly struct ColorFormat
{ {
#region Instances #region Instances
@ -15,7 +18,14 @@ public readonly struct ColorFormat
#region Properties & Fields #region Properties & Fields
/// <summary>
/// Gets the Id of the color-format.
/// </summary>
public readonly int Id; public readonly int Id;
/// <summary>
/// Gets the Bytes per pixel for this color-format.
/// </summary>
public readonly int BytesPerPixel; public readonly int BytesPerPixel;
#endregion #endregion

View File

@ -5,12 +5,16 @@ using System.Runtime.InteropServices;
namespace ScreenCapture.NET; namespace ScreenCapture.NET;
/// <summary>
/// Represents a color in 24 bit RGB-format.
/// </summary>
[DebuggerDisplay("[A: {A}, R: {R}, G: {G}, B: {B}]")] [DebuggerDisplay("[A: {A}, R: {R}, G: {G}, B: {B}]")]
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public readonly struct ColorRGB : IColor public readonly struct ColorRGB : IColor
{ {
#region Properties & Fields #region Properties & Fields
/// <inheritdoc />
public static ColorFormat ColorFormat => ColorFormat.RGB; public static ColorFormat ColorFormat => ColorFormat.RGB;
private readonly byte _r; private readonly byte _r;
@ -18,9 +22,16 @@ public readonly struct ColorRGB : IColor
private readonly byte _b; private readonly byte _b;
// ReSharper disable ConvertToAutoPropertyWhenPossible // ReSharper disable ConvertToAutoPropertyWhenPossible
/// <inheritdoc />
public byte A => byte.MaxValue; public byte A => byte.MaxValue;
/// <inheritdoc />
public byte R => _r; public byte R => _r;
/// <inheritdoc />
public byte G => _g; public byte G => _g;
/// <inheritdoc />
public byte B => _b; public byte B => _b;
// ReSharper restore ConvertToAutoPropertyWhenPossible // ReSharper restore ConvertToAutoPropertyWhenPossible
@ -28,6 +39,12 @@ public readonly struct ColorRGB : IColor
#region Constructors #region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="ColorRGB"/> class.
/// </summary>
/// <param name="r">The red-component of the color.</param>
/// <param name="g">The green-component of the color.</param>
/// <param name="b">The blue-component of the color.</param>
public ColorRGB(byte r, byte g, byte b) public ColorRGB(byte r, byte g, byte b)
{ {
this._r = r; this._r = r;
@ -39,6 +56,7 @@ public readonly struct ColorRGB : IColor
#region Methods #region Methods
/// <inheritdoc />
public override string ToString() => $"[A: {A}, R: {_r}, G: {_g}, B: {_b}]"; public override string ToString() => $"[A: {A}, R: {_r}, G: {_g}, B: {_b}]";
#endregion #endregion

View File

@ -5,12 +5,16 @@ using System.Runtime.InteropServices;
namespace ScreenCapture.NET; namespace ScreenCapture.NET;
/// <summary>
/// Represents a color in 32 bit RGBA-format.
/// </summary>
[DebuggerDisplay("[A: {A}, R: {R}, G: {G}, B: {B}]")] [DebuggerDisplay("[A: {A}, R: {R}, G: {G}, B: {B}]")]
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public readonly struct ColorRGBA : IColor public readonly struct ColorRGBA : IColor
{ {
#region Properties & Fields #region Properties & Fields
/// <inheritdoc />
public static ColorFormat ColorFormat => ColorFormat.RGBA; public static ColorFormat ColorFormat => ColorFormat.RGBA;
private readonly byte _r; private readonly byte _r;
@ -19,9 +23,16 @@ public readonly struct ColorRGBA : IColor
private readonly byte _a; private readonly byte _a;
// ReSharper disable ConvertToAutoPropertyWhenPossible // ReSharper disable ConvertToAutoPropertyWhenPossible
/// <inheritdoc />
public byte R => _r; public byte R => _r;
/// <inheritdoc />
public byte G => _g; public byte G => _g;
/// <inheritdoc />
public byte B => _b; public byte B => _b;
/// <inheritdoc />
public byte A => _a; public byte A => _a;
// ReSharper restore ConvertToAutoPropertyWhenPossible // ReSharper restore ConvertToAutoPropertyWhenPossible
@ -29,6 +40,13 @@ public readonly struct ColorRGBA : IColor
#region Constructors #region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="ColorRGBA"/> class.
/// </summary>
/// <param name="r">The red-component of the color.</param>
/// <param name="g">The green-component of the color.</param>
/// <param name="b">The blue-component of the color.</param>
/// <param name="a">The alpha-component of the color.</param>
public ColorRGBA(byte r, byte g, byte b, byte a) public ColorRGBA(byte r, byte g, byte b, byte a)
{ {
this._r = r; this._r = r;
@ -41,6 +59,7 @@ public readonly struct ColorRGBA : IColor
#region Methods #region Methods
/// <inheritdoc />
public override string ToString() => $"[A: {_a}, R: {_r}, G: {_g}, B: {_b}]"; public override string ToString() => $"[A: {_a}, R: {_r}, G: {_g}, B: {_b}]";
#endregion #endregion

View File

@ -2,12 +2,33 @@
namespace ScreenCapture.NET; namespace ScreenCapture.NET;
/// <summary>
/// Represents a generic color made of 4 bytes (alpha, red, green and blue)
/// </summary>
public interface IColor public interface IColor
{ {
/// <summary>
/// Gets the red-component of this color.
/// </summary>
byte R { get; } byte R { get; }
/// <summary>
/// Gets the green-component of this color.
/// </summary>
byte G { get; } byte G { get; }
/// <summary>
/// Gets the blue-component of this color.
/// </summary>
byte B { get; } byte B { get; }
/// <summary>
/// Gets the alpha-component of this color.
/// </summary>
byte A { get; } byte A { get; }
/// <summary>
/// Gets the color-format of this color.
/// </summary>
public static virtual ColorFormat ColorFormat => throw new NotSupportedException(); public static virtual ColorFormat ColorFormat => throw new NotSupportedException();
} }

View File

@ -2,61 +2,102 @@
namespace ScreenCapture.NET; namespace ScreenCapture.NET;
/// <summary>
/// Represents a zone on the screen to be captured.
/// </summary>
public interface ICaptureZone public interface ICaptureZone
{ {
/// <summary>
/// Gets the display this zone is on.
/// </summary>
Display Display { get; } Display Display { get; }
/// <summary>
/// Gets the color-format used in the buffer of this zone.
/// </summary>
ColorFormat ColorFormat { get; }
/// <summary> /// <summary>
/// Gets the x-location of the region on the screen. /// Gets the x-location of the region on the screen.
/// </summary> /// </summary>
int X { get; } int X { get; }
/// <summary> /// <summary>
/// Gets the y-location of the region on the screen. /// Gets the y-location of the region on the screen.
/// </summary> /// </summary>
int Y { get; } int Y { get; }
/// <summary> /// <summary>
/// Gets the width of the captured region. /// Gets the width of the captured region.
/// </summary> /// </summary>
int Width { get; } int Width { get; }
/// <summary> /// <summary>
/// Gets the height of the captured region. /// Gets the height of the captured region.
/// </summary> /// </summary>
int Height { get; } int Height { get; }
/// <summary>
/// Gets the stride of the buffer.
/// </summary>
int Stride { get; }
/// <summary> /// <summary>
/// Gets the level of downscaling applied to the image of this region before copying to local memory. The calculation is (width and height)/2^downscaleLevel. /// Gets the level of downscaling applied to the image of this region before copying to local memory. The calculation is (width and height)/2^downscaleLevel.
/// </summary> /// </summary>
int DownscaleLevel { get; } int DownscaleLevel { get; }
/// <summary> /// <summary>
/// Gets the original width of the region (this equals <see cref="Width"/> if <see cref="DownscaleLevel"/> is 0). /// Gets the original width of the region (this equals <see cref="Width"/> if <see cref="DownscaleLevel"/> is 0).
/// </summary> /// </summary>
int UnscaledWidth { get; } int UnscaledWidth { get; }
/// <summary> /// <summary>
/// Gets the original height of the region (this equals <see cref="Height"/> if <see cref="DownscaleLevel"/> is 0). /// Gets the original height of the region (this equals <see cref="Height"/> if <see cref="DownscaleLevel"/> is 0).
/// </summary> /// </summary>
int UnscaledHeight { get; } int UnscaledHeight { get; }
/// <summary>
/// Gets the raw buffer of this zone.
/// </summary>
ReadOnlySpan<byte> RawBuffer { get; } ReadOnlySpan<byte> RawBuffer { get; }
/// <summary>
/// Gets the <see cref="IImage"/> represented by the buffer of this zone.
/// </summary>
IImage Image { get; } IImage Image { get; }
/// <summary> /// <summary>
/// Gets or sets if the <see cref="ICaptureZone"/> should be automatically updated on every captured frame. /// Gets or sets if the <see cref="ICaptureZone"/> should be automatically updated on every captured frame.
/// </summary> /// </summary>
bool AutoUpdate { get; set; } bool AutoUpdate { get; set; }
/// <summary> /// <summary>
/// Gets if an update for the <see cref="ICaptureZone"/> is requested on the next captured frame. /// Gets if an update for the <see cref="ICaptureZone"/> is requested on the next captured frame.
/// </summary> /// </summary>
bool IsUpdateRequested { get; } bool IsUpdateRequested { get; }
/// <summary> /// <summary>
/// Occurs when the <see cref="ICaptureZone"/> is updated. /// Occurs when the <see cref="ICaptureZone"/> is updated.
/// </summary> /// </summary>
event EventHandler? Updated; event EventHandler? Updated;
/// <summary>
/// Locks the image for use. Unlock by disposing the returned disposable.
/// </summary>
/// <returns>The disposable used to unlock the image.</returns>
IDisposable Lock();
/// <summary> /// <summary>
/// Requests to update this <see cref="ICaptureZone"/> when the next frame is captured. /// Requests to update this <see cref="ICaptureZone"/> when the next frame is captured.
/// Only necessary if <see cref="AutoUpdate"/> is set to <c>false</c>. /// Only necessary if <see cref="AutoUpdate"/> is set to <c>false</c>.
/// </summary> /// </summary>
void RequestUpdate(); void RequestUpdate();
RefImage<TColor> GetRefImage<TColor>() /// <summary>
where TColor : struct, IColor; /// Gets a <see cref="RefImage{TColor}"/>. Basically the same as <see cref="Image"/> but with better performance if the color-layout is known.
/// </summary>
/// <typeparam name="TColor">The color used by the buffer of this zone.</typeparam>
/// <returns>The <see cref="RefImage{TColor}"/> representing this zone.</returns>
RefImage<TColor> GetRefImage<TColor>() where TColor : struct, IColor;
} }

View File

@ -2,38 +2,118 @@
namespace ScreenCapture.NET; namespace ScreenCapture.NET;
/// <summary>
/// Represents a image.
/// </summary>
public interface IImage : IEnumerable<IColor> public interface IImage : IEnumerable<IColor>
{ {
/// <summary>
/// Gets the width of this image.
/// </summary>
int Width { get; } int Width { get; }
/// <summary>
/// Gets the height of this image.
/// </summary>
int Height { get; } int Height { get; }
/// <summary>
/// Gets the color at the specified location.
/// </summary>
/// <param name="x">The X-location to read.</param>
/// <param name="y">The Y-location to read.</param>
/// <returns>The color at the specified location.</returns>
IColor this[int x, int y] { get; } IColor this[int x, int y] { get; }
/// <summary>
/// Gets an image representing the specified location.
/// </summary>
/// <param name="x">The X-location of the image.</param>
/// <param name="y">The Y-location of the image.</param>
/// <param name="width">The width of the sub-image.</param>
/// <param name="height"></param>
/// <returns></returns>
IImage this[int x, int y, int width, int height] { get; } IImage this[int x, int y, int width, int height] { get; }
/// <summary>
/// Gets a list of all rows of this image.
/// </summary>
IImageRows Rows { get; } IImageRows Rows { get; }
/// <summary>
/// Gets a list of all columns of this image.
/// </summary>
IImageColumns Columns { get; } IImageColumns Columns { get; }
/// <summary>
/// Represents a list of rows of an image.
/// </summary>
public interface IImageRows : IEnumerable<IImageRow> public interface IImageRows : IEnumerable<IImageRow>
{ {
/// <summary>
/// Gets the amount of rows in this list.
/// </summary>
int Count { get; } int Count { get; }
/// <summary>
/// Gets a specific <see cref="IImageRow"/>.
/// </summary>
/// <param name="column">The ´row to get.</param>
/// <returns>The requested <see cref="IImageRow"/>.</returns>
IImageRow this[int column] { get; } IImageRow this[int column] { get; }
} }
/// <summary>
/// Represents a list of columns of an image.
/// </summary>
public interface IImageColumns : IEnumerable<IImageColumn> public interface IImageColumns : IEnumerable<IImageColumn>
{ {
/// <summary>
/// Gets the amount of columns in this list.
/// </summary>
int Count { get; } int Count { get; }
/// <summary>
/// Gets a specific <see cref="IImageColumn"/>.
/// </summary>
/// <param name="column">The column to get.</param>
/// <returns>The requested <see cref="IImageColumn"/>.</returns>
IImageColumn this[int column] { get; } IImageColumn this[int column] { get; }
} }
/// <summary>
/// Represents a single row of an image.
/// </summary>
public interface IImageRow : IEnumerable<IColor> public interface IImageRow : IEnumerable<IColor>
{ {
/// <summary>
/// Gets the length of the row.
/// </summary>
int Length { get; } int Length { get; }
/// <summary>
/// Gets the <see cref="IColor"/> at the specified location.
/// </summary>
/// <param name="x">The location to get the color from.</param>
/// <returns>The <see cref="IColor"/> at the specified location.</returns>
IColor this[int x] { get; } IColor this[int x] { get; }
} }
/// <summary>
/// Represents a single column of an image.
/// </summary>
public interface IImageColumn : IEnumerable<IColor> public interface IImageColumn : IEnumerable<IColor>
{ {
/// <summary>
/// Gets the length of the column.
/// </summary>
int Length { get; } int Length { get; }
/// <summary>
/// Gets the <see cref="IColor"/> at the specified location.
/// </summary>
/// <param name="y">The location to get the color from.</param>
/// <returns>The <see cref="IColor"/> at the specified location.</returns>
IColor this[int y] { get; } IColor this[int y] { get; }
} }
} }

View File

@ -6,6 +6,7 @@ using System.Runtime.InteropServices;
namespace ScreenCapture.NET; namespace ScreenCapture.NET;
/// <inheritdoc />
public sealed class Image<TColor> : IImage public sealed class Image<TColor> : IImage
where TColor : struct, IColor where TColor : struct, IColor
{ {
@ -17,13 +18,17 @@ public sealed class Image<TColor> : IImage
private readonly int _y; private readonly int _y;
private readonly int _stride; private readonly int _stride;
/// <inheritdoc />
public int Width { get; } public int Width { get; }
/// <inheritdoc />
public int Height { get; } public int Height { get; }
#endregion #endregion
#region Indexer #region Indexer
/// <inheritdoc />
public IColor this[int x, int y] public IColor this[int x, int y]
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -35,6 +40,7 @@ public sealed class Image<TColor> : IImage
} }
} }
/// <inheritdoc />
public IImage this[int x, int y, int width, int height] public IImage this[int x, int y, int width, int height]
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -46,12 +52,14 @@ public sealed class Image<TColor> : IImage
} }
} }
/// <inheritdoc />
public IImage.IImageRows Rows public IImage.IImageRows Rows
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
get => new ImageRows(_buffer, _x, _y, Width, Height, _stride); get => new ImageRows(_buffer, _x, _y, Width, Height, _stride);
} }
/// <inheritdoc />
public IImage.IImageColumns Columns public IImage.IImageColumns Columns
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -76,6 +84,7 @@ public sealed class Image<TColor> : IImage
#region Methods #region Methods
/// <inheritdoc />
public IEnumerator<IColor> GetEnumerator() public IEnumerator<IColor> GetEnumerator()
{ {
for (int y = 0; y < Height; y++) for (int y = 0; y < Height; y++)
@ -83,12 +92,14 @@ public sealed class Image<TColor> : IImage
yield return this[x, y]; yield return this[x, y];
} }
/// <inheritdoc />
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
#endregion #endregion
#region Indexer-Classes #region Indexer-Classes
/// <inheritdoc />
private sealed class ImageRows : IImage.IImageRows private sealed class ImageRows : IImage.IImageRows
{ {
#region Properties & Fields #region Properties & Fields
@ -100,12 +111,14 @@ public sealed class Image<TColor> : IImage
private readonly int _height; private readonly int _height;
private readonly int _stride; private readonly int _stride;
/// <inheritdoc />
public int Count => _height; public int Count => _height;
#endregion #endregion
#region Indexer #region Indexer
/// <inheritdoc />
public IImage.IImageRow this[int row] public IImage.IImageRow this[int row]
{ {
get get
@ -134,17 +147,20 @@ public sealed class Image<TColor> : IImage
#region Methods #region Methods
/// <inheritdoc />
public IEnumerator<IImage.IImageRow> GetEnumerator() public IEnumerator<IImage.IImageRow> GetEnumerator()
{ {
for (int y = 0; y < _height; y++) for (int y = 0; y < _height; y++)
yield return this[y]; yield return this[y];
} }
/// <inheritdoc />
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
#endregion #endregion
} }
/// <inheritdoc />
private sealed class ImageRow : IImage.IImageRow private sealed class ImageRow : IImage.IImageRow
{ {
#region Properties & Fields #region Properties & Fields
@ -153,12 +169,14 @@ public sealed class Image<TColor> : IImage
private readonly int _start; private readonly int _start;
private readonly int _length; private readonly int _length;
/// <inheritdoc />
public int Length => _length; public int Length => _length;
#endregion #endregion
#region Indexer #region Indexer
/// <inheritdoc />
public IColor this[int x] public IColor this[int x]
{ {
get get
@ -185,17 +203,20 @@ public sealed class Image<TColor> : IImage
#region Methods #region Methods
/// <inheritdoc />
public IEnumerator<IColor> GetEnumerator() public IEnumerator<IColor> GetEnumerator()
{ {
for (int x = 0; x < _length; x++) for (int x = 0; x < _length; x++)
yield return this[x]; yield return this[x];
} }
/// <inheritdoc />
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
#endregion #endregion
} }
/// <inheritdoc />
private sealed class ImageColumns : IImage.IImageColumns private sealed class ImageColumns : IImage.IImageColumns
{ {
#region Properties & Fields #region Properties & Fields
@ -207,12 +228,14 @@ public sealed class Image<TColor> : IImage
private readonly int _height; private readonly int _height;
private readonly int _stride; private readonly int _stride;
/// <inheritdoc />
public int Count => _width; public int Count => _width;
#endregion #endregion
#region Indexer #region Indexer
/// <inheritdoc />
public IImage.IImageColumn this[int column] public IImage.IImageColumn this[int column]
{ {
get get
@ -241,17 +264,20 @@ public sealed class Image<TColor> : IImage
#region Methods #region Methods
/// <inheritdoc />
public IEnumerator<IImage.IImageColumn> GetEnumerator() public IEnumerator<IImage.IImageColumn> GetEnumerator()
{ {
for (int y = 0; y < _height; y++) for (int y = 0; y < _height; y++)
yield return this[y]; yield return this[y];
} }
/// <inheritdoc />
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
#endregion #endregion
} }
/// <inheritdoc />
private sealed class ImageColumn : IImage.IImageColumn private sealed class ImageColumn : IImage.IImageColumn
{ {
#region Properties & Fields #region Properties & Fields
@ -261,12 +287,14 @@ public sealed class Image<TColor> : IImage
private readonly int _length; private readonly int _length;
private readonly int _step; private readonly int _step;
/// <inheritdoc />
public int Length => _length; public int Length => _length;
#endregion #endregion
#region Indexer #region Indexer
/// <inheritdoc />
public IColor this[int y] public IColor this[int y]
{ {
get get
@ -294,12 +322,14 @@ public sealed class Image<TColor> : IImage
#region Methods #region Methods
/// <inheritdoc />
public IEnumerator<IColor> GetEnumerator() public IEnumerator<IColor> GetEnumerator()
{ {
for (int y = 0; y < _length; y++) for (int y = 0; y < _length; y++)
yield return this[y]; yield return this[y];
} }
/// <inheritdoc />
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
#endregion #endregion