/// <summary> /// Returns a slice that is expected to be within the bounds of a single buffer. /// Otherwise <see cref="ArgumentOutOfRangeException"/> is thrown. /// </summary> internal static Memory <T> GetBoundedSlice <T>(this IMemoryGroup <T> group, long start, int length) where T : struct { Guard.NotNull(group, nameof(group)); Guard.IsTrue(group.IsValid, nameof(group), "Group must be valid!"); Guard.MustBeGreaterThanOrEqualTo(length, 0, nameof(length)); Guard.MustBeLessThan(start, group.TotalLength, nameof(start)); int bufferIdx = (int)(start / group.BufferLength); if (bufferIdx >= group.Count) { throw new ArgumentOutOfRangeException(nameof(start)); } int bufferStart = (int)(start % group.BufferLength); int bufferEnd = bufferStart + length; Memory <T> memory = group[bufferIdx]; if (bufferEnd > memory.Length) { throw new ArgumentOutOfRangeException(nameof(length)); } return(memory.Slice(bufferStart, length)); }
public override void Dispose() { ImageFrame <TImageSharpPixel>?image = _image; if (image is null) { return; } IMemoryGroup <TImageSharpPixel> memoryGroup = image.GetPixelMemoryGroup(); long totalLength = memoryGroup.TotalLength; // Copy pixels into this column int width = image.Width; int start = _start; int end = start + _length; int colIndex = _colIndex; int index = 0; Span <TImageSharpPixel> sourceSpan = MemoryMarshal.Cast <byte, TImageSharpPixel>(_buffer.AsSpan(0, _length * Unsafe.SizeOf <TTiffPixel>())); for (int rowIndex = start; rowIndex < end; rowIndex++) { GetBoundedSlice(memoryGroup, totalLength, rowIndex * (long)width, width)[colIndex] = sourceSpan[index++]; } _image = null; if (_parent != null) { ImageSharpPixelBufferWriter <TImageSharpPixel, TTiffPixel> parent = _parent; _parent = null; if (Interlocked.CompareExchange(ref parent._cachedColHandle, this, null) != null) { ReleaseBuffer(); } } }
internal static Span <T> GetBoundedSlice <T>(IMemoryGroup <T> group, long totalLength, long start, int length) where T : struct { Debug.Assert(!(group is null)); Debug.Assert(group !.IsValid); Debug.Assert(length >= 0); Debug.Assert(start <= group.TotalLength); Debug.Assert(totalLength == group.TotalLength); int bufferIdx = (int)(start / totalLength); if (bufferIdx >= group.Count) { throw new ArgumentOutOfRangeException(nameof(start)); } int bufferStart = (int)(start % totalLength); int bufferEnd = bufferStart + length; Memory <T> memory = group[bufferIdx]; if (bufferEnd > memory.Length) { throw new ArgumentOutOfRangeException(nameof(length)); } return(memory.Span.Slice(bufferStart, length)); }
/// <summary> /// Creates a new <see cref="Thread"/> /// </summary> /// <param name="name">The name of the thread.</param> /// <param name="capabilities">A collection of capabilities that the <see cref="Thread"/> has to run certain <see cref="ICommand"/> commands.</param> /// <param name="pointer">The <see cref="ThreadPointer"/> contains information about the <see cref="ICommand"/>s that will be run on the <see cref="Thread"/>.</param> /// <param name="context">Memory context, such as static type information, specific to the environment where the <see cref="Thread"/> is executing.</param> public Thread(string name, CapabilitiesCollection capabilities, ThreadPointer pointer, IMemoryGroup context) { Name = name; Capabilities = capabilities; Pointer = pointer; Context = context; }
public Image <TPixel> Decode <TPixel>(Configuration configuration, Stream stream) where TPixel : unmanaged, IPixel <TPixel> { using var magickImage = new MagickImage(stream); var result = new Image <TPixel>(configuration, magickImage.Width, magickImage.Height); IMemoryGroup <TPixel> resultPixels = result.GetRootFramePixelBuffer().FastMemoryGroup; using (IPixelCollection pixels = magickImage.GetPixelsUnsafe()) { if (magickImage.Depth == 8) { byte[] data = pixels.ToByteArray(PixelMapping.RGBA); FromRgba32Bytes(configuration, data, resultPixels); } else if (magickImage.Depth == 16) { ushort[] data = pixels.ToShortArray(PixelMapping.RGBA); Span <byte> bytes = MemoryMarshal.Cast <ushort, byte>(data.AsSpan()); FromRgba64Bytes(configuration, bytes, resultPixels); } else { throw new InvalidOperationException(); } } return(result); }
internal static void CopyTo <T>(this IMemoryGroup <T> source, IMemoryGroup <T> target) where T : struct { Guard.NotNull(source, nameof(source)); Guard.NotNull(target, nameof(target)); Guard.IsTrue(source.IsValid, nameof(source), "Source group must be valid."); Guard.IsTrue(target.IsValid, nameof(target), "Target group must be valid."); Guard.MustBeLessThanOrEqualTo(source.TotalLength, target.TotalLength, "Destination buffer too short!"); if (source.IsEmpty()) { return; } long position = 0; var srcCur = new MemoryGroupCursor <T>(source); var trgCur = new MemoryGroupCursor <T>(target); while (position < source.TotalLength) { int fwd = Math.Min(srcCur.LookAhead(), trgCur.LookAhead()); Span <T> srcSpan = srcCur.GetSpan(fwd); Span <T> trgSpan = trgCur.GetSpan(fwd); srcSpan.CopyTo(trgSpan); srcCur.Forward(fwd); trgCur.Forward(fwd); position += fwd; } }
public static MemoryGroupIndex MaxIndex <T>(this IMemoryGroup <T> group) where T : struct { return(group.Count == 0 ? new MemoryGroupIndex(group.BufferLength, 0, 0) : new MemoryGroupIndex(group.BufferLength, group.Count - 1, group[group.Count - 1].Length)); }
internal static void Fill <T>(this IMemoryGroup <T> group, T value) where T : struct { foreach (Memory <T> memory in group) { memory.Span.Fill(value); } }
internal static void Clear <T>(this IMemoryGroup <T> group) where T : struct { foreach (Memory <T> memory in group) { memory.Span.Clear(); } }
internal static void TransformInplace <T>( this IMemoryGroup <T> memoryGroup, TransformItemsInplaceDelegate <T> transform) where T : struct { foreach (Memory <T> memory in memoryGroup) { transform(memory.Span); } }
/// <summary> /// Gets the representation of the pixels as a <see cref="Span{T}"/> in the source image's pixel format /// stored in row major order, if the backing buffer is contiguous. /// </summary> /// <param name="span">The <see cref="Span{T}"/>.</param> /// <returns>The <see cref="bool"/>.</returns> public bool TryGetSinglePixelSpan(out Span <TPixel> span) { IMemoryGroup <TPixel> mg = this.GetPixelMemoryGroup(); if (mg.Count > 1) { span = default; return(false); } span = mg.Single().Span; return(true); }
/// <summary> /// Gets the representation of the pixels as a <see cref="Memory{T}"/> in the source image's pixel format /// stored in row major order, if the backing buffer is contiguous. /// <para /> /// To ensure the memory is contiguous, <see cref="Configuration.PreferContiguousImageBuffers"/> should be set /// to true, preferably on a non-global configuration instance (not <see cref="Configuration.Default"/>). /// <para /> /// WARNING: Disposing or leaking the underlying image while still working with the <paramref name="memory"/>'s <see cref="Span{T}"/> /// might lead to memory corruption. /// </summary> /// <param name="memory">The <see cref="Memory{T}"/> referencing the image buffer.</param> /// <returns>The <see cref="bool"/> indicating the success.</returns> public bool DangerousTryGetSinglePixelMemory(out Memory <TPixel> memory) { IMemoryGroup <TPixel> mg = this.GetPixelMemoryGroup(); if (mg.Count > 1) { memory = default; return(false); } memory = mg.Single(); return(true); }
public void OwnedMemory_PixelDataIsCorrect <TPixel>(TestImageProvider <TPixel> provider) where TPixel : unmanaged, IPixel <TPixel> { provider.LimitAllocatorBufferCapacity().InPixelsSqrt(200); using Image <TPixel> image = provider.GetImage(); // Act: IMemoryGroup <TPixel> memoryGroup = image.GetPixelMemoryGroup(); // Assert: VerifyMemoryGroupDataMatchesTestPattern(provider, memoryGroup, image.Size()); }
public void OwnedMemory_DestructiveMutate_ShouldInvalidateMemoryGroup <TPixel>(TestImageProvider <TPixel> provider) where TPixel : unmanaged, IPixel <TPixel> { using Image <TPixel> image = provider.GetImage(); IMemoryGroup <TPixel> memoryGroup = image.GetPixelMemoryGroup(); Memory <TPixel> memory = memoryGroup.Single(); image.Mutate(c => c.Resize(8, 8)); Assert.False(memoryGroup.IsValid); Assert.ThrowsAny <InvalidMemoryOperationException>(() => _ = memoryGroup.First()); Assert.ThrowsAny <InvalidMemoryOperationException>(() => _ = memory.Span); }
public static Span <TPixel> GetPixelSpan <TPixel>(this ImageFrame <TPixel> source) where TPixel : struct, IPixel <TPixel> { Guard.NotNull(source, nameof(source)); IMemoryGroup <TPixel> mg = source.GetPixelMemoryGroup(); if (mg.Count > 1) { throw new InvalidOperationException($"GetPixelSpan is invalid, since the backing buffer of this {source.Width}x{source.Height} sized image is discontiguous!"); } return(mg.Single().Span); }
internal static void CopyTo <T>(this ReadOnlySpan <T> source, IMemoryGroup <T> target) where T : struct { Guard.NotNull(target, nameof(target)); Guard.MustBeGreaterThanOrEqualTo(target.TotalLength, source.Length, nameof(target)); var cur = new MemoryGroupCursor <T>(target); while (!source.IsEmpty) { int fwd = Math.Min(cur.LookAhead(), source.Length); source.Slice(0, fwd).CopyTo(cur.GetSpan(fwd)); cur.Forward(fwd); source = source.Slice(fwd); } }
/// <inheritdoc/> public bool Push(IMemoryGroup memoryGroup) { if (new List <IMemoryGroup>(Layers) { memoryGroup }.CanLink()) { Layers.Add(memoryGroup); WritableLayer = memoryGroup as IWritableMemoryGroup; return(true); } else { return(false); } }
/// <summary> /// Starts the execution of a thread at a specific <see cref="ICommand"/> with a memory context in the form of an <see cref="IMemoryStack"/> and an input <see cref="IWritableMemoryGroup"/>. /// </summary> /// <param name="me">The owning <see cref="DataObject"/>, which executes the commands and provides bound .NET objects.</param> /// <param name="inputs">Memory context in the form of local variables such as inputs or scoped variables.</param> /// <returns>A <see cref="DataObject"/> representing the context at the point the <see cref="Thread"/> completed execution (this value may be null).</returns> public async Task <DataObject> RunThreadAsync(DataObject me, IMemoryGroup inputs) { ////Initializes memory. MemoryStack = new MemoryStack(); MemoryStack.Push(Context); MemoryStack.Push(me.MemoryStack); MemoryStack.Push(inputs); MemoryStack.Push(); IMemoryGroup commandContext = null; while (!Pointer.IsStopped) { commandContext = await Pointer.CurrentCommand.ExecuteCommandAsync(this, me, commandContext); Pointer.Next(); } return(commandContext as DataObject); }
internal static void CopyTo <T>(this IMemoryGroup <T> source, Span <T> target) where T : struct { Guard.NotNull(source, nameof(source)); Guard.MustBeGreaterThanOrEqualTo(target.Length, source.TotalLength, nameof(target)); var cur = new MemoryGroupCursor <T>(source); long position = 0; while (position < source.TotalLength) { int fwd = Math.Min(cur.LookAhead(), target.Length); cur.GetSpan(fwd).CopyTo(target); cur.Forward(fwd); target = target.Slice(fwd); position += fwd; } }
/// <summary> /// Returns the slice of the buffer starting at global index <paramref name="start"/> that goes until the end of the buffer. /// </summary> internal static Memory <T> GetRemainingSliceOfBuffer <T>(this IMemoryGroup <T> group, long start) where T : struct { Guard.NotNull(group, nameof(group)); Guard.IsTrue(group.IsValid, nameof(group), "Group must be valid!"); Guard.MustBeLessThan(start, group.TotalLength, nameof(start)); int bufferIdx = (int)(start / group.BufferLength); // if (bufferIdx < 0 || bufferIdx >= group.Count) if ((uint)bufferIdx >= group.Count) { throw new ArgumentOutOfRangeException(nameof(start)); } int bufferStart = (int)(start % group.BufferLength); Memory <T> memory = group[bufferIdx]; return(memory.Slice(bufferStart)); }
private static void VerifyMemoryGroupDataMatchesTestPattern <TPixel>( TestImageProvider <TPixel> provider, IMemoryGroup <TPixel> memoryGroup, Size size) where TPixel : unmanaged, IPixel <TPixel> { Assert.True(memoryGroup.IsValid); Assert.Equal(size.Width * size.Height, memoryGroup.TotalLength); Assert.True(memoryGroup.BufferLength % size.Width == 0); int cnt = 0; for (MemoryGroupIndex i = memoryGroup.MaxIndex(); i < memoryGroup.MaxIndex(); i += 1, cnt++) { int y = cnt / size.Width; int x = cnt % size.Width; TPixel expected = provider.GetExpectedBasicTestPatternPixelAt(x, y); TPixel actual = memoryGroup.GetElementAt(i); Assert.Equal(expected, actual); } }
private static void FromRgba64Bytes <TPixel>(Configuration configuration, Span <byte> rgbaBytes, IMemoryGroup <TPixel> destinationGroup) where TPixel : unmanaged, IPixel <TPixel> { foreach (Memory <TPixel> m in destinationGroup) { Span <TPixel> destBuffer = m.Span; PixelOperations <TPixel> .Instance.FromRgba64Bytes( configuration, rgbaBytes, destBuffer, destBuffer.Length); rgbaBytes = rgbaBytes.Slice(destBuffer.Length * 8); } }
internal static bool IsEmpty <T>(this IMemoryGroup <T> group) where T : struct => group.Count == 0;
public static void SetElementAt <T>(this IMemoryGroup <T> group, MemoryGroupIndex idx, T value) where T : struct { group[idx.BufferIndex].Span[idx.ElementIndex] = value; }
public static MemoryGroupIndex MinIndex <T>(this IMemoryGroup <T> group) where T : struct { return(new MemoryGroupIndex(group.BufferLength, 0, 0)); }
public static T GetElementAt <T>(this IMemoryGroup <T> group, MemoryGroupIndex idx) where T : struct { return(group[idx.BufferIndex].Span[idx.ElementIndex]); }
internal MemoryGroupEnumerator(MemoryGroupView <T> memoryGroup) { this.memoryGroup = memoryGroup; this.count = memoryGroup.Count; this.index = -1; }
internal MemoryGroupEnumerator(MemoryGroup <T> .Consumed memoryGroup) { this.memoryGroup = memoryGroup; this.count = memoryGroup.Count; this.index = -1; }
public MemoryGroupCursor(IMemoryGroup <T> memoryGroup) { this.memoryGroup = memoryGroup; this.bufferIndex = 0; this.elementIndex = 0; }
internal static void CopyTo <T>(this Span <T> source, IMemoryGroup <T> target) where T : struct => CopyTo((ReadOnlySpan <T>)source, target);