mirror of
https://github.com/DarthAffe/ScreenCapture.NET.git
synced 2025-12-12 13:28:35 +00:00
Merge pull request #18 from DarthAffe/FixesAndImprovememnts
Fixes and improvememnts
This commit is contained in:
commit
5eb8b5636e
@ -27,7 +27,13 @@ public static class BlackBarDetection
|
|||||||
return image[left, top, right - left, bottom - top];
|
return image[left, top, right - left, bottom - top];
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int CalculateTop(IImage image, int threshold)
|
/// <summary>
|
||||||
|
/// Calculates the first row starting from the top with at least one non black pixel.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="image">The image to check.</param>
|
||||||
|
/// <param name="threshold">The threshold of "blackness" used to detect black bars. (e. g. Threshold 5 will consider a pixel of color [5,5,5] as black.)</param>
|
||||||
|
/// <returns>The row number of the first row with at least one non-black pixel.</returns>
|
||||||
|
public static int CalculateTop(IImage image, int threshold)
|
||||||
{
|
{
|
||||||
IImage.IImageRows rows = image.Rows;
|
IImage.IImageRows rows = image.Rows;
|
||||||
for (int y = 0; y < rows.Count; y++)
|
for (int y = 0; y < rows.Count; y++)
|
||||||
@ -43,7 +49,13 @@ public static class BlackBarDetection
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int CalculateBottom(IImage image, int threshold)
|
/// <summary>
|
||||||
|
/// Calculates the last row starting from the top with at least one non black pixel.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="image">The image to check.</param>
|
||||||
|
/// <param name="threshold">The threshold of "blackness" used to detect black bars. (e. g. Threshold 5 will consider a pixel of color [5,5,5] as black.)</param>
|
||||||
|
/// <returns>The row number of the last row with at least one non-black pixel.</returns>
|
||||||
|
public static int CalculateBottom(IImage image, int threshold)
|
||||||
{
|
{
|
||||||
IImage.IImageRows rows = image.Rows;
|
IImage.IImageRows rows = image.Rows;
|
||||||
for (int y = rows.Count - 1; y >= 0; y--)
|
for (int y = rows.Count - 1; y >= 0; y--)
|
||||||
@ -59,7 +71,13 @@ public static class BlackBarDetection
|
|||||||
return rows.Count;
|
return rows.Count;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int CalculateLeft(IImage image, int threshold)
|
/// <summary>
|
||||||
|
/// Calculates the first column starting from the left with at least one non black pixel.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="image">The image to check.</param>
|
||||||
|
/// <param name="threshold">The threshold of "blackness" used to detect black bars. (e. g. Threshold 5 will consider a pixel of color [5,5,5] as black.)</param>
|
||||||
|
/// <returns>The column number of the first column with at least one non-black pixel.</returns>
|
||||||
|
public static int CalculateLeft(IImage image, int threshold)
|
||||||
{
|
{
|
||||||
IImage.IImageColumns columns = image.Columns;
|
IImage.IImageColumns columns = image.Columns;
|
||||||
for (int x = 0; x < columns.Count; x++)
|
for (int x = 0; x < columns.Count; x++)
|
||||||
@ -75,7 +93,13 @@ public static class BlackBarDetection
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int CalculateRight(IImage image, int threshold)
|
/// <summary>
|
||||||
|
/// Calculates the last column starting from the top with at least one non black pixel.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="image">The image to check.</param>
|
||||||
|
/// <param name="threshold">The threshold of "blackness" used to detect black bars. (e. g. Threshold 5 will consider a pixel of color [5,5,5] as black.)</param>
|
||||||
|
/// <returns>The column number of the last column with at least one non-black pixel.</returns>
|
||||||
|
public static int CalculateRight(IImage image, int threshold)
|
||||||
{
|
{
|
||||||
IImage.IImageColumns columns = image.Columns;
|
IImage.IImageColumns columns = image.Columns;
|
||||||
for (int x = columns.Count - 1; x >= 0; x--)
|
for (int x = columns.Count - 1; x >= 0; x--)
|
||||||
@ -109,14 +133,20 @@ public static class BlackBarDetection
|
|||||||
where TColor : struct, IColor
|
where TColor : struct, IColor
|
||||||
{
|
{
|
||||||
int top = removeTop ? CalculateTop(image, threshold) : 0;
|
int top = removeTop ? CalculateTop(image, threshold) : 0;
|
||||||
int bottom = removeBottom ? CalculateBottom(image, threshold) : image.Height;
|
int bottom = removeBottom ? CalculateBottom(image, threshold) : image.Height - 1;
|
||||||
int left = removeLeft ? CalculateLeft(image, threshold) : 0;
|
int left = removeLeft ? CalculateLeft(image, threshold) : 0;
|
||||||
int right = removeRight ? CalculateRight(image, threshold) : image.Width;
|
int right = removeRight ? CalculateRight(image, threshold) : image.Width - 1;
|
||||||
|
|
||||||
return image[left, top, right - left, bottom - top];
|
return image[left, top, (right - left) + 1, (bottom - top) + 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int CalculateTop<TColor>(this RefImage<TColor> image, int threshold)
|
/// <summary>
|
||||||
|
/// Calculates the first row starting from the top with at least one non black pixel.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="image">The image to check.</param>
|
||||||
|
/// <param name="threshold">The threshold of "blackness" used to detect black bars. (e. g. Threshold 5 will consider a pixel of color [5,5,5] as black.)</param>
|
||||||
|
/// <returns>The row number of the first row with at least one non-black pixel.</returns>
|
||||||
|
public static int CalculateTop<TColor>(this RefImage<TColor> image, int threshold)
|
||||||
where TColor : struct, IColor
|
where TColor : struct, IColor
|
||||||
{
|
{
|
||||||
RefImage<TColor>.ImageRows rows = image.Rows;
|
RefImage<TColor>.ImageRows rows = image.Rows;
|
||||||
@ -133,7 +163,13 @@ public static class BlackBarDetection
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int CalculateBottom<TColor>(this RefImage<TColor> image, int threshold)
|
/// <summary>
|
||||||
|
/// Calculates the last row starting from the top with at least one non black pixel.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="image">The image to check.</param>
|
||||||
|
/// <param name="threshold">The threshold of "blackness" used to detect black bars. (e. g. Threshold 5 will consider a pixel of color [5,5,5] as black.)</param>
|
||||||
|
/// <returns>The row number of the last row with at least one non-black pixel.</returns>
|
||||||
|
public static int CalculateBottom<TColor>(this RefImage<TColor> image, int threshold)
|
||||||
where TColor : struct, IColor
|
where TColor : struct, IColor
|
||||||
{
|
{
|
||||||
RefImage<TColor>.ImageRows rows = image.Rows;
|
RefImage<TColor>.ImageRows rows = image.Rows;
|
||||||
@ -150,7 +186,13 @@ public static class BlackBarDetection
|
|||||||
return rows.Count;
|
return rows.Count;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int CalculateLeft<TColor>(this RefImage<TColor> image, int threshold)
|
/// <summary>
|
||||||
|
/// Calculates the first column starting from the left with at least one non black pixel.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="image">The image to check.</param>
|
||||||
|
/// <param name="threshold">The threshold of "blackness" used to detect black bars. (e. g. Threshold 5 will consider a pixel of color [5,5,5] as black.)</param>
|
||||||
|
/// <returns>The column number of the first column with at least one non-black pixel.</returns>
|
||||||
|
public static int CalculateLeft<TColor>(this RefImage<TColor> image, int threshold)
|
||||||
where TColor : struct, IColor
|
where TColor : struct, IColor
|
||||||
{
|
{
|
||||||
RefImage<TColor>.ImageColumns columns = image.Columns;
|
RefImage<TColor>.ImageColumns columns = image.Columns;
|
||||||
@ -167,7 +209,13 @@ public static class BlackBarDetection
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int CalculateRight<TColor>(this RefImage<TColor> image, int threshold)
|
/// <summary>
|
||||||
|
/// Calculates the last column starting from the top with at least one non black pixel.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="image">The image to check.</param>
|
||||||
|
/// <param name="threshold">The threshold of "blackness" used to detect black bars. (e. g. Threshold 5 will consider a pixel of color [5,5,5] as black.)</param>
|
||||||
|
/// <returns>The column number of the last column with at least one non-black pixel.</returns>
|
||||||
|
public static int CalculateRight<TColor>(this RefImage<TColor> image, int threshold)
|
||||||
where TColor : struct, IColor
|
where TColor : struct, IColor
|
||||||
{
|
{
|
||||||
RefImage<TColor>.ImageColumns columns = image.Columns;
|
RefImage<TColor>.ImageColumns columns = image.Columns;
|
||||||
|
|||||||
@ -240,7 +240,7 @@ public abstract class AbstractScreenCapture<TColor> : IScreenCapture
|
|||||||
_isDisposed = true;
|
_isDisposed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="Dispose" />
|
/// <inheritdoc cref="IDisposable.Dispose" />
|
||||||
protected virtual void Dispose(bool disposing) { }
|
protected virtual void Dispose(bool disposing) { }
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace ScreenCapture.NET;
|
namespace ScreenCapture.NET;
|
||||||
|
|
||||||
@ -7,6 +8,11 @@ namespace ScreenCapture.NET;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IImage : IEnumerable<IColor>
|
public interface IImage : IEnumerable<IColor>
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the color format used in this image.
|
||||||
|
/// </summary>
|
||||||
|
ColorFormat ColorFormat { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the width of this image.
|
/// Gets the width of this image.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -17,6 +23,11 @@ public interface IImage : IEnumerable<IColor>
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
int Height { get; }
|
int Height { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the size in bytes of this image.
|
||||||
|
/// </summary>
|
||||||
|
int SizeInBytes { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the color at the specified location.
|
/// Gets the color at the specified location.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -45,6 +56,28 @@ public interface IImage : IEnumerable<IColor>
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
IImageColumns Columns { get; }
|
IImageColumns Columns { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets an <see cref="RefImage{TColor}"/> representing this <see cref="IImage"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TColor">The color-type of the iamge.</typeparam>
|
||||||
|
/// <returns>The <inheritdoc cref="RefImage{TColor}"/>.</returns>
|
||||||
|
RefImage<TColor> AsRefImage<TColor>() where TColor : struct, IColor;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Copies the contents of this <see cref="IImage"/> into a destination <see cref="Span{T}"/> instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="destination">The destination <see cref="Span{T}"/> instance.</param>
|
||||||
|
/// <exception cref="ArgumentException">
|
||||||
|
/// Thrown when <paramref name="destination"/> is shorter than the source <see cref="IImage"/> instance.
|
||||||
|
/// </exception>
|
||||||
|
void CopyTo(in Span<byte> destination);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Allocates a new array and copies this <see cref="IImage"/> into it.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The new array containing the data of this <see cref="IImage"/>.</returns>
|
||||||
|
byte[] ToArray();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a list of rows of an image.
|
/// Represents a list of rows of an image.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -91,12 +124,32 @@ public interface IImage : IEnumerable<IColor>
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
int Length { get; }
|
int Length { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the size in bytes of this row.
|
||||||
|
/// </summary>
|
||||||
|
int SizeInBytes { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the <see cref="IColor"/> at the specified location.
|
/// Gets the <see cref="IColor"/> at the specified location.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="x">The location to get the color from.</param>
|
/// <param name="x">The location to get the color from.</param>
|
||||||
/// <returns>The <see cref="IColor"/> at the specified location.</returns>
|
/// <returns>The <see cref="IColor"/> at the specified location.</returns>
|
||||||
IColor this[int x] { get; }
|
IColor this[int x] { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Copies the contents of this <see cref="IImageRow"/> into a destination <see cref="Span{T}"/> instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="destination">The destination <see cref="Span{T}"/> instance.</param>
|
||||||
|
/// <exception cref="ArgumentException">
|
||||||
|
/// Thrown when <paramref name="destination"/> is shorter than the source <see cref="IImageRow"/> instance.
|
||||||
|
/// </exception>
|
||||||
|
void CopyTo(in Span<byte> destination);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Allocates a new array and copies this <see cref="IImageRow"/> into it.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The new array containing the data of this <see cref="IImageRow"/>.</returns>
|
||||||
|
byte[] ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -109,11 +162,31 @@ public interface IImage : IEnumerable<IColor>
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
int Length { get; }
|
int Length { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the size in bytes of this column.
|
||||||
|
/// </summary>
|
||||||
|
int SizeInBytes { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the <see cref="IColor"/> at the specified location.
|
/// Gets the <see cref="IColor"/> at the specified location.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="y">The location to get the color from.</param>
|
/// <param name="y">The location to get the color from.</param>
|
||||||
/// <returns>The <see cref="IColor"/> at the specified location.</returns>
|
/// <returns>The <see cref="IColor"/> at the specified location.</returns>
|
||||||
IColor this[int y] { get; }
|
IColor this[int y] { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Copies the contents of this <see cref="IImageColumn"/> into a destination <see cref="Span{T}"/> instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="destination">The destination <see cref="Span{T}"/> instance.</param>
|
||||||
|
/// <exception cref="ArgumentException">
|
||||||
|
/// Thrown when <paramref name="destination"/> is shorter than the source <see cref="IImageColumn"/> instance.
|
||||||
|
/// </exception>
|
||||||
|
void CopyTo(in Span<byte> destination);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Allocates a new array and copies this <see cref="IImageColumn"/> into it.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The new array containing the data of this <see cref="IImageColumn"/>.</returns>
|
||||||
|
byte[] ToArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -18,12 +18,18 @@ public sealed class Image<TColor> : IImage
|
|||||||
private readonly int _y;
|
private readonly int _y;
|
||||||
private readonly int _stride;
|
private readonly int _stride;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public ColorFormat ColorFormat => TColor.ColorFormat;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public int Width { get; }
|
public int Width { get; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public int Height { get; }
|
public int Height { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public int SizeInBytes => Width * Height * TColor.ColorFormat.BytesPerPixel;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Indexer
|
#region Indexer
|
||||||
@ -84,6 +90,39 @@ public sealed class Image<TColor> : IImage
|
|||||||
|
|
||||||
#region Methods
|
#region Methods
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void CopyTo(in Span<byte> destination)
|
||||||
|
{
|
||||||
|
if (destination == null) throw new ArgumentNullException(nameof(destination));
|
||||||
|
if (destination.Length < SizeInBytes) throw new ArgumentException("The destination is too small to fit this image.", nameof(destination));
|
||||||
|
|
||||||
|
int targetStride = Width * TColor.ColorFormat.BytesPerPixel;
|
||||||
|
IImage.IImageRows rows = Rows;
|
||||||
|
Span<byte> target = destination;
|
||||||
|
foreach (IImage.IImageRow row in rows)
|
||||||
|
{
|
||||||
|
row.CopyTo(target);
|
||||||
|
target = target[targetStride..];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public byte[] ToArray()
|
||||||
|
{
|
||||||
|
byte[] array = new byte[SizeInBytes];
|
||||||
|
CopyTo(array);
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public RefImage<T> AsRefImage<T>()
|
||||||
|
where T : struct, IColor
|
||||||
|
{
|
||||||
|
if (typeof(T) != typeof(TColor)) throw new ArgumentException("The requested color format does not fit this image.", nameof(T));
|
||||||
|
|
||||||
|
return new RefImage<T>(MemoryMarshal.Cast<byte, T>(_buffer), _x, _y, Width, Height, _stride);
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public IEnumerator<IColor> GetEnumerator()
|
public IEnumerator<IColor> GetEnumerator()
|
||||||
{
|
{
|
||||||
@ -172,6 +211,9 @@ public sealed class Image<TColor> : IImage
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public int Length => _length;
|
public int Length => _length;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public int SizeInBytes => Length * TColor.ColorFormat.BytesPerPixel;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Indexer
|
#region Indexer
|
||||||
@ -203,6 +245,23 @@ public sealed class Image<TColor> : IImage
|
|||||||
|
|
||||||
#region Methods
|
#region Methods
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void CopyTo(in Span<byte> destination)
|
||||||
|
{
|
||||||
|
if (destination == null) throw new ArgumentNullException(nameof(destination));
|
||||||
|
if (destination.Length < SizeInBytes) throw new ArgumentException("The destination is too small to fit this image.", nameof(destination));
|
||||||
|
|
||||||
|
_buffer.AsSpan(_start, SizeInBytes).CopyTo(destination);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public byte[] ToArray()
|
||||||
|
{
|
||||||
|
byte[] array = new byte[SizeInBytes];
|
||||||
|
CopyTo(array);
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public IEnumerator<IColor> GetEnumerator()
|
public IEnumerator<IColor> GetEnumerator()
|
||||||
{
|
{
|
||||||
@ -290,6 +349,9 @@ public sealed class Image<TColor> : IImage
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public int Length => _length;
|
public int Length => _length;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public int SizeInBytes => Length * TColor.ColorFormat.BytesPerPixel;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Indexer
|
#region Indexer
|
||||||
@ -301,8 +363,8 @@ public sealed class Image<TColor> : IImage
|
|||||||
{
|
{
|
||||||
if ((y < 0) || (y >= _length)) throw new IndexOutOfRangeException();
|
if ((y < 0) || (y >= _length)) throw new IndexOutOfRangeException();
|
||||||
|
|
||||||
ReadOnlySpan<TColor> row = MemoryMarshal.Cast<byte, TColor>(_buffer)[_start..];
|
ReadOnlySpan<TColor> data = MemoryMarshal.Cast<byte, TColor>(_buffer)[_start..];
|
||||||
return row[y * _step];
|
return data[y * _step];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -322,6 +384,31 @@ public sealed class Image<TColor> : IImage
|
|||||||
|
|
||||||
#region Methods
|
#region Methods
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void CopyTo(in Span<byte> destination)
|
||||||
|
{
|
||||||
|
if (destination == null) throw new ArgumentNullException(nameof(destination));
|
||||||
|
if (destination.Length < SizeInBytes) throw new ArgumentException("The destination is too small to fit this image.", nameof(destination));
|
||||||
|
|
||||||
|
if (_step == 1)
|
||||||
|
_buffer.AsSpan(_start, SizeInBytes).CopyTo(destination);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ReadOnlySpan<TColor> data = MemoryMarshal.Cast<byte, TColor>(_buffer)[_start..];
|
||||||
|
Span<TColor> target = MemoryMarshal.Cast<byte, TColor>(destination);
|
||||||
|
for (int i = 0; i < Length; i++)
|
||||||
|
target[i] = data[i * _step];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public byte[] ToArray()
|
||||||
|
{
|
||||||
|
byte[] array = new byte[SizeInBytes];
|
||||||
|
CopyTo(array);
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public IEnumerator<IColor> GetEnumerator()
|
public IEnumerator<IColor> GetEnumerator()
|
||||||
{
|
{
|
||||||
|
|||||||
@ -13,23 +13,37 @@ public readonly ref struct RefImage<TColor>
|
|||||||
|
|
||||||
private readonly int _x;
|
private readonly int _x;
|
||||||
private readonly int _y;
|
private readonly int _y;
|
||||||
private readonly int _stride;
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the width of the image.
|
||||||
|
/// </summary>
|
||||||
public int Width { get; }
|
public int Width { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the height of the image.
|
||||||
|
/// </summary>
|
||||||
public int Height { get; }
|
public int Height { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the stride (entries per row) of the underlying buffer.
|
||||||
|
/// Only useful if you want to work with a pinned buffer.
|
||||||
|
/// </summary>
|
||||||
|
public int RawStride { get; }
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Indexer
|
#region Indexer
|
||||||
|
|
||||||
public TColor this[int x, int y]
|
public ref readonly TColor this[int x, int y]
|
||||||
{
|
{
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if ((x < 0) || (y < 0) || (x >= Width) || (y >= Height)) throw new IndexOutOfRangeException();
|
if ((x < 0) || (y < 0) || (x >= Width) || (y >= Height)) throw new IndexOutOfRangeException();
|
||||||
|
|
||||||
return _pixels[((_y + y) * _stride) + (_x + x)];
|
ref TColor r0 = ref MemoryMarshal.GetReference(_pixels);
|
||||||
|
nint offset = (nint)(uint)((_y + y) * RawStride) + (_x + x);
|
||||||
|
return ref Unsafe.Add(ref r0, offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,19 +54,19 @@ public readonly ref struct RefImage<TColor>
|
|||||||
{
|
{
|
||||||
if ((x < 0) || (y < 0) || (width <= 0) || (height <= 0) || ((x + width) > Width) || ((y + height) > Height)) throw new IndexOutOfRangeException();
|
if ((x < 0) || (y < 0) || (width <= 0) || (height <= 0) || ((x + width) > Width) || ((y + height) > Height)) throw new IndexOutOfRangeException();
|
||||||
|
|
||||||
return new RefImage<TColor>(_pixels, _x + x, _y + y, width, height, _stride);
|
return new RefImage<TColor>(_pixels, _x + x, _y + y, width, height, RawStride);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ImageRows Rows
|
public ImageRows Rows
|
||||||
{
|
{
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
get => new(_pixels, _x, _y, Width, Height, _stride);
|
get => new(_pixels, _x, _y, Width, Height, RawStride);
|
||||||
}
|
}
|
||||||
public ImageColumns Columns
|
public ImageColumns Columns
|
||||||
{
|
{
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
get => new(_pixels, _x, _y, Width, Height, _stride);
|
get => new(_pixels, _x, _y, Width, Height, RawStride);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@ -66,20 +80,27 @@ public readonly ref struct RefImage<TColor>
|
|||||||
this._y = y;
|
this._y = y;
|
||||||
this.Width = width;
|
this.Width = width;
|
||||||
this.Height = height;
|
this.Height = height;
|
||||||
this._stride = stride;
|
this.RawStride = stride;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Methods
|
#region Methods
|
||||||
|
|
||||||
public void CopyTo(in Span<TColor> dest)
|
/// <summary>
|
||||||
|
/// Copies the contents of this <see cref="RefImage{TColor}"/> into a destination <see cref="Span{T}"/> instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="destination">The destination <see cref="Span{T}"/> instance.</param>
|
||||||
|
/// <exception cref="ArgumentException">
|
||||||
|
/// Thrown when <paramref name="destination"/> is shorter than the source <see cref="RefImage{TColor}"/> instance.
|
||||||
|
/// </exception>
|
||||||
|
public void CopyTo(in Span<TColor> destination)
|
||||||
{
|
{
|
||||||
if (dest == null) throw new ArgumentNullException(nameof(dest));
|
if (destination == null) throw new ArgumentNullException(nameof(destination));
|
||||||
if (dest.Length < (Width * Height)) throw new ArgumentException("The destination is too small to fit this image.", nameof(dest));
|
if (destination.Length < (Width * Height)) throw new ArgumentException("The destination is too small to fit this image.", nameof(destination));
|
||||||
|
|
||||||
ImageRows rows = Rows;
|
ImageRows rows = Rows;
|
||||||
Span<TColor> target = dest;
|
Span<TColor> target = destination;
|
||||||
foreach (ReadOnlyRefEnumerable<TColor> row in rows)
|
foreach (ReadOnlyRefEnumerable<TColor> row in rows)
|
||||||
{
|
{
|
||||||
row.CopyTo(target);
|
row.CopyTo(target);
|
||||||
@ -87,6 +108,10 @@ public readonly ref struct RefImage<TColor>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Allocates a new array and copies this <see cref="RefImage{TColor}"/> into it.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The new array containing the data of this <see cref="RefImage{TColor}"/>.</returns>
|
||||||
public TColor[] ToArray()
|
public TColor[] ToArray()
|
||||||
{
|
{
|
||||||
TColor[] array = new TColor[Width * Height];
|
TColor[] array = new TColor[Width * Height];
|
||||||
@ -94,6 +119,18 @@ public readonly ref struct RefImage<TColor>
|
|||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns a reference to the first element of this image inside the full image buffer.
|
||||||
|
/// </summary>
|
||||||
|
public ref readonly TColor GetPinnableReference()
|
||||||
|
{
|
||||||
|
if (_pixels.Length == 0)
|
||||||
|
return ref Unsafe.NullRef<TColor>();
|
||||||
|
|
||||||
|
int offset = (_y * RawStride) + _x;
|
||||||
|
return ref MemoryMarshal.GetReference(_pixels[offset..]);
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc cref="System.Collections.IEnumerable.GetEnumerator"/>
|
/// <inheritdoc cref="System.Collections.IEnumerable.GetEnumerator"/>
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public ImageEnumerator GetEnumerator() => new(_pixels);
|
public ImageEnumerator GetEnumerator() => new(_pixels);
|
||||||
|
|||||||
@ -29,9 +29,9 @@
|
|||||||
Reworked most of the data handling and splitted capture-logic into separate packages.
|
Reworked most of the data handling and splitted capture-logic into separate packages.
|
||||||
</PackageReleaseNotes>
|
</PackageReleaseNotes>
|
||||||
|
|
||||||
<Version>2.0.0</Version>
|
<Version>2.0.1</Version>
|
||||||
<AssemblyVersion>2.0.0</AssemblyVersion>
|
<AssemblyVersion>2.0.1</AssemblyVersion>
|
||||||
<FileVersion>2.0.0</FileVersion>
|
<FileVersion>2.0.1</FileVersion>
|
||||||
|
|
||||||
<OutputPath>..\bin\</OutputPath>
|
<OutputPath>..\bin\</OutputPath>
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
|
|||||||
@ -161,5 +161,19 @@ public class ImageTest
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestMethod]
|
||||||
|
public void TestAsRefImage()
|
||||||
|
{
|
||||||
|
IImage image = _captureZone!.Image;
|
||||||
|
image = image[163, 280, 720, 13];
|
||||||
|
image = image[15, 2, 47, 8];
|
||||||
|
|
||||||
|
RefImage<ColorARGB> refImage = image.AsRefImage<ColorARGB>();
|
||||||
|
|
||||||
|
for (int y = 0; y < image.Height; y++)
|
||||||
|
for (int x = 0; x < image.Width; x++)
|
||||||
|
Assert.AreEqual(image[x, y], refImage[x, y]);
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user