Пример #1
0
        private static JpegColorConverter.ComponentValues CreateRandomValues(
            int componentCount,
            int inputBufferLength,
            int seed,
            float minVal = 0f,
            float maxVal = 255f)
        {
            var rnd = new Random(seed);

            var buffers = new Buffer2D <float> [componentCount];

            for (int i = 0; i < componentCount; i++)
            {
                var values = new float[inputBufferLength];

                for (int j = 0; j < inputBufferLength; j++)
                {
                    values[j] = ((float)rnd.NextDouble() * (maxVal - minVal)) + minVal;
                }

                // no need to dispose when buffer is not array owner
                var memory = new Memory <float>(values);
                var source = MemoryGroup <float> .Wrap(memory);

                buffers[i] = new Buffer2D <float>(source, values.Length, 1);
            }

            return(new JpegColorConverter.ComponentValues(buffers, 0));
        }
Пример #2
0
        public void Wrap()
        {
            int[] data0 = { 1, 2, 3, 4 };
            int[] data1 = { 5, 6, 7, 8 };
            int[] data2 = { 9, 10 };
            using var mgr0 = new TestMemoryManager <int>(data0);
            using var mgr1 = new TestMemoryManager <int>(data1);

            using var group = MemoryGroup <int> .Wrap(mgr0.Memory, mgr1.Memory, data2);

            Assert.Equal(3, group.Count);
            Assert.Equal(4, group.BufferLength);
            Assert.Equal(10, group.TotalLength);

            Assert.True(group[0].Span.SequenceEqual(data0));
            Assert.True(group[1].Span.SequenceEqual(data1));
            Assert.True(group[2].Span.SequenceEqual(data2));

            int cnt = 0;

            int[][] allData = { data0, data1, data2 };
            foreach (Memory <int> memory in group)
            {
                Assert.True(memory.Span.SequenceEqual(allData[cnt]));
                cnt++;
            }
        }
Пример #3
0
        /// <summary>
        /// Wraps an existing contiguous memory area of 'width' x 'height' pixels,
        /// allowing to view/manipulate it as an ImageSharp <see cref="Image{TPixel}"/> instance.
        /// The ownership of the <paramref name="pixelMemoryOwner"/> is being transferred to the new <see cref="Image{TPixel}"/> instance,
        /// meaning that the caller is not allowed to dispose <paramref name="pixelMemoryOwner"/>.
        /// It will be disposed together with the result image.
        /// </summary>
        /// <typeparam name="TPixel">The pixel type</typeparam>
        /// <param name="config">The <see cref="ImageSharp.Configuration"/></param>
        /// <param name="pixelMemoryOwner">The <see cref="IMemoryOwner{T}"/> that is being transferred to the image</param>
        /// <param name="width">The width of the memory image.</param>
        /// <param name="height">The height of the memory image.</param>
        /// <param name="metadata">The <see cref="ImageMetadata"/></param>
        /// <returns>An <see cref="Image{TPixel}"/> instance</returns>
        public static Image <TPixel> WrapMemory <TPixel>(
            Configuration config,
            IMemoryOwner <TPixel> pixelMemoryOwner,
            int width,
            int height,
            ImageMetadata metadata)
            where TPixel : struct, IPixel <TPixel>
        {
            var memorySource = MemoryGroup <TPixel> .Wrap(pixelMemoryOwner);

            return(new Image <TPixel>(config, memorySource, width, height, metadata));
        }
