mirror of https://github.com/SixLabors/ImageSharp
6 changed files with 88 additions and 200 deletions
@ -1,177 +0,0 @@ |
|||
// <copyright file="CompandingResizeProcessor.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp.Processing.Processors |
|||
{ |
|||
using System; |
|||
using System.Numerics; |
|||
using System.Threading.Tasks; |
|||
|
|||
/// <summary>
|
|||
/// Provides methods that allow the resizing of images using various algorithms.
|
|||
/// This version will expand and compress the image to and from a linear color space during processing.
|
|||
/// </summary>
|
|||
/// <typeparam name="TColor">The pixel format.</typeparam>
|
|||
internal class CompandingResizeProcessor<TColor> : ResamplingWeightedProcessor<TColor> |
|||
where TColor : struct, IPixel<TColor> |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="CompandingResizeProcessor{TColor}"/> class.
|
|||
/// </summary>
|
|||
/// <param name="sampler">The sampler to perform the resize operation.</param>
|
|||
/// <param name="width">The target width.</param>
|
|||
/// <param name="height">The target height.</param>
|
|||
public CompandingResizeProcessor(IResampler sampler, int width, int height) |
|||
: base(sampler, width, height, new Rectangle(0, 0, width, height)) |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="CompandingResizeProcessor{TColor}"/> class.
|
|||
/// </summary>
|
|||
/// <param name="sampler">The sampler to perform the resize operation.</param>
|
|||
/// <param name="width">The target width.</param>
|
|||
/// <param name="height">The target height.</param>
|
|||
/// <param name="resizeRectangle">
|
|||
/// The <see cref="Rectangle"/> structure that specifies the portion of the target image object to draw to.
|
|||
/// </param>
|
|||
public CompandingResizeProcessor(IResampler sampler, int width, int height, Rectangle resizeRectangle) |
|||
: base(sampler, width, height, resizeRectangle) |
|||
{ |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override bool Compand { get; set; } = true; |
|||
|
|||
/// <inheritdoc/>
|
|||
protected override unsafe void OnApply(ImageBase<TColor> source, Rectangle sourceRectangle) |
|||
{ |
|||
// Jump out, we'll deal with that later.
|
|||
if (source.Width == this.Width && source.Height == this.Height && sourceRectangle == this.ResizeRectangle) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
int width = this.Width; |
|||
int height = this.Height; |
|||
int sourceX = sourceRectangle.X; |
|||
int sourceY = sourceRectangle.Y; |
|||
int startY = this.ResizeRectangle.Y; |
|||
int endY = this.ResizeRectangle.Bottom; |
|||
int startX = this.ResizeRectangle.X; |
|||
int endX = this.ResizeRectangle.Right; |
|||
|
|||
int minX = Math.Max(0, startX); |
|||
int maxX = Math.Min(width, endX); |
|||
int minY = Math.Max(0, startY); |
|||
int maxY = Math.Min(height, endY); |
|||
|
|||
if (this.Sampler is NearestNeighborResampler) |
|||
{ |
|||
// Scaling factors
|
|||
float widthFactor = sourceRectangle.Width / (float)this.ResizeRectangle.Width; |
|||
float heightFactor = sourceRectangle.Height / (float)this.ResizeRectangle.Height; |
|||
|
|||
using (PixelAccessor<TColor> targetPixels = new PixelAccessor<TColor>(width, height)) |
|||
{ |
|||
using (PixelAccessor<TColor> sourcePixels = source.Lock()) |
|||
{ |
|||
Parallel.For( |
|||
minY, |
|||
maxY, |
|||
this.ParallelOptions, |
|||
y => |
|||
{ |
|||
// Y coordinates of source points
|
|||
int originY = (int)(((y - startY) * heightFactor) + sourceY); |
|||
|
|||
for (int x = minX; x < maxX; x++) |
|||
{ |
|||
// X coordinates of source points
|
|||
targetPixels[x, y] = sourcePixels[(int)(((x - startX) * widthFactor) + sourceX), originY]; |
|||
} |
|||
}); |
|||
} |
|||
|
|||
// Break out now.
|
|||
source.SwapPixelsBuffers(targetPixels); |
|||
return; |
|||
} |
|||
} |
|||
|
|||
// Interpolate the image using the calculated weights.
|
|||
// A 2-pass 1D algorithm appears to be faster than splitting a 1-pass 2D algorithm
|
|||
// First process the columns. Since we are not using multiple threads startY and endY
|
|||
// are the upper and lower bounds of the source rectangle.
|
|||
using (PixelAccessor<TColor> targetPixels = new PixelAccessor<TColor>(width, height)) |
|||
{ |
|||
using (PixelAccessor<TColor> sourcePixels = source.Lock()) |
|||
using (PixelAccessor<TColor> firstPassPixels = new PixelAccessor<TColor>(width, source.Height)) |
|||
{ |
|||
Parallel.For( |
|||
0, |
|||
sourceRectangle.Bottom, |
|||
this.ParallelOptions, |
|||
y => |
|||
{ |
|||
for (int x = minX; x < maxX; x++) |
|||
{ |
|||
// Ensure offsets are normalised for cropping and padding.
|
|||
WeightsWindow ws = this.HorizontalWeights.Weights[x - startX]; |
|||
float* horizontalValues = ws.Ptr; |
|||
int left = ws.Left; |
|||
|
|||
// Destination color components
|
|||
Vector4 destination = Vector4.Zero; |
|||
|
|||
for (int i = 0; i < ws.Length; i++) |
|||
{ |
|||
float xw = horizontalValues[i]; |
|||
int index = left + i; |
|||
destination += sourcePixels[index, y].ToVector4().Expand() * xw; |
|||
} |
|||
|
|||
TColor d = default(TColor); |
|||
d.PackFromVector4(destination.Compress()); |
|||
firstPassPixels[x, y] = d; |
|||
} |
|||
}); |
|||
|
|||
// Now process the rows.
|
|||
Parallel.For( |
|||
minY, |
|||
maxY, |
|||
this.ParallelOptions, |
|||
y => |
|||
{ |
|||
// Ensure offsets are normalised for cropping and padding.
|
|||
WeightsWindow ws = this.VerticalWeights.Weights[y - startY]; |
|||
float* verticalValues = ws.Ptr; |
|||
int left = ws.Left; |
|||
|
|||
for (int x = 0; x < width; x++) |
|||
{ |
|||
// Destination color components
|
|||
Vector4 destination = Vector4.Zero; |
|||
|
|||
for (int i = 0; i < ws.Length; i++) |
|||
{ |
|||
float yw = verticalValues[i]; |
|||
int index = left + i; |
|||
destination += firstPassPixels[x, index].ToVector4().Expand() * yw; |
|||
} |
|||
|
|||
TColor d = default(TColor); |
|||
d.PackFromVector4(destination.Compress()); |
|||
targetPixels[x, y] = d; |
|||
} |
|||
}); |
|||
} |
|||
|
|||
source.SwapPixelsBuffers(targetPixels); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue