diff --git a/ScreenCapture.NET/Extensions/BlackBarDetection.cs b/ScreenCapture.NET/Extensions/BlackBarDetection.cs new file mode 100644 index 0000000..4042fee --- /dev/null +++ b/ScreenCapture.NET/Extensions/BlackBarDetection.cs @@ -0,0 +1,188 @@ +namespace ScreenCapture.NET; + +/// +/// Helper-class for black-bar removal. +/// +public static class BlackBarDetection +{ + #region IImage + + /// + /// Create an image with black bars removed + /// + /// The image the bars are removed from. + /// The threshold of "blackness" used to detect black bars. (e. g. Threshold 5 will consider a pixel of color [5,5,5] as black.) + /// A bool indicating if black bars should be removed at the top of the image. + /// A bool indicating if black bars should be removed at the bottom of the image. + /// A bool indicating if black bars should be removed on the left side of the image. + /// A bool indicating if black bars should be removed on the right side of the image. + /// The image with black bars removed. + public static IImage RemoveBlackBars(this IImage image, int threshold = 0, bool removeTop = true, bool removeBottom = true, bool removeLeft = true, bool removeRight = true) + { + int top = removeTop ? CalculateTop(image, threshold) : 0; + int bottom = removeBottom ? CalculateBottom(image, threshold) : image.Height; + int left = removeLeft ? CalculateLeft(image, threshold) : 0; + int right = removeRight ? CalculateRight(image, threshold) : image.Width; + + return image[left, top, right - left, bottom - top]; + } + + private static int CalculateTop(IImage image, int threshold) + { + IImage.IImageRows rows = image.Rows; + for (int y = 0; y < rows.Count; y++) + { + IImage.IImageRow row = rows[y]; + foreach (IColor color in row) + { + if ((color.R > threshold) || (color.G > threshold) || (color.B > threshold)) + return y; + } + } + + return 0; + } + + private static int CalculateBottom(IImage image, int threshold) + { + IImage.IImageRows rows = image.Rows; + for (int y = rows.Count - 1; y >= 0; y--) + { + IImage.IImageRow row = rows[y]; + foreach (IColor color in row) + { + if ((color.R > threshold) || (color.G > threshold) || (color.B > threshold)) + return y; + } + } + + return rows.Count; + } + + private static int CalculateLeft(IImage image, int threshold) + { + IImage.IImageColumns columns = image.Columns; + for (int x = 0; x < columns.Count; x++) + { + IImage.IImageColumn column = columns[x]; + foreach (IColor color in column) + { + if ((color.R > threshold) || (color.G > threshold) || (color.B > threshold)) + return x; + } + } + + return 0; + } + + private static int CalculateRight(IImage image, int threshold) + { + IImage.IImageColumns columns = image.Columns; + for (int x = columns.Count - 1; x >= 0; x--) + { + IImage.IImageColumn column = columns[x]; + foreach (IColor color in column) + { + if ((color.R > threshold) || (color.G > threshold) || (color.B > threshold)) + return x; + } + } + + return columns.Count; + } + + #endregion + + #region RefImage + + /// + /// Create an image with black bars removed + /// + /// The image the bars are removed from. + /// The threshold of "blackness" used to detect black bars. (e. g. Threshold 5 will consider a pixel of color [5,5,5] as black.) + /// A bool indicating if black bars should be removed at the top of the image. + /// A bool indicating if black bars should be removed at the bottom of the image. + /// A bool indicating if black bars should be removed on the left side of the image. + /// A bool indicating if black bars should be removed on the right side of the image. + /// The image with black bars removed. + public static RefImage RemoveBlackBars(this RefImage image, int threshold = 0, bool removeTop = true, bool removeBottom = true, bool removeLeft = true, bool removeRight = true) + where TColor : struct, IColor + { + int top = removeTop ? CalculateTop(image, threshold) : 0; + int bottom = removeBottom ? CalculateBottom(image, threshold) : image.Height; + int left = removeLeft ? CalculateLeft(image, threshold) : 0; + int right = removeRight ? CalculateRight(image, threshold) : image.Width; + + return image[left, top, right - left, bottom - top]; + } + + private static int CalculateTop(this RefImage image, int threshold) + where TColor : struct, IColor + { + RefImage.ImageRows rows = image.Rows; + for (int y = 0; y < rows.Count; y++) + { + ReadOnlyRefEnumerable row = rows[y]; + foreach (TColor color in row) + { + if ((color.R > threshold) || (color.G > threshold) || (color.B > threshold)) + return y; + } + } + + return 0; + } + + private static int CalculateBottom(this RefImage image, int threshold) + where TColor : struct, IColor + { + RefImage.ImageRows rows = image.Rows; + for (int y = rows.Count - 1; y >= 0; y--) + { + ReadOnlyRefEnumerable row = rows[y]; + foreach (TColor color in row) + { + if ((color.R > threshold) || (color.G > threshold) || (color.B > threshold)) + return y; + } + } + + return rows.Count; + } + + private static int CalculateLeft(this RefImage image, int threshold) + where TColor : struct, IColor + { + RefImage.ImageColumns columns = image.Columns; + for (int x = 0; x < columns.Count; x++) + { + ReadOnlyRefEnumerable column = columns[x]; + foreach (TColor color in column) + { + if ((color.R > threshold) || (color.G > threshold) || (color.B > threshold)) + return x; + } + } + + return 0; + } + + private static int CalculateRight(this RefImage image, int threshold) + where TColor : struct, IColor + { + RefImage.ImageColumns columns = image.Columns; + for (int x = columns.Count - 1; x >= 0; x--) + { + ReadOnlyRefEnumerable column = columns[x]; + foreach (TColor color in column) + { + if ((color.R > threshold) || (color.G > threshold) || (color.B > threshold)) + return x; + } + } + + return columns.Count; + } + + #endregion +} \ No newline at end of file diff --git a/ScreenCapture.NET/Model/BlackBarDetection.cs b/ScreenCapture.NET/Model/BlackBarDetection.cs deleted file mode 100644 index 1e93712..0000000 --- a/ScreenCapture.NET/Model/BlackBarDetection.cs +++ /dev/null @@ -1,141 +0,0 @@ -// ReSharper disable MemberCanBePrivate.Global - -using System; - -namespace ScreenCapture.NET; - -/// -/// Represents the configuration for the detection and removal of black bars around the screen image. -/// -public sealed class BlackBarDetection -{ - #region Properties & Fields - - private readonly ICaptureZone _captureZone; - - private int? _top; - /// - /// Gets the size of the detected black bar at the top of the image. - /// - public int Top => _top ??= CalculateTop(); - - private int? _bottom; - /// - /// Gets the size of the detected black bar at the bottom of the image. - /// - public int Bottom => _bottom ??= CalculateBottom(); - - private int? _left; - /// - /// Gets the size of the detected black bar at the left of the image. - /// - public int Left => _left ??= CalculateLeft(); - - private int? _right; - /// - /// Gets the size of the detected black bar at the right of the image. - /// - public int Right => _right ??= CalculateRight(); - - private int _theshold = 0; - /// - /// Gets or sets the threshold of "blackness" used to detect black bars. (e. g. Threshold 5 will consider a pixel of color [5,5,5] as black.) (default 0) - /// - public int Threshold - { - get => _theshold; - set - { - _theshold = value; - InvalidateCache(); - } - } - - #endregion - - #region Constructors - - internal BlackBarDetection(ICaptureZone captureZone) - { - this._captureZone = captureZone; - } - - #endregion - - #region Methods - - /// - /// Invalidates the cached values and recalculates , , and . - /// - public void InvalidateCache() - { - _top = null; - _bottom = null; - _left = null; - _right = null; - } - - private int CalculateTop() - { - //int threshold = Threshold; - //int stride = _captureZone.Stride; - //for (int row = 0; row < _captureZone.Height; row++) - //{ - // Span data = new(_captureZone.Buffer, row * stride, stride); - // for (int i = 0; i < data.Length; i += 4) - // if ((data[i] > threshold) || (data[i + 1] > threshold) || (data[i + 2] > threshold)) - // return row; - //} - - return 0; - } - - private int CalculateBottom() - { - //int threshold = Threshold; - //int stride = _captureZone.Stride; - //for (int row = _captureZone.Height - 1; row >= 0; row--) - //{ - // Span data = new(_captureZone.Buffer, row * stride, stride); - // for (int i = 0; i < data.Length; i += 4) - // if ((data[i] > threshold) || (data[i + 1] > threshold) || (data[i + 2] > threshold)) - // return (_captureZone.Height - 1) - row; - //} - - return 0; - } - - private int CalculateLeft() - { - //int threshold = Threshold; - //int stride = _captureZone.Stride; - //byte[] buffer = _captureZone.Buffer; - //for (int column = 0; column < _captureZone.Width; column++) - // for (int row = 0; row < _captureZone.Height; row++) - // { - // int offset = (stride * row) + (column * 4); - // if ((buffer[offset] > threshold) || (buffer[offset + 1] > threshold) || (buffer[offset + 2] > threshold)) - // return column; - // } - - return 0; - } - - private int CalculateRight() - { - //int threshold = Threshold; - //int stride = _captureZone.Stride; - //byte[] buffer = _captureZone.Buffer; - //for (int column = _captureZone.Width - 1; column >= 0; column--) - // for (int row = 0; row < _captureZone.Height; row++) - // { - // int offset = (stride * row) + (column * 4); - // if ((buffer[offset] > threshold) || (buffer[offset + 1] > threshold) || (buffer[offset + 2] > threshold)) - // return (_captureZone.Width - 1) - column; - // } - - return 0; - } - - #endregion -} \ No newline at end of file diff --git a/ScreenCapture.NET/ScreenCapture.NET.csproj.DotSettings b/ScreenCapture.NET/ScreenCapture.NET.csproj.DotSettings index 3504048..560de9f 100644 --- a/ScreenCapture.NET/ScreenCapture.NET.csproj.DotSettings +++ b/ScreenCapture.NET/ScreenCapture.NET.csproj.DotSettings @@ -2,6 +2,7 @@ True True True + True True True True