Example #1
0
        public void Slice2()
        {
            var         rowInterval = new RowInterval(10, 20);
            RowInterval sliced      = rowInterval.Slice(3, 5);

            Assert.Equal(13, sliced.Min);
            Assert.Equal(18, sliced.Max);
        }
Example #2
0
        public void Slice1()
        {
            var         rowInterval = new RowInterval(10, 20);
            RowInterval sliced      = rowInterval.Slice(5);

            Assert.Equal(15, sliced.Min);
            Assert.Equal(20, sliced.Max);
        }
Example #3
0
        /// <inheritdoc/>
        protected override void OnFrameApply(ImageFrame <TPixel> source, ImageFrame <TPixel> destination)
        {
            Rectangle     sourceRectangle = this.SourceRectangle;
            Configuration configuration   = this.Configuration;

            // Handle resize dimensions identical to the original
            if (source.Width == destination.Width &&
                source.Height == destination.Height &&
                sourceRectangle == this.targetRectangle)
            {
                // The cloned will be blank here copy all the pixel data over
                source.GetPixelMemoryGroup().CopyTo(destination.GetPixelMemoryGroup());
                return;
            }

            int width    = this.targetWidth;
            int height   = this.targetHeight;
            var interest = Rectangle.Intersect(this.targetRectangle, new Rectangle(0, 0, width, height));

            if (this.resampler is NearestNeighborResampler)
            {
                // Scaling factors
                float widthFactor  = sourceRectangle.Width / (float)this.targetRectangle.Width;
                float heightFactor = sourceRectangle.Height / (float)this.targetRectangle.Height;

                var operation = new RowIntervalOperation(sourceRectangle, this.targetRectangle, widthFactor, heightFactor, source, destination);
                ParallelRowIterator.IterateRows(
                    configuration,
                    interest,
                    in operation);

                return;
            }

            PixelConversionModifiers conversionModifiers =
                PixelConversionModifiers.Premultiply.ApplyCompanding(this.compand);

            BufferArea <TPixel> sourceArea = source.PixelBuffer.GetArea(sourceRectangle);

            // To reintroduce parallel processing, we to launch multiple workers
            // for different row intervals of the image.
            using (var worker = new ResizeWorker <TPixel>(
                       configuration,
                       sourceArea,
                       conversionModifiers,
                       this.horizontalKernelMap,
                       this.verticalKernelMap,
                       width,
                       interest,
                       this.targetRectangle.Location))
            {
                worker.Initialize();

                var workingInterval = new RowInterval(interest.Top, interest.Bottom);
                worker.FillDestinationPixels(workingInterval, destination.PixelBuffer);
            }
        }
Example #4
0
        public void Equality_WhenTrue()
        {
            var a = new RowInterval(42, 123);
            var b = new RowInterval(42, 123);

            Assert.True(a.Equals(b));
            Assert.True(a.Equals((object)b));
            Assert.True(a == b);
            Assert.Equal(a.GetHashCode(), b.GetHashCode());
        }
Example #5
0
        public void GetMultiRowSpan(int width, int height, int min, int max)
        {
            using (Buffer2D <int> buffer = Configuration.Default.MemoryAllocator.Allocate2D <int>(width, height))
            {
                var rows = new RowInterval(min, max);

                Span <int> span = buffer.GetMultiRowSpan(rows);

                ref int expected0      = ref buffer.Span[min * width];
                int     expectedLength = (max - min) * width;

                ref int actual0 = ref span[0];
Example #6
0
        public void Equality_WhenFalse()
        {
            var a = new RowInterval(42, 123);
            var b = new RowInterval(42, 125);
            var c = new RowInterval(40, 123);

            Assert.False(a.Equals(b));
            Assert.False(c.Equals(a));
            Assert.False(b.Equals(c));

            Assert.False(a.Equals((object)b));
            Assert.False(a.Equals(null));
            Assert.False(a == b);
            Assert.True(a != c);
        }
Example #7
0
        public ResizeWorker(
            Configuration configuration,
            Buffer2DRegion <TPixel> source,
            PixelConversionModifiers conversionModifiers,
            ResizeKernelMap horizontalKernelMap,
            ResizeKernelMap verticalKernelMap,
            int destWidth,
            Rectangle targetWorkingRect,
            Point targetOrigin)
        {
            this.configuration       = configuration;
            this.source              = source;
            this.sourceRectangle     = source.Rectangle;
            this.conversionModifiers = conversionModifiers;
            this.horizontalKernelMap = horizontalKernelMap;
            this.verticalKernelMap   = verticalKernelMap;
            this.destWidth           = destWidth;
            this.targetWorkingRect   = targetWorkingRect;
            this.targetOrigin        = targetOrigin;

            this.windowBandHeight = verticalKernelMap.MaxDiameter;

            // We need to make sure the working buffer is contiguous:
            int workingBufferLimitHintInBytes = Math.Min(
                configuration.WorkingBufferSizeHintInBytes,
                configuration.MemoryAllocator.GetBufferCapacityInBytes());

            int numberOfWindowBands = ResizeHelper.CalculateResizeWorkerHeightInWindowBands(
                this.windowBandHeight,
                destWidth,
                workingBufferLimitHintInBytes);

            this.workerHeight = Math.Min(this.sourceRectangle.Height, numberOfWindowBands * this.windowBandHeight);

            this.transposedFirstPassBuffer = configuration.MemoryAllocator.Allocate2D <Vector4>(
                this.workerHeight,
                destWidth,
                preferContiguosImageBuffers: true,
                options: AllocationOptions.Clean);

            this.tempRowBuffer    = configuration.MemoryAllocator.Allocate <Vector4>(this.sourceRectangle.Width);
            this.tempColumnBuffer = configuration.MemoryAllocator.Allocate <Vector4>(destWidth);

            this.currentWindow = new RowInterval(0, this.workerHeight);
        }
Example #8
0
        public void FillDestinationPixels(RowInterval rowInterval, Buffer2D <TPixel> destination)
        {
            Span <Vector4> tempColSpan = this.tempColumnBuffer.GetSpan();

            for (int y = rowInterval.Min; y < rowInterval.Max; y++)
            {
                // Ensure offsets are normalized for cropping and padding.
                ResizeKernel kernel = this.verticalKernelMap.GetKernel(y - this.targetOrigin.Y);

                if (kernel.StartIndex + kernel.Length > this.currentWindow.Max)
                {
                    this.Slide();
                }

                ref Vector4 tempRowBase = ref MemoryMarshal.GetReference(tempColSpan);

                int top = kernel.StartIndex - this.currentWindow.Min;

                ref Vector4 fpBase = ref this.transposedFirstPassBuffer.Span[top];
Example #9
0
        public ResizeWorker(
            Configuration configuration,
            BufferArea <TPixel> source,
            PixelConversionModifiers conversionModifiers,
            ResizeKernelMap horizontalKernelMap,
            ResizeKernelMap verticalKernelMap,
            int destWidth,
            Rectangle targetWorkingRect,
            Point targetOrigin)
        {
            this.configuration       = configuration;
            this.source              = source;
            this.sourceRectangle     = source.Rectangle;
            this.conversionModifiers = conversionModifiers;
            this.horizontalKernelMap = horizontalKernelMap;
            this.verticalKernelMap   = verticalKernelMap;
            this.destWidth           = destWidth;
            this.targetWorkingRect   = targetWorkingRect;
            this.targetOrigin        = targetOrigin;

            this.windowBandHeight = verticalKernelMap.MaxDiameter;

            int numberOfWindowBands = ResizeHelper.CalculateResizeWorkerHeightInWindowBands(
                this.windowBandHeight,
                destWidth,
                configuration.WorkingBufferSizeHintInBytes);

            this.workerHeight = Math.Min(this.sourceRectangle.Height, numberOfWindowBands * this.windowBandHeight);

            this.transposedFirstPassBuffer = configuration.MemoryAllocator.Allocate2D <Vector4>(
                this.workerHeight,
                destWidth,
                AllocationOptions.Clean);

            this.tempRowBuffer    = configuration.MemoryAllocator.Allocate <Vector4>(this.sourceRectangle.Width);
            this.tempColumnBuffer = configuration.MemoryAllocator.Allocate <Vector4>(destWidth);

            this.currentWindow = new RowInterval(0, this.workerHeight);
        }
        /// <inheritdoc/>
        protected override void OnFrameApply(ImageFrame <TPixel> source, ImageFrame <TPixel> destination)
        {
            Rectangle     sourceRectangle = this.SourceRectangle;
            Configuration configuration   = this.Configuration;

            // Handle resize dimensions identical to the original
            if (source.Width == destination.Width && source.Height == destination.Height && sourceRectangle == this.targetRectangle)
            {
                // The cloned will be blank here copy all the pixel data over
                source.GetPixelSpan().CopyTo(destination.GetPixelSpan());
                return;
            }

            int width   = this.targetWidth;
            int height  = this.targetHeight;
            int sourceX = sourceRectangle.X;
            int sourceY = sourceRectangle.Y;
            int startY  = this.targetRectangle.Y;
            int startX  = this.targetRectangle.X;

            var targetWorkingRect = Rectangle.Intersect(
                this.targetRectangle,
                new Rectangle(0, 0, width, height));

            if (this.resampler is NearestNeighborResampler)
            {
                // Scaling factors
                float widthFactor  = sourceRectangle.Width / (float)this.targetRectangle.Width;
                float heightFactor = sourceRectangle.Height / (float)this.targetRectangle.Height;

                ParallelHelper.IterateRows(
                    targetWorkingRect,
                    configuration,
                    rows =>
                {
                    for (int y = rows.Min; y < rows.Max; y++)
                    {
                        // Y coordinates of source points
                        Span <TPixel> sourceRow = source.GetPixelRowSpan((int)(((y - startY) * heightFactor) + sourceY));
                        Span <TPixel> targetRow = destination.GetPixelRowSpan(y);

                        for (int x = targetWorkingRect.Left; x < targetWorkingRect.Right; x++)
                        {
                            // X coordinates of source points
                            targetRow[x] = sourceRow[(int)(((x - startX) * widthFactor) + sourceX)];
                        }
                    }
                });

                return;
            }

            PixelConversionModifiers conversionModifiers =
                PixelConversionModifiers.Premultiply.ApplyCompanding(this.compand);

            BufferArea <TPixel> sourceArea = source.PixelBuffer.GetArea(sourceRectangle);

            // To reintroduce parallel processing, we to launch multiple workers
            // for different row intervals of the image.
            using (var worker = new ResizeWorker <TPixel>(
                       configuration,
                       sourceArea,
                       conversionModifiers,
                       this.horizontalKernelMap,
                       this.verticalKernelMap,
                       width,
                       targetWorkingRect,
                       this.targetRectangle.Location))
            {
                worker.Initialize();

                var workingInterval = new RowInterval(targetWorkingRect.Top, targetWorkingRect.Bottom);
                worker.FillDestinationPixels(workingInterval, destination.PixelBuffer);
            }
        }