diff --git a/HPPH/Images/Image.cs b/HPPH/Images/Image.cs index cd37633..92ccf27 100644 --- a/HPPH/Images/Image.cs +++ b/HPPH/Images/Image.cs @@ -45,7 +45,7 @@ public sealed class Image : IImage { if ((x < 0) || (y < 0) || (x >= Width) || (y >= Height)) throw new IndexOutOfRangeException(); - return MemoryMarshal.Cast(_buffer)[((_y + y) * _stride) + (_x + x)]; + return MemoryMarshal.Cast(_buffer.AsSpan()[((_y + y) * _stride)..])[_x + x]; } } @@ -79,7 +79,7 @@ public sealed class Image : IImage #region Constructors - internal Image(byte[] buffer, int x, int y, int width, int height, int stride) + private Image(byte[] buffer, int x, int y, int width, int height, int stride) { this._buffer = buffer; this._x = x; @@ -93,6 +93,19 @@ public sealed class Image : IImage #region Methods + public static Image Create(ReadOnlySpan buffer, int width, int height) + => Create(MemoryMarshal.AsBytes(buffer), width, height, width * TColor.ColorFormat.BytesPerPixel); + + public static Image Create(ReadOnlySpan buffer, int width, int height, int stride) + { + if (stride < width) throw new ArgumentException("Stride can't be smaller than width."); + if (buffer.Length < (height * stride)) throw new ArgumentException("Not enough data in the buffer."); + + byte[] data = new byte[buffer.Length]; + buffer.CopyTo(data); + return new Image(data, 0, 0, width, height, stride); + } + /// public void CopyTo(Span destination) { @@ -136,7 +149,7 @@ public sealed class Image : IImage { if (typeof(T) != typeof(TColor)) throw new ArgumentException("The requested color format does not fit this image.", nameof(T)); - return new RefImage(MemoryMarshal.Cast(_buffer), _x, _y, Width, Height, _stride); + return new RefImage(_buffer, _x, _y, Width, Height, _stride); } /// @@ -180,7 +193,7 @@ public sealed class Image : IImage { if ((row < 0) || (row >= _height)) throw new IndexOutOfRangeException(); - return new ImageRow(_buffer, (((row + _y) * _stride) + _x), _width); + return new ImageRow(_buffer, ((row + _y) * _stride) + (_x * TColor.ColorFormat.BytesPerPixel), _width); } } @@ -188,7 +201,7 @@ public sealed class Image : IImage #region Constructors - internal ImageRows(byte[] buffer, int x, int y, int width, int height, int stride) + internal ImageRows(byte[] buffer, int x, int y, int width, int height, int stride, int bpp) { this._buffer = buffer; this._x = x; @@ -241,8 +254,7 @@ public sealed class Image : IImage { if ((x < 0) || (x >= _length)) throw new IndexOutOfRangeException(); - ReadOnlySpan row = MemoryMarshal.Cast(_buffer)[_start..]; - return row[x]; + return MemoryMarshal.Cast(_buffer)[_start..][x]; } } @@ -267,7 +279,7 @@ public sealed class Image : IImage 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)); - MemoryMarshal.Cast(_buffer).Slice(_start, _length).CopyTo(MemoryMarshal.Cast(destination)); + _buffer.AsSpan().Slice(_start, SizeInBytes).CopyTo(destination); } /// @@ -317,7 +329,7 @@ public sealed class Image : IImage { if ((column < 0) || (column >= _width)) throw new IndexOutOfRangeException(); - return new ImageColumn(_buffer, (_y * _stride) + _x + column, _height, _stride); + return new ImageColumn(_buffer, (_y * _stride) + ((_x + column) * TColor.ColorFormat.BytesPerPixel), _height, _stride); } } @@ -379,8 +391,7 @@ public sealed class Image : IImage { if ((y < 0) || (y >= _length)) throw new IndexOutOfRangeException(); - ReadOnlySpan data = MemoryMarshal.Cast(_buffer)[_start..]; - return data[y * _step]; + return MemoryMarshal.Cast(_buffer.AsSpan()[_start..])[y * _step]; } } @@ -410,7 +421,7 @@ public sealed class Image : IImage _buffer.AsSpan(_start, SizeInBytes).CopyTo(destination); else { - ReadOnlySpan data = MemoryMarshal.Cast(_buffer)[_start..]; + ReadOnlySpan data = MemoryMarshal.Cast(_buffer.AsSpan()[_start..]); Span target = MemoryMarshal.Cast(destination); for (int i = 0; i < Length; i++) target[i] = data[i * _step]; diff --git a/HPPH/Images/RefImage.cs b/HPPH/Images/RefImage.cs index 1ed2a7b..c31b8a9 100644 --- a/HPPH/Images/RefImage.cs +++ b/HPPH/Images/RefImage.cs @@ -8,7 +8,7 @@ public readonly ref struct RefImage { #region Properties & Fields - private readonly ReadOnlySpan _pixels; + private readonly ReadOnlySpan _data; private readonly int _x; private readonly int _y; @@ -40,8 +40,9 @@ public readonly ref struct RefImage { if ((x < 0) || (y < 0) || (x >= Width) || (y >= Height)) throw new IndexOutOfRangeException(); - ref TColor r0 = ref MemoryMarshal.GetReference(_pixels); - nint offset = (nint)(uint)((_y + y) * RawStride) + (_x + x); + ReadOnlySpan data = MemoryMarshal.Cast(_data[((_y + y) * RawStride)..]); + ref TColor r0 = ref MemoryMarshal.GetReference(data); + nint offset = (nint)(uint)(_x + x); return ref Unsafe.Add(ref r0, offset); } } @@ -53,29 +54,29 @@ public readonly ref struct RefImage { if ((x < 0) || (y < 0) || (width <= 0) || (height <= 0) || ((x + width) > Width) || ((y + height) > Height)) throw new IndexOutOfRangeException(); - return new RefImage(_pixels, _x + x, _y + y, width, height, RawStride); + return new RefImage(_data, _x + x, _y + y, width, height, RawStride); } } public ImageRows Rows { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => new(_pixels, _x, _y, Width, Height, RawStride); + get => new(_data, _x, _y, Width, Height, RawStride); } public ImageColumns Columns { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => new(_pixels, _x, _y, Width, Height, RawStride); + get => new(_data, _x, _y, Width, Height, RawStride); } #endregion #region Constructors - internal RefImage(ReadOnlySpan pixels, int x, int y, int width, int height, int stride) + internal RefImage(ReadOnlySpan data, int x, int y, int width, int height, int stride) { - this._pixels = pixels; + this._data = data; this._x = x; this._y = y; this.Width = width; @@ -122,44 +123,63 @@ public readonly ref struct RefImage /// /// Returns a reference to the first element of this image inside the full image buffer. /// - public ref readonly TColor GetPinnableReference() + public ref readonly byte GetPinnableReference() { - if (_pixels.Length == 0) - return ref Unsafe.NullRef(); + if (_data.Length == 0) + return ref Unsafe.NullRef(); - int offset = (_y * RawStride) + _x; - return ref MemoryMarshal.GetReference(_pixels[offset..]); + int offset = (_y * RawStride) + (_x * TColor.ColorFormat.BytesPerPixel); + return ref MemoryMarshal.GetReference(_data[offset..]); } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ImageEnumerator GetEnumerator() => new(_pixels); + public ImageEnumerator GetEnumerator() => new(_data, _x, _y, Width, Height, RawStride); #endregion + //TODO DarthAffe 10.07.2024: anpassen public ref struct ImageEnumerator { #region Properties & Fields - private readonly ReadOnlySpan _pixels; + private readonly ReadOnlySpan _data; + private readonly int _x; + private readonly int _y; + private readonly int _width; + private readonly int _stride; + private readonly int _count; + private int _position; /// public readonly TColor Current { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => _pixels[_position]; + get + { + int row = (_position / _width); + int column = _position - (row * _width); + + return MemoryMarshal.Cast(_data[(_y * _stride)..])[_x + column]; + } } #endregion #region Constructors - + // ReSharper disable once ConvertToPrimaryConstructor - Not possible with ref types [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal ImageEnumerator(ReadOnlySpan pixels) + internal ImageEnumerator(ReadOnlySpan data, int x, int y, int width, int height, int stride) { - this._pixels = pixels; + this._data = data; + this._x = x; + this._y = y; + this._width = width; + this._stride = stride; + + _count = _width * height; _position = -1; } @@ -170,7 +190,7 @@ public readonly ref struct RefImage /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool MoveNext() => ++_position < _pixels.Length; + public bool MoveNext() => ++_position < _count; #endregion } @@ -181,7 +201,7 @@ public readonly ref struct RefImage { #region Properties & Fields - private readonly ReadOnlySpan _pixels; + private readonly ReadOnlySpan _data; private readonly int _x; private readonly int _y; private readonly int _width; @@ -201,8 +221,10 @@ public readonly ref struct RefImage { if ((row < 0) || (row > _height)) throw new IndexOutOfRangeException(); - ref TColor r0 = ref MemoryMarshal.GetReference(_pixels); - ref TColor rr = ref Unsafe.Add(ref r0, (nint)(uint)(((row + _y) * _stride) + _x)); + + ReadOnlySpan data = MemoryMarshal.Cast(_data[((row + _y) * _stride)..]); + ref TColor r0 = ref MemoryMarshal.GetReference(data); + ref TColor rr = ref Unsafe.Add(ref r0, (nint)(uint)_x); return new ReadOnlyRefEnumerable(rr, _width, 1); } @@ -213,9 +235,9 @@ public readonly ref struct RefImage #region Constructors // ReSharper disable once ConvertToPrimaryConstructor - Not possible with ref types - public ImageRows(ReadOnlySpan pixels, int x, int y, int width, int height, int stride) + internal ImageRows(ReadOnlySpan data, int x, int y, int width, int height, int stride) { - this._pixels = pixels; + this._data = data; this._x = x; this._y = y; this._width = width; @@ -276,7 +298,7 @@ public readonly ref struct RefImage { #region Properties & Fields - private readonly ReadOnlySpan _pixels; + private readonly ReadOnlySpan _data; private readonly int _x; private readonly int _y; private readonly int _width; @@ -296,8 +318,9 @@ public readonly ref struct RefImage { if ((column < 0) || (column > _width)) throw new IndexOutOfRangeException(); - ref TColor r0 = ref MemoryMarshal.GetReference(_pixels); - ref TColor rc = ref Unsafe.Add(ref r0, (nint)(uint)((_y * _stride) + (column + _x))); + ReadOnlySpan data = MemoryMarshal.Cast(_data[(_y * _stride)..]); + ref TColor r0 = ref MemoryMarshal.GetReference(data); + ref TColor rc = ref Unsafe.Add(ref r0, (nint)(uint)(column + _x)); return new ReadOnlyRefEnumerable(rc, _height, _stride); } @@ -308,9 +331,9 @@ public readonly ref struct RefImage #region Constructors // ReSharper disable once ConvertToPrimaryConstructor - Not possible with ref types - public ImageColumns(ReadOnlySpan pixels, int x, int y, int width, int height, int stride) + internal ImageColumns(ReadOnlySpan data, int x, int y, int width, int height, int stride) { - this._pixels = pixels; + this._data = data; this._x = x; this._y = y; this._width = width;