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); }
public void Slice1() { var rowInterval = new RowInterval(10, 20); RowInterval sliced = rowInterval.Slice(5); Assert.Equal(15, sliced.Min); Assert.Equal(20, sliced.Max); }
/// <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); } }
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()); }
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];
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); }
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); }
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];
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); } }