Пример #4
0
        /// <summary>
        /// Wraps an existing contiguous memory area of 'width' x 'height' pixels,
        /// allowing to view/manipulate it as an ImageSharp <see cref="Image{TPixel}"/> instance.
        /// The ownership of the <paramref name="pixelMemoryOwner"/> is being transferred to the new <see cref="Image{TPixel}"/> instance,
        /// meaning that the caller is not allowed to dispose <paramref name="pixelMemoryOwner"/>.
        /// It will be disposed together with the result image.
        /// </summary>
        /// <typeparam name="TPixel">The pixel type</typeparam>
        /// <param name="configuration">The <see cref="Configuration"/></param>
        /// <param name="pixelMemoryOwner">The <see cref="IMemoryOwner{T}"/> that is being transferred to the image</param>
        /// <param name="width">The width of the memory image.</param>
        /// <param name="height">The height of the memory image.</param>
        /// <param name="metadata">The <see cref="ImageMetadata"/></param>
        /// <exception cref="ArgumentNullException">The configuration is null.</exception>
        /// <exception cref="ArgumentNullException">The metadata is null.</exception>
        /// <returns>An <see cref="Image{TPixel}"/> instance</returns>
        public static Image <TPixel> WrapMemory <TPixel>(
            Configuration configuration,
            IMemoryOwner <TPixel> pixelMemoryOwner,
            int width,
            int height,
            ImageMetadata metadata)
            where TPixel : unmanaged, IPixel <TPixel>
        {
            Guard.NotNull(configuration, nameof(configuration));
            Guard.NotNull(metadata, nameof(metadata));

            var memorySource = MemoryGroup <TPixel> .Wrap(pixelMemoryOwner);

            return(new Image <TPixel>(configuration, memorySource, width, height, metadata));
        }
Пример #5
0
        /// <summary>
        /// <para>
        /// Wraps an existing contiguous memory area of 'width' x 'height' pixels allowing viewing/manipulation as
        /// an <see cref="Image{TPixel}"/> instance.
        /// </para>
        /// <para>
        /// Please note: using this method does not transfer the ownership of the underlying buffer of the input <see cref="Memory{T}"/>
        /// to the new <see cref="Image{TPixel}"/> instance. This means that consumers of this method must ensure that the input buffer
        /// is either self-contained, (for example, a <see cref="Memory{T}"/> instance wrapping a new array that was
        /// created), or that the owning object is not disposed until the returned <see cref="Image{TPixel}"/> is disposed.
        /// </para>
        /// <para>
        /// If the input <see cref="Memory{T}"/> instance is one retrieved from an <see cref="IMemoryOwner{T}"/> instance
        /// rented from a memory pool (such as <see cref="MemoryPool{T}"/>), and that owning instance is disposed while the image is still
        /// in use, this will lead to undefined behavior and possibly runtime crashes (as the same buffer might then be modified by other
        /// consumers while the returned image is still working on it). Make sure to control the lifetime of the input buffers appropriately.
        /// </para>
        /// </summary>
        /// <typeparam name="TPixel">The pixel type</typeparam>
        /// <param name="configuration">The <see cref="Configuration"/></param>
        /// <param name="pixelMemory">The pixel memory.</param>
        /// <param name="width">The width of the memory image.</param>
        /// <param name="height">The height of the memory image.</param>
        /// <param name="metadata">The <see cref="ImageMetadata"/>.</param>
        /// <exception cref="ArgumentNullException">The configuration is null.</exception>
        /// <exception cref="ArgumentNullException">The metadata is null.</exception>
        /// <returns>An <see cref="Image{TPixel}"/> instance</returns>
        public static Image <TPixel> WrapMemory <TPixel>(
            Configuration configuration,
            Memory <TPixel> pixelMemory,
            int width,
            int height,
            ImageMetadata metadata)
            where TPixel : unmanaged, IPixel <TPixel>
        {
            Guard.NotNull(configuration, nameof(configuration));
            Guard.NotNull(metadata, nameof(metadata));
            Guard.IsTrue(pixelMemory.Length == width * height, nameof(pixelMemory), "The length of the input memory doesn't match the specified image size");

            var memorySource = MemoryGroup <TPixel> .Wrap(pixelMemory);

            return(new Image <TPixel>(configuration, memorySource, width, height, metadata));
        }
Пример #6
0
        /// <summary>
        /// <para>
        /// Wraps an existing contiguous memory area of 'width' x 'height' pixels allowing viewing/manipulation as
        /// an <see cref="Image{TPixel}"/> instance.
        /// </para>
        /// <para>
        /// Please note: this method relies on callers to carefully manage the target memory area being referenced by the
        /// pointer and that the lifetime of such a memory area is at least equal to that of the returned
        /// <see cref="Image{TPixel}"/> instance. For example, if the input pointer references an unmanaged memory area,
        /// callers must ensure that the memory area is not freed as long as the returned <see cref="Image{TPixel}"/> is
        /// in use and not disposed. The same applies if the input memory area points to a pinned managed object, as callers
        /// must ensure that objects will remain pinned as long as the <see cref="Image{TPixel}"/> instance is in use.
        /// Failing to do so constitutes undefined behavior and will likely lead to memory corruption and runtime crashes.
        /// </para>
        /// <para>
        /// Note also that if you have a <see cref="Memory{T}"/> or an array (which can be cast to <see cref="Memory{T}"/>) of
        /// either <see cref="byte"/> or <typeparamref name="TPixel"/> values, it is highly recommended to use one of the other
        /// available overloads of this method instead (such as <see cref="WrapMemory{TPixel}(Configuration, Memory{byte}, int, int)"/>
        /// or <see cref="WrapMemory{TPixel}(Configuration, Memory{TPixel}, int, int)"/>, to make the resulting code less error
        /// prone and avoid having to pin the underlying memory buffer in use. This method is primarily meant to be used when
        /// doing interop or working with buffers that are located in unmanaged memory.
        /// </para>
        /// </summary>
        /// <typeparam name="TPixel">The pixel type</typeparam>
        /// <param name="configuration">The <see cref="Configuration"/></param>
        /// <param name="pointer">The pointer to the target memory buffer to wrap.</param>
        /// <param name="width">The width of the memory image.</param>
        /// <param name="height">The height of the memory image.</param>
        /// <param name="metadata">The <see cref="ImageMetadata"/>.</param>
        /// <exception cref="ArgumentNullException">The configuration is null.</exception>
        /// <exception cref="ArgumentNullException">The metadata is null.</exception>
        /// <returns>An <see cref="Image{TPixel}"/> instance</returns>
        public static unsafe Image <TPixel> WrapMemory <TPixel>(
            Configuration configuration,
            void *pointer,
            int width,
            int height,
            ImageMetadata metadata)
            where TPixel : unmanaged, IPixel <TPixel>
        {
            Guard.IsFalse(pointer == null, nameof(pointer), "Pointer must be not null");
            Guard.NotNull(configuration, nameof(configuration));
            Guard.NotNull(metadata, nameof(metadata));

            var memoryManager = new UnmanagedMemoryManager <TPixel>(pointer, width * height);

            var memorySource = MemoryGroup <TPixel> .Wrap(memoryManager.Memory);

            return(new Image <TPixel>(configuration, memorySource, width, height, metadata));
        }
Пример #7
0
        public void Wrap()
        {
            int[] data0 = { 1, 2, 3, 4 };
            int[] data1 = { 5, 6, 7, 8 };
            int[] data2 = { 9, 10 };
            using var mgr0 = new TestMemoryManager <int>(data0);
            using var mgr1 = new TestMemoryManager <int>(data1);

            using var group = MemoryGroup <int> .Wrap(mgr0.Memory, mgr1.Memory, data2);

            Assert.Equal(3, group.Count);
            Assert.Equal(4, group.BufferLength);
            Assert.Equal(10, group.TotalLength);

            Assert.True(group[0].Span.SequenceEqual(data0));
            Assert.True(group[1].Span.SequenceEqual(data1));
            Assert.True(group[2].Span.SequenceEqual(data2));
        }
Пример #8
0
            public void WhenDestIsNotMemoryOwner_DifferentSize_Throws(bool sourceIsOwner)
            {
                var data  = new Rgba32[21];
                var color = new Rgba32(1, 2, 3, 4);

                using var destOwner = new TestMemoryManager <Rgba32>(data);
                using var dest      = new Buffer2D <Rgba32>(MemoryGroup <Rgba32> .Wrap(destOwner.Memory), 21, 1);

                using Buffer2D <Rgba32> source = this.MemoryAllocator.Allocate2D <Rgba32>(22, 1);

                source.FastMemoryGroup[0].Span[10] = color;

                // Act:
                Assert.ThrowsAny <InvalidOperationException>(() => Buffer2D <Rgba32> .SwapOrCopyContent(dest, source));

                Assert.Equal(color, source.MemoryGroup[0].Span[10]);
                Assert.NotEqual(color, dest.MemoryGroup[0].Span[10]);
            }
Пример #9
0
        /// <summary>
        /// Wraps an existing contiguous memory area of at least 'width' x 'height' pixels,
        /// allowing to view/manipulate it as an <see cref="Image{TPixel}"/> instance.
        /// The ownership of the <paramref name="byteMemoryOwner"/> is being transferred to the new <see cref="Image{TPixel}"/> instance,
        /// meaning that the caller is not allowed to dispose <paramref name="byteMemoryOwner"/>.
        /// It will be disposed together with the result image.
        /// </summary>
        /// <typeparam name="TPixel">The pixel type</typeparam>
        /// <param name="configuration">The <see cref="Configuration"/></param>
        /// <param name="byteMemoryOwner">The <see cref="IMemoryOwner{T}"/> that is being transferred to the image</param>
        /// <param name="width">The width of the memory image.</param>
        /// <param name="height">The height of the memory image.</param>
        /// <param name="metadata">The <see cref="ImageMetadata"/></param>
        /// <exception cref="ArgumentNullException">The configuration is null.</exception>
        /// <exception cref="ArgumentNullException">The metadata is null.</exception>
        /// <returns>An <see cref="Image{TPixel}"/> instance</returns>
        public static Image <TPixel> WrapMemory <TPixel>(
            Configuration configuration,
            IMemoryOwner <byte> byteMemoryOwner,
            int width,
            int height,
            ImageMetadata metadata)
            where TPixel : unmanaged, IPixel <TPixel>
        {
            Guard.NotNull(configuration, nameof(configuration));
            Guard.NotNull(metadata, nameof(metadata));

            var pixelMemoryOwner = new ByteMemoryOwner <TPixel>(byteMemoryOwner);

            Guard.IsTrue(pixelMemoryOwner.Memory.Length >= (long)width * height, nameof(pixelMemoryOwner), "The length of the input memory is less than the specified image size");

            var memorySource = MemoryGroup <TPixel> .Wrap(pixelMemoryOwner);

            return(new Image <TPixel>(configuration, memorySource, width, height, metadata));
        }
Пример #10
0
            public void WhenDestIsNotAllocated_SameSize_ShouldCopy(bool sourceIsAllocated)
            {
                var data  = new Rgba32[21];
                var color = new Rgba32(1, 2, 3, 4);

                using var destOwner = new TestMemoryManager <Rgba32>(data);
                using var dest      = new Buffer2D <Rgba32>(MemoryGroup <Rgba32> .Wrap(destOwner.Memory), 21, 1);

                using Buffer2D <Rgba32> source = this.MemoryAllocator.Allocate2D <Rgba32>(21, 1);

                source.FastMemoryGroup[0].Span[10] = color;

                // Act:
                bool swap = Buffer2D <Rgba32> .SwapOrCopyContent(dest, source);

                // Assert:
                Assert.False(swap);
                Assert.Equal(color, dest.MemoryGroup[0].Span[10]);
                Assert.NotEqual(source.FastMemoryGroup[0], dest.FastMemoryGroup[0]);
            }
Пример #11
0
            public void SwapOrCopyContent_WhenDestinationIsOwned_ShouldNotSwapInDisposedSourceBuffer()
            {
                using var destData = MemoryGroup <int> .Wrap(new int[100]);

                using var dest = new Buffer2D <int>(destData, 10, 10);

                using (Buffer2D <int> source = this.MemoryAllocator.Allocate2D <int>(10, 10, AllocationOptions.Clean))
                {
                    source[0, 0] = 1;
                    dest[0, 0]   = 2;

                    Buffer2D <int> .SwapOrCopyContent(dest, source);
                }

                int actual1 = dest.DangerousGetRowSpan(0)[0];
                int actual2 = dest.DangerousGetRowSpan(0)[0];
                int actual3 = dest.GetSafeRowMemory(0).Span[0];
                int actual5 = dest[0, 0];

                Assert.Equal(1, actual1);
                Assert.Equal(1, actual2);
                Assert.Equal(1, actual3);
                Assert.Equal(1, actual5);
            }