Browse Source

pass Configuration to Vector4 converters in PixelOperations

pull/751/head
Anton Firszov 7 years ago
parent
commit
ca60ecf7f4
  1. 2
      src/ImageSharp.Drawing/Processing/BrushApplicator.cs
  2. 7
      src/ImageSharp.Drawing/Processing/ImageBrush{TPixel}.cs
  3. 7
      src/ImageSharp.Drawing/Processing/PatternBrush{TPixel}.cs
  4. 4
      src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs
  5. 7
      src/ImageSharp.Drawing/Processing/RecolorBrush{TPixel}.cs
  6. 10
      src/ImageSharp.Drawing/Processing/SolidBrush{TPixel}.cs
  7. 17
      src/ImageSharp/Formats/Gif/GifEncoderCore.cs
  8. 12
      src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs
  9. 2
      src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
  10. 3
      src/ImageSharp/Formats/Png/PngEncoderCore.cs
  11. 16
      src/ImageSharp/ImageFrame{TPixel}.cs
  12. 81
      src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs
  13. 20
      src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs
  14. 9
      src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs
  15. 28
      src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs
  16. 4
      src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs
  17. 4
      src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs
  18. 4
      src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs
  19. 19
      src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessorBase.cs
  20. 2
      src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor.cs
  21. 2
      src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs
  22. 2
      src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs
  23. 4
      src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs
  24. 6
      src/ImageSharp/Processing/Processors/Quantization/IQuantizer.cs
  25. 5
      src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs
  26. 5
      src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs
  27. 15
      src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs
  28. 2
      src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor.cs
  29. 5
      src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs
  30. 4
      src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs
  31. 10
      tests/ImageSharp.Benchmarks/Color/Bulk/FromVector4.cs
  32. 25
      tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs
  33. 8
      tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs
  34. 4
      tests/ImageSharp.Tests/Formats/Jpg/JpegImagePostProcessorTests.cs
  35. 20
      tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests_TPixel.cs
  36. 15
      tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs
  37. 25
      tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs
  38. 36
      tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs

2
src/ImageSharp.Drawing/Processing/BrushApplicator.cs

@ -89,7 +89,7 @@ namespace SixLabors.ImageSharp.Processing
}
Span<TPixel> destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length);
this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, overlaySpan, amountSpan);
this.Blender.Blend(this.Target.Configuration, destinationRow, destinationRow, overlaySpan, amountSpan);
}
}
}

7
src/ImageSharp.Drawing/Processing/ImageBrush{TPixel}.cs

@ -140,7 +140,12 @@ namespace SixLabors.ImageSharp.Processing
}
Span<TPixel> destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length);
this.Blender.Blend(this.source.MemoryAllocator, destinationRow, destinationRow, overlaySpan, amountSpan);
this.Blender.Blend(
this.source.Configuration,
destinationRow,
destinationRow,
overlaySpan,
amountSpan);
}
}
}

7
src/ImageSharp.Drawing/Processing/PatternBrush{TPixel}.cs

@ -170,7 +170,12 @@ namespace SixLabors.ImageSharp.Processing
}
Span<TPixel> destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length);
this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, overlaySpan, amountSpan);
this.Blender.Blend(
this.Target.Configuration,
destinationRow,
destinationRow,
overlaySpan,
amountSpan);
}
}
}

4
src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs

@ -79,8 +79,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
int width = maxX - minX;
MemoryAllocator memoryAllocator = this.Image.GetConfiguration().MemoryAllocator;
var workingRect = Rectangle.FromLTRB(minX, minY, maxX, maxY);
ParallelHelper.IterateRows(
@ -93,7 +91,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
Span<TPixelDst> background = source.GetPixelRowSpan(y).Slice(minX, width);
Span<TPixelSrc> foreground =
targetImage.GetPixelRowSpan(y - locationY).Slice(targetX, width);
blender.Blend<TPixelSrc>(memoryAllocator, background, background, foreground, this.Opacity);
blender.Blend<TPixelSrc>(configuration, background, background, foreground, this.Opacity);
}
});
}

7
src/ImageSharp.Drawing/Processing/RecolorBrush{TPixel}.cs

@ -158,7 +158,12 @@ namespace SixLabors.ImageSharp.Processing
}
Span<TPixel> destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length);
this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, overlaySpan, amountSpan);
this.Blender.Blend(
this.Target.Configuration,
destinationRow,
destinationRow,
overlaySpan,
amountSpan);
}
}
}

10
src/ImageSharp.Drawing/Processing/SolidBrush{TPixel}.cs

@ -92,10 +92,11 @@ namespace SixLabors.ImageSharp.Processing
Span<TPixel> destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length);
MemoryAllocator memoryAllocator = this.Target.MemoryAllocator;
Configuration configuration = this.Target.Configuration;
if (this.Options.BlendPercentage == 1f)
{
this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, this.Colors.GetSpan(), scanline);
this.Blender.Blend(configuration, destinationRow, destinationRow, this.Colors.GetSpan(), scanline);
}
else
{
@ -108,7 +109,12 @@ namespace SixLabors.ImageSharp.Processing
amountSpan[i] = scanline[i] * this.Options.BlendPercentage;
}
this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, this.Colors.GetSpan(), amountSpan);
this.Blender.Blend(
configuration,
destinationRow,
destinationRow,
this.Colors.GetSpan(),
amountSpan);
}
}
}

17
src/ImageSharp/Formats/Gif/GifEncoderCore.cs

@ -8,6 +8,7 @@ using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.MetaData;
using SixLabors.ImageSharp.PixelFormats;
@ -88,7 +89,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
// Quantize the image returning a palette.
QuantizedFrame<TPixel> quantized =
this.quantizer.CreateFrameQuantizer<TPixel>().QuantizeFrame(image.Frames.RootFrame);
this.quantizer.CreateFrameQuantizer<TPixel>(image.GetConfiguration()).QuantizeFrame(image.Frames.RootFrame);
// Get the number of bits.
this.bitDepth = ImageMaths.GetBitsNeededForColorDepth(quantized.Palette.Length).Clamp(1, 8);
@ -151,7 +152,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
else
{
using (QuantizedFrame<TPixel> paletteQuantized
= palleteQuantizer.CreateFrameQuantizer(() => quantized.Palette).QuantizeFrame(frame))
= palleteQuantizer.CreateFrameQuantizer(image.GetConfiguration(), () => quantized.Palette).QuantizeFrame(frame))
{
this.WriteImageData(paletteQuantized, stream);
}
@ -171,15 +172,17 @@ namespace SixLabors.ImageSharp.Formats.Gif
if (quantized is null)
{
// Allow each frame to be encoded at whatever color depth the frame designates if set.
if (previousFrame != null
&& previousMeta.ColorTableLength != frameMetaData.ColorTableLength
&& frameMetaData.ColorTableLength > 0)
if (previousFrame != null && previousMeta.ColorTableLength != frameMetaData.ColorTableLength
&& frameMetaData.ColorTableLength > 0)
{
quantized = this.quantizer.CreateFrameQuantizer<TPixel>(frameMetaData.ColorTableLength).QuantizeFrame(frame);
quantized = this.quantizer.CreateFrameQuantizer<TPixel>(
image.GetConfiguration(),
frameMetaData.ColorTableLength).QuantizeFrame(frame);
}
else
{
quantized = this.quantizer.CreateFrameQuantizer<TPixel>().QuantizeFrame(frame);
quantized = this.quantizer.CreateFrameQuantizer<TPixel>(image.GetConfiguration())
.QuantizeFrame(frame);
}
}

12
src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs

@ -26,6 +26,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
/// </summary>
internal class JpegImagePostProcessor : IDisposable
{
private readonly Configuration configuration;
/// <summary>
/// The number of block rows to be processed in one Step.
/// </summary>
@ -49,15 +51,17 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
/// <summary>
/// Initializes a new instance of the <see cref="JpegImagePostProcessor"/> class.
/// </summary>
/// <param name="memoryAllocator">The <see cref="MemoryAllocator"/> to use for buffer allocations.</param>
/// <param name="configuration">The <see cref="Configuration"/> to configure internal operations.</param>
/// <param name="rawJpeg">The <see cref="IRawJpegData"/> representing the uncompressed spectral Jpeg data</param>
public JpegImagePostProcessor(MemoryAllocator memoryAllocator, IRawJpegData rawJpeg)
public JpegImagePostProcessor(Configuration configuration, IRawJpegData rawJpeg)
{
this.configuration = configuration;
this.RawJpeg = rawJpeg;
IJpegComponent c0 = rawJpeg.Components.First();
this.NumberOfPostProcessorSteps = c0.SizeInBlocks.Height / BlockRowsPerStep;
this.PostProcessorBufferSize = new Size(c0.SizeInBlocks.Width * 8, PixelRowsPerStep);
MemoryAllocator memoryAllocator = configuration.MemoryAllocator;
this.ComponentProcessors = rawJpeg.Components.Select(c => new JpegComponentPostProcessor(memoryAllocator, this, c)).ToArray();
this.rgbaBuffer = memoryAllocator.Allocate<Vector4>(rawJpeg.ImageSizeInPixels.Width);
this.colorConverter = JpegColorConverter.GetConverter(rawJpeg.ColorSpace);
@ -158,9 +162,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
this.colorConverter.ConvertToRgba(values, this.rgbaBuffer.GetSpan());
Span<TPixel> destRow = destination.GetPixelRowSpan(yy);
// TODO: Investigate if slicing is actually necessary
PixelOperations<TPixel>.Instance.FromVector4(this.rgbaBuffer.GetSpan().Slice(0, destRow.Length), destRow);
PixelOperations<TPixel>.Instance.FromVector4(this.configuration, this.rgbaBuffer.GetSpan().Slice(0, destRow.Length), destRow);
}
}
}

2
src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs

@ -936,7 +936,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
private Image<TPixel> PostProcessIntoImage<TPixel>()
where TPixel : struct, IPixel<TPixel>
{
using (var postProcessor = new JpegImagePostProcessor(this.configuration.MemoryAllocator, this))
using (var postProcessor = new JpegImagePostProcessor(this.configuration, this))
{
var image = new Image<TPixel>(this.configuration, this.ImageWidth, this.ImageHeight, this.MetaData);
postProcessor.PostProcess(image.Frames.RootFrame);

3
src/ImageSharp/Formats/Png/PngEncoderCore.cs

@ -237,7 +237,8 @@ namespace SixLabors.ImageSharp.Formats.Png
}
// Create quantized frame returning the palette and set the bit depth.
quantized = this.quantizer.CreateFrameQuantizer<TPixel>().QuantizeFrame(image.Frames.RootFrame);
quantized = this.quantizer.CreateFrameQuantizer<TPixel>(image.GetConfiguration())
.QuantizeFrame(image.Frames.RootFrame);
byte quantizedBits = (byte)ImageMaths.GetBitsNeededForColorDepth(quantized.Palette.Length).Clamp(1, 8);
bits = Math.Max(bits, quantizedBits);

16
src/ImageSharp/ImageFrame{TPixel}.cs

@ -21,7 +21,6 @@ namespace SixLabors.ImageSharp
public sealed class ImageFrame<TPixel> : IPixelSource<TPixel>, IDisposable
where TPixel : struct, IPixel<TPixel>
{
private readonly Configuration configuration;
private bool isDisposed;
/// <summary>
@ -84,7 +83,7 @@ namespace SixLabors.ImageSharp
Guard.MustBeGreaterThan(width, 0, nameof(width));
Guard.MustBeGreaterThan(height, 0, nameof(height));
this.configuration = configuration;
this.Configuration = configuration;
this.MemoryAllocator = configuration.MemoryAllocator;
this.PixelBuffer = this.MemoryAllocator.Allocate2D<TPixel>(width, height);
this.MetaData = metaData ?? new ImageFrameMetaData();
@ -118,7 +117,7 @@ namespace SixLabors.ImageSharp
Guard.MustBeGreaterThan(height, 0, nameof(height));
Guard.NotNull(metaData, nameof(metaData));
this.configuration = configuration;
this.Configuration = configuration;
this.MemoryAllocator = configuration.MemoryAllocator;
this.PixelBuffer = new Buffer2D<TPixel>(memorySource, width, height);
this.MetaData = metaData;
@ -134,7 +133,7 @@ namespace SixLabors.ImageSharp
Guard.NotNull(configuration, nameof(configuration));
Guard.NotNull(source, nameof(source));
this.configuration = configuration;
this.Configuration = configuration;
this.MemoryAllocator = configuration.MemoryAllocator;
this.PixelBuffer = this.MemoryAllocator.Allocate2D<TPixel>(source.PixelBuffer.Width, source.PixelBuffer.Height);
source.PixelBuffer.GetSpan().CopyTo(this.PixelBuffer.GetSpan());
@ -146,6 +145,11 @@ namespace SixLabors.ImageSharp
/// </summary>
public MemoryAllocator MemoryAllocator { get; }
/// <summary>
/// Gets the <see cref="Configuration"/> instance associated with this <see cref="ImageFrame{TPixel}"/>.
/// </summary>
internal Configuration Configuration { get; }
/// <summary>
/// Gets the image pixels. Not private as Buffer2D requires an array in its constructor.
/// </summary>
@ -254,7 +258,7 @@ namespace SixLabors.ImageSharp
/// Clones the current instance.
/// </summary>
/// <returns>The <see cref="ImageFrame{TPixel}"/></returns>
internal ImageFrame<TPixel> Clone() => this.Clone(this.configuration);
internal ImageFrame<TPixel> Clone() => this.Clone(this.Configuration);
/// <summary>
/// Clones the current instance.
@ -269,7 +273,7 @@ namespace SixLabors.ImageSharp
/// <typeparam name="TPixel2">The pixel format.</typeparam>
/// <returns>The <see cref="ImageFrame{TPixel2}"/></returns>
internal ImageFrame<TPixel2> CloneAs<TPixel2>()
where TPixel2 : struct, IPixel<TPixel2> => this.CloneAs<TPixel2>(this.configuration);
where TPixel2 : struct, IPixel<TPixel2> => this.CloneAs<TPixel2>(this.Configuration);
/// <summary>
/// Returns a copy of the image frame in the given pixel format.

81
src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs

@ -4,8 +4,8 @@
using System;
using System.Buffers;
using System.Numerics;
using SixLabors.ImageSharp.Memory;
using SixLabors.Memory;
namespace SixLabors.ImageSharp.PixelFormats
{
@ -38,7 +38,11 @@ namespace SixLabors.ImageSharp.PixelFormats
/// A value between 0 and 1 indicating the weight of the second source vector.
/// At amount = 0, "from" is returned, at amount = 1, "to" is returned.
/// </param>
protected abstract void BlendFunction(Span<Vector4> destination, ReadOnlySpan<Vector4> background, ReadOnlySpan<Vector4> source, float amount);
protected abstract void BlendFunction(
Span<Vector4> destination,
ReadOnlySpan<Vector4> background,
ReadOnlySpan<Vector4> source,
float amount);
/// <summary>
/// Blend 2 rows together.
@ -50,12 +54,16 @@ namespace SixLabors.ImageSharp.PixelFormats
/// A span with values between 0 and 1 indicating the weight of the second source vector.
/// At amount = 0, "from" is returned, at amount = 1, "to" is returned.
/// </param>
protected abstract void BlendFunction(Span<Vector4> destination, ReadOnlySpan<Vector4> background, ReadOnlySpan<Vector4> source, ReadOnlySpan<float> amount);
protected abstract void BlendFunction(
Span<Vector4> destination,
ReadOnlySpan<Vector4> background,
ReadOnlySpan<Vector4> source,
ReadOnlySpan<float> amount);
/// <summary>
/// Blends 2 rows together
/// </summary>
/// <param name="memoryManager">memory manager to use internally</param>
/// <param name="configuration"><see cref="Configuration"/> to use internally</param>
/// <param name="destination">the destination span</param>
/// <param name="background">the background span</param>
/// <param name="source">the source span</param>
@ -63,16 +71,21 @@ namespace SixLabors.ImageSharp.PixelFormats
/// A span with values between 0 and 1 indicating the weight of the second source vector.
/// At amount = 0, "from" is returned, at amount = 1, "to" is returned.
/// </param>
public void Blend(MemoryAllocator memoryManager, Span<TPixel> destination, ReadOnlySpan<TPixel> background, ReadOnlySpan<TPixel> source, ReadOnlySpan<float> amount)
public void Blend(
Configuration configuration,
Span<TPixel> destination,
ReadOnlySpan<TPixel> background,
ReadOnlySpan<TPixel> source,
ReadOnlySpan<float> amount)
{
this.Blend<TPixel>(memoryManager, destination, background, source, amount);
this.Blend<TPixel>(configuration, destination, background, source, amount);
}
/// <summary>
/// Blends 2 rows together
/// </summary>
/// <typeparam name="TPixelSrc">the pixel format of the source span</typeparam>
/// <param name="memoryManager">memory manager to use internally</param>
/// <param name="configuration"><see cref="Configuration"/> to use internally</param>
/// <param name="destination">the destination span</param>
/// <param name="background">the background span</param>
/// <param name="source">the source span</param>
@ -80,25 +93,40 @@ namespace SixLabors.ImageSharp.PixelFormats
/// A span with values between 0 and 1 indicating the weight of the second source vector.
/// At amount = 0, "from" is returned, at amount = 1, "to" is returned.
/// </param>
public void Blend<TPixelSrc>(MemoryAllocator memoryManager, Span<TPixel> destination, ReadOnlySpan<TPixel> background, ReadOnlySpan<TPixelSrc> source, ReadOnlySpan<float> amount)
public void Blend<TPixelSrc>(
Configuration configuration,
Span<TPixel> destination,
ReadOnlySpan<TPixel> background,
ReadOnlySpan<TPixelSrc> source,
ReadOnlySpan<float> amount)
where TPixelSrc : struct, IPixel<TPixelSrc>
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length));
using (IMemoryOwner<Vector4> buffer = memoryManager.Allocate<Vector4>(destination.Length * 3))
using (IMemoryOwner<Vector4> buffer =
configuration.MemoryAllocator.Allocate<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToScaledVector4(background.Slice(0, background.Length), backgroundSpan);
PixelOperations<TPixelSrc>.Instance.ToScaledVector4(source.Slice(0, background.Length), sourceSpan);
PixelOperations<TPixel>.Instance.ToScaledVector4(
configuration,
background.Slice(0, background.Length),
backgroundSpan);
PixelOperations<TPixelSrc>.Instance.ToScaledVector4(
configuration,
source.Slice(0, background.Length),
sourceSpan);
this.BlendFunction(destinationSpan, backgroundSpan, sourceSpan, amount);
PixelOperations<TPixel>.Instance.FromScaledVector4(destinationSpan.Slice(0, background.Length), destination);
PixelOperations<TPixel>.Instance.FromScaledVector4(
configuration,
destinationSpan.Slice(0, background.Length),
destination);
}
}
@ -106,7 +134,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// Blends 2 rows together
/// </summary>
/// <typeparam name="TPixelSrc">the pixel format of the source span</typeparam>
/// <param name="memoryManager">memory manager to use internally</param>
/// <param name="configuration"><see cref="Configuration"/> to use internally</param>
/// <param name="destination">the destination span</param>
/// <param name="background">the background span</param>
/// <param name="source">the source span</param>
@ -114,26 +142,41 @@ namespace SixLabors.ImageSharp.PixelFormats
/// A value between 0 and 1 indicating the weight of the second source vector.
/// At amount = 0, "from" is returned, at amount = 1, "to" is returned.
/// </param>
public void Blend<TPixelSrc>(MemoryAllocator memoryManager, Span<TPixel> destination, ReadOnlySpan<TPixel> background, ReadOnlySpan<TPixelSrc> source, float amount)
public void Blend<TPixelSrc>(
Configuration configuration,
Span<TPixel> destination,
ReadOnlySpan<TPixel> background,
ReadOnlySpan<TPixelSrc> source,
float amount)
where TPixelSrc : struct, IPixel<TPixelSrc>
{
Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length));
Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length));
Guard.MustBeBetweenOrEqualTo(amount, 0, 1, nameof(amount));
using (IMemoryOwner<Vector4> buffer = memoryManager.Allocate<Vector4>(destination.Length * 3))
using (IMemoryOwner<Vector4> buffer =
configuration.MemoryAllocator.Allocate<Vector4>(destination.Length * 3))
{
Span<Vector4> destinationSpan = buffer.Slice(0, destination.Length);
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToScaledVector4(background.Slice(0, background.Length), backgroundSpan);
PixelOperations<TPixelSrc>.Instance.ToScaledVector4(source.Slice(0, background.Length), sourceSpan);
PixelOperations<TPixel>.Instance.ToScaledVector4(
configuration,
background.Slice(0, background.Length),
backgroundSpan);
PixelOperations<TPixelSrc>.Instance.ToScaledVector4(
configuration,
source.Slice(0, background.Length),
sourceSpan);
this.BlendFunction(destinationSpan, backgroundSpan, sourceSpan, amount);
PixelOperations<TPixel>.Instance.FromScaledVector4(destinationSpan.Slice(0, background.Length), destination);
PixelOperations<TPixel>.Instance.FromScaledVector4(
configuration,
destinationSpan.Slice(0, background.Length),
destination);
}
}
}
}
}

20
src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs

@ -19,7 +19,10 @@ namespace SixLabors.ImageSharp.PixelFormats
internal partial class PixelOperations : PixelOperations<Rgba32>
{
/// <inheritdoc />
internal override void ToVector4(ReadOnlySpan<Rgba32> sourceColors, Span<Vector4> destinationVectors)
internal override void ToVector4(
Configuration configuration,
ReadOnlySpan<Rgba32> sourceColors,
Span<Vector4> destinationVectors)
{
Guard.DestinationShouldNotBeTooShort(sourceColors, destinationVectors, nameof(destinationVectors));
@ -31,7 +34,10 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
internal override void FromVector4(ReadOnlySpan<Vector4> sourceVectors, Span<Rgba32> destinationColors)
internal override void FromVector4(
Configuration configuration,
ReadOnlySpan<Vector4> sourceVectors,
Span<Rgba32> destinationColors)
{
Guard.DestinationShouldNotBeTooShort(sourceVectors, destinationColors, nameof(destinationColors));
@ -43,17 +49,21 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
internal override void ToScaledVector4(ReadOnlySpan<Rgba32> sourceColors, Span<Vector4> destinationVectors)
internal override void ToScaledVector4(
Configuration configuration,
ReadOnlySpan<Rgba32> sourceColors,
Span<Vector4> destinationVectors)
{
this.ToVector4(sourceColors, destinationVectors);
this.ToVector4(configuration, sourceColors, destinationVectors);
}
/// <inheritdoc />
internal override void FromScaledVector4(
Configuration configuration,
ReadOnlySpan<Vector4> sourceVectors,
Span<Rgba32> destinationColors)
{
this.FromVector4(sourceVectors, destinationColors);
this.FromVector4(configuration, sourceVectors, destinationColors);
}
}
}

9
src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs

@ -19,6 +19,7 @@ namespace SixLabors.ImageSharp.PixelFormats
{
/// <inheritdoc />
internal override void FromScaledVector4(
Configuration configuration,
ReadOnlySpan<Vector4> sourceVectors,
Span<RgbaVector> destinationColors)
{
@ -29,12 +30,16 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <inheritdoc />
internal override void ToScaledVector4(
Configuration configuration,
ReadOnlySpan<RgbaVector> sourceColors,
Span<Vector4> destinationVectors)
=> this.ToVector4(sourceColors, destinationVectors);
=> this.ToVector4(configuration, sourceColors, destinationVectors);
/// <inheritdoc />
internal override void ToVector4(ReadOnlySpan<RgbaVector> sourceColors, Span<Vector4> destinationVectors)
internal override void ToVector4(
Configuration configuration,
ReadOnlySpan<RgbaVector> sourceColors,
Span<Vector4> destinationVectors)
{
Guard.DestinationShouldNotBeTooShort(sourceColors, destinationVectors, nameof(destinationVectors));

28
src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs

@ -24,10 +24,15 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <summary>
/// Bulk version of <see cref="IPixel.FromVector4"/> converting 'sourceVectors.Length' pixels into 'destinationColors'.
/// </summary>
/// <param name="configuration">A <see cref="Configuration"/> to configure internal operations</param>
/// <param name="sourceVectors">The <see cref="Span{T}"/> to the source vectors.</param>
/// <param name="destinationColors">The <see cref="Span{T}"/> to the destination colors.</param>
internal virtual void FromVector4(ReadOnlySpan<Vector4> sourceVectors, Span<TPixel> destinationColors)
internal virtual void FromVector4(
Configuration configuration,
ReadOnlySpan<Vector4> sourceVectors,
Span<TPixel> destinationColors)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourceVectors, destinationColors, nameof(destinationColors));
ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceVectors);
@ -44,10 +49,15 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <summary>
/// Bulk version of <see cref="IPixel.ToVector4()"/> converting 'sourceColors.Length' pixels into 'destinationVectors'.
/// </summary>
/// <param name="configuration">A <see cref="Configuration"/> to configure internal operations</param>
/// <param name="sourceColors">The <see cref="Span{T}"/> to the source colors.</param>
/// <param name="destinationVectors">The <see cref="Span{T}"/> to the destination vectors.</param>
internal virtual void ToVector4(ReadOnlySpan<TPixel> sourceColors, Span<Vector4> destinationVectors)
internal virtual void ToVector4(
Configuration configuration,
ReadOnlySpan<TPixel> sourceColors,
Span<Vector4> destinationVectors)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourceColors, destinationVectors, nameof(destinationVectors));
ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourceColors);
@ -64,10 +74,15 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <summary>
/// Bulk version of <see cref="IPixel.FromScaledVector4"/> converting 'sourceVectors.Length' pixels into 'destinationColors'.
/// </summary>
/// <param name="configuration">A <see cref="Configuration"/> to configure internal operations</param>
/// <param name="sourceVectors">The <see cref="Span{T}"/> to the source vectors.</param>
/// <param name="destinationColors">The <see cref="Span{T}"/> to the destination colors.</param>
internal virtual void FromScaledVector4(ReadOnlySpan<Vector4> sourceVectors, Span<TPixel> destinationColors)
internal virtual void FromScaledVector4(
Configuration configuration,
ReadOnlySpan<Vector4> sourceVectors,
Span<TPixel> destinationColors)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourceVectors, destinationColors, nameof(destinationColors));
ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceVectors);
@ -84,10 +99,15 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <summary>
/// Bulk version of <see cref="IPixel.ToScaledVector4()"/> converting 'sourceColors.Length' pixels into 'destinationVectors'.
/// </summary>
/// <param name="configuration">A <see cref="Configuration"/> to configure internal operations</param>
/// <param name="sourceColors">The <see cref="Span{T}"/> to the source colors.</param>
/// <param name="destinationVectors">The <see cref="Span{T}"/> to the destination vectors.</param>
internal virtual void ToScaledVector4(ReadOnlySpan<TPixel> sourceColors, Span<Vector4> destinationVectors)
internal virtual void ToScaledVector4(
Configuration configuration,
ReadOnlySpan<TPixel> sourceColors,
Span<Vector4> destinationVectors)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourceColors, destinationVectors, nameof(destinationVectors));
ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourceColors);

4
src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs

@ -75,14 +75,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
for (int y = rows.Min; y < rows.Max; y++)
{
Span<TPixel> targetRowSpan = targetPixels.GetRowSpan(y).Slice(startX);
PixelOperations<TPixel>.Instance.ToVector4(targetRowSpan.Slice(0, length), vectorSpan);
PixelOperations<TPixel>.Instance.ToVector4(configuration, targetRowSpan.Slice(0, length), vectorSpan);
for (int x = 0; x < width; x++)
{
DenseMatrixUtils.Convolve2D(in matrixY, in matrixX, source.PixelBuffer, vectorSpan, y, x, maxY, maxX, startX);
}
PixelOperations<TPixel>.Instance.FromVector4(vectorSpan.Slice(0, length), targetRowSpan);
PixelOperations<TPixel>.Instance.FromVector4(configuration, vectorSpan.Slice(0, length), targetRowSpan);
}
});

4
src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs

@ -93,14 +93,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
for (int y = rows.Min; y < rows.Max; y++)
{
Span<TPixel> targetRowSpan = targetPixels.GetRowSpan(y).Slice(startX);
PixelOperations<TPixel>.Instance.ToVector4(targetRowSpan.Slice(0, length), vectorSpan);
PixelOperations<TPixel>.Instance.ToVector4(configuration, targetRowSpan.Slice(0, length), vectorSpan);
for (int x = 0; x < width; x++)
{
DenseMatrixUtils.Convolve(in matrix, sourcePixels, vectorSpan, y, x, maxY, maxX, startX);
}
PixelOperations<TPixel>.Instance.FromVector4(vectorSpan.Slice(0, length), targetRowSpan);
PixelOperations<TPixel>.Instance.FromVector4(configuration, vectorSpan.Slice(0, length), targetRowSpan);
}
});
}

4
src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs

@ -59,14 +59,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
for (int y = rows.Min; y < rows.Max; y++)
{
Span<TPixel> targetRowSpan = targetPixels.GetRowSpan(y).Slice(startX);
PixelOperations<TPixel>.Instance.ToVector4(targetRowSpan.Slice(0, length), vectorSpan);
PixelOperations<TPixel>.Instance.ToVector4(configuration, targetRowSpan.Slice(0, length), vectorSpan);
for (int x = 0; x < width; x++)
{
DenseMatrixUtils.Convolve(in matrix, source.PixelBuffer, vectorSpan, y, x, maxY, maxX, startX);
}
PixelOperations<TPixel>.Instance.FromVector4(vectorSpan.Slice(0, length), targetRowSpan);
PixelOperations<TPixel>.Instance.FromVector4(configuration, vectorSpan.Slice(0, length), targetRowSpan);
}
});

19
src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessorBase.cs

@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Numerics;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Dithering
{
@ -21,7 +22,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering
/// <summary>
/// The vector representation of the image palette.
/// </summary>
private readonly Vector4[] paletteVector;
private Vector4[] paletteVector;
/// <summary>
/// Initializes a new instance of the <see cref="PaletteDitherProcessorBase{TPixel}"/> class.
@ -30,8 +31,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering
protected PaletteDitherProcessorBase(TPixel[] palette)
{
this.Palette = palette ?? throw new ArgumentNullException(nameof(palette));
this.paletteVector = new Vector4[this.Palette.Length];
PixelOperations<TPixel>.Instance.ToScaledVector4(this.Palette, this.paletteVector);
}
/// <summary>
@ -40,7 +39,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering
public TPixel[] Palette { get; }
/// <summary>
/// Returns the two closest colors from the palette calcluated via Euclidean distance in the Rgba space.
/// Returns the two closest colors from the palette calculated via Euclidean distance in the Rgba space.
/// </summary>
/// <param name="pixel">The source color to match.</param>
/// <returns>The <see cref="PixelPair{TPixel}"/>.</returns>
@ -90,5 +89,17 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering
return pair;
}
protected override void BeforeFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{
base.BeforeFrameApply(source, sourceRectangle, configuration);
// Lazy init paletteVector:
if (this.paletteVector == null)
{
this.paletteVector = new Vector4[this.Palette.Length];
PixelOperations<TPixel>.Instance.ToScaledVector4(configuration, this.Palette, this.paletteVector);
}
}
}
}

2
src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor.cs

@ -94,7 +94,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays
// This switched color & destination in the 2nd and 3rd places because we are applying the target color under the current one
blender.Blend(
source.MemoryAllocator,
source.Configuration,
destination,
colors.GetSpan(),
destination,

2
src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs

@ -145,7 +145,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays
Span<TPixel> destination = source.GetPixelRowSpan(offsetY).Slice(offsetX, width);
this.blender.Blend(
source.MemoryAllocator,
source.Configuration,
destination,
destination,
rowColors.GetSpan(),

2
src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs

@ -147,7 +147,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays
Span<TPixel> destination = source.GetPixelRowSpan(offsetY).Slice(offsetX, width);
this.blender.Blend(
source.MemoryAllocator,
source.Configuration,
destination,
destination,
rowColors.GetSpan(),

4
src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs

@ -17,6 +17,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
public abstract class FrameQuantizerBase<TPixel> : IFrameQuantizer<TPixel>
where TPixel : struct, IPixel<TPixel>
{
private readonly Configuration configuration;
/// <summary>
/// A lookup table for colors
/// </summary>
@ -79,7 +81,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
// Collect the palette. Required before the second pass runs.
TPixel[] palette = this.GetPalette();
this.paletteVector = new Vector4[palette.Length];
PixelOperations<TPixel>.Instance.ToScaledVector4(palette, this.paletteVector);
PixelOperations<TPixel>.Instance.ToScaledVector4(image.Configuration, palette, this.paletteVector);
var quantizedFrame = new QuantizedFrame<TPixel>(image.MemoryAllocator, width, height, palette);
if (this.Dither)

6
src/ImageSharp/Processing/Processors/Quantization/IQuantizer.cs

@ -19,18 +19,20 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
/// <summary>
/// Creates the generic frame quantizer
/// </summary>
/// <param name="configuration">The <see cref="Configuration"/> to configure internal operations.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <returns>The <see cref="IFrameQuantizer{TPixel}"/></returns>
IFrameQuantizer<TPixel> CreateFrameQuantizer<TPixel>()
IFrameQuantizer<TPixel> CreateFrameQuantizer<TPixel>(Configuration configuration)
where TPixel : struct, IPixel<TPixel>;
/// <summary>
/// Creates the generic frame quantizer
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="configuration">The <see cref="Configuration"/> to configure internal operations.</param>
/// <param name="maxColors">The maximum number of colors to hold in the color palette.</param>
/// <returns>The <see cref="IFrameQuantizer{TPixel}"/></returns>
IFrameQuantizer<TPixel> CreateFrameQuantizer<TPixel>(int maxColors)
IFrameQuantizer<TPixel> CreateFrameQuantizer<TPixel>(Configuration configuration, int maxColors)
where TPixel : struct, IPixel<TPixel>;
}
}

5
src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs

@ -74,13 +74,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
/// </summary>
public int MaxColors { get; }
/// <param name="configuration"></param>
/// <inheritdoc />
public IFrameQuantizer<TPixel> CreateFrameQuantizer<TPixel>()
public IFrameQuantizer<TPixel> CreateFrameQuantizer<TPixel>(Configuration configuration)
where TPixel : struct, IPixel<TPixel>
=> new OctreeFrameQuantizer<TPixel>(this);
/// <inheritdoc/>
public IFrameQuantizer<TPixel> CreateFrameQuantizer<TPixel>(int maxColors)
public IFrameQuantizer<TPixel> CreateFrameQuantizer<TPixel>(Configuration configuration, int maxColors)
where TPixel : struct, IPixel<TPixel>
{
maxColors = maxColors.Clamp(1, DefaultMaxColors);

5
src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs

@ -31,9 +31,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
/// <summary>
/// Initializes a new instance of the <see cref="PaletteFrameQuantizer{TPixel}"/> class.
/// </summary>
/// <param name="configuration">The <see cref="Configuration"/> to configure internal operations.</param>
/// <param name="quantizer">The palette quantizer.</param>
/// <param name="colors">An array of all colors in the palette.</param>
public PaletteFrameQuantizer(PaletteQuantizer quantizer, TPixel[] colors)
public PaletteFrameQuantizer(Configuration configuration, PaletteQuantizer quantizer, TPixel[] colors)
: base(quantizer, true)
{
// TODO: Why is this value constrained? Gif has limitations but theoretically
@ -41,7 +42,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
Guard.MustBeBetweenOrEqualTo(colors.Length, 1, 256, nameof(colors));
this.palette = colors;
this.paletteVector = new Vector4[this.palette.Length];
PixelOperations<TPixel>.Instance.ToScaledVector4(this.palette, this.paletteVector);
PixelOperations<TPixel>.Instance.ToScaledVector4(configuration, this.palette, this.paletteVector);
}
/// <inheritdoc/>

15
src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs

@ -43,12 +43,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
public IErrorDiffuser Diffuser { get; }
/// <inheritdoc />
public virtual IFrameQuantizer<TPixel> CreateFrameQuantizer<TPixel>()
public virtual IFrameQuantizer<TPixel> CreateFrameQuantizer<TPixel>(Configuration configuration)
where TPixel : struct, IPixel<TPixel>
=> this.CreateFrameQuantizer(() => NamedColors<TPixel>.WebSafePalette);
=> this.CreateFrameQuantizer(configuration, () => NamedColors<TPixel>.WebSafePalette);
/// <inheritdoc/>
public IFrameQuantizer<TPixel> CreateFrameQuantizer<TPixel>(int maxColors)
public IFrameQuantizer<TPixel> CreateFrameQuantizer<TPixel>(Configuration configuration, int maxColors)
where TPixel : struct, IPixel<TPixel>
{
TPixel[] websafe = NamedColors<TPixel>.WebSafePalette;
@ -56,21 +56,22 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
if (max != websafe.Length)
{
return this.CreateFrameQuantizer(() => NamedColors<TPixel>.WebSafePalette.AsSpan(0, max).ToArray());
return this.CreateFrameQuantizer(configuration, () => NamedColors<TPixel>.WebSafePalette.AsSpan(0, max).ToArray());
}
return this.CreateFrameQuantizer(() => websafe);
return this.CreateFrameQuantizer(configuration, () => websafe);
}
/// <summary>
/// Gets the palette to use to quantize the image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="configuration">The <see cref="Configuration"/> to configure internal operations</param>
/// <param name="paletteFunction">The method to return the palette.</param>
/// <returns>The <see cref="IFrameQuantizer{TPixel}"/></returns>
public IFrameQuantizer<TPixel> CreateFrameQuantizer<TPixel>(Func<TPixel[]> paletteFunction)
public IFrameQuantizer<TPixel> CreateFrameQuantizer<TPixel>(Configuration configuration, Func<TPixel[]> paletteFunction)
where TPixel : struct, IPixel<TPixel>
=> new PaletteFrameQuantizer<TPixel>(this, paletteFunction.Invoke());
=> new PaletteFrameQuantizer<TPixel>(configuration, this, paletteFunction.Invoke());
private static IErrorDiffuser GetDiffuser(bool dither) => dither ? KnownDiffusers.FloydSteinberg : null;
}

2
src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor.cs

@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
/// <inheritdoc />
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{
IFrameQuantizer<TPixel> executor = this.Quantizer.CreateFrameQuantizer<TPixel>();
IFrameQuantizer<TPixel> executor = this.Quantizer.CreateFrameQuantizer<TPixel>(configuration);
using (QuantizedFrame<TPixel> quantized = executor.QuantizeFrame(source))
{
int paletteCount = quantized.Palette.Length - 1;

5
src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs

@ -73,13 +73,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
/// </summary>
public int MaxColors { get; }
/// <param name="configuration"></param>
/// <inheritdoc />
public IFrameQuantizer<TPixel> CreateFrameQuantizer<TPixel>()
public IFrameQuantizer<TPixel> CreateFrameQuantizer<TPixel>(Configuration configuration)
where TPixel : struct, IPixel<TPixel>
=> new WuFrameQuantizer<TPixel>(this);
/// <inheritdoc/>
public IFrameQuantizer<TPixel> CreateFrameQuantizer<TPixel>(int maxColors)
public IFrameQuantizer<TPixel> CreateFrameQuantizer<TPixel>(Configuration configuration, int maxColors)
where TPixel : struct, IPixel<TPixel>
{
maxColors = maxColors.Clamp(1, DefaultMaxColors);

4
src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs

@ -257,7 +257,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
Span<TPixel> sourceRow = source.GetPixelRowSpan(y);
Span<Vector4> tempRowSpan = tempRowBuffer.Span;
PixelOperations<TPixel>.Instance.ToVector4(sourceRow, tempRowSpan);
PixelOperations<TPixel>.Instance.ToVector4(configuration, sourceRow, tempRowSpan);
Vector4Utils.Premultiply(tempRowSpan);
ref Vector4 firstPassBaseRef = ref firstPassPixelsTransposed.Span[y];
@ -309,7 +309,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
}
Span<TPixel> targetRowSpan = destination.GetPixelRowSpan(y);
PixelOperations<TPixel>.Instance.FromVector4(tempRowSpan, targetRowSpan);
PixelOperations<TPixel>.Instance.FromVector4(configuration, tempRowSpan, targetRowSpan);
}
});
}

10
tests/ImageSharp.Benchmarks/Color/Bulk/FromVector4.cs

@ -24,6 +24,8 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
protected IMemoryOwner<TPixel> destination;
protected Configuration Configuration => Configuration.Default;
[Params(
64,
2048
@ -33,8 +35,8 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
[GlobalSetup]
public void Setup()
{
this.destination = Configuration.Default.MemoryAllocator.Allocate<TPixel>(this.Count);
this.source = Configuration.Default.MemoryAllocator.Allocate<Vector4>(this.Count);
this.destination = this.Configuration.MemoryAllocator.Allocate<TPixel>(this.Count);
this.source = this.Configuration.MemoryAllocator.Allocate<Vector4>(this.Count);
}
[GlobalCleanup]
@ -59,13 +61,13 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
[Benchmark]
public void PixelOperations_Base()
{
new PixelOperations<TPixel>().FromVector4(this.source.GetSpan(), this.destination.GetSpan());
new PixelOperations<TPixel>().FromVector4(this.Configuration, this.source.GetSpan(), this.destination.GetSpan());
}
[Benchmark]
public void PixelOperations_Specialized()
{
PixelOperations<TPixel>.Instance.FromVector4(this.source.GetSpan(), this.destination.GetSpan());
PixelOperations<TPixel>.Instance.FromVector4(this.Configuration, this.source.GetSpan(), this.destination.GetSpan());
}
}

25
tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs

@ -10,10 +10,6 @@ using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Attributes.Jobs;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Environments;
using BenchmarkDotNet.Jobs;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@ -27,20 +23,21 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
protected IMemoryOwner<Vector4> destination;
protected Configuration Configuration => Configuration.Default;
[Params(
64,
64,
//256,
//512,
//1024,
2048
)]
2048)]
public int Count { get; set; }
[GlobalSetup]
public void Setup()
{
this.source = Configuration.Default.MemoryAllocator.Allocate<TPixel>(this.Count);
this.destination = Configuration.Default.MemoryAllocator.Allocate<Vector4>(this.Count);
this.source = this.Configuration.MemoryAllocator.Allocate<TPixel>(this.Count);
this.destination = this.Configuration.MemoryAllocator.Allocate<Vector4>(this.Count);
}
[GlobalCleanup]
@ -65,13 +62,19 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
[Benchmark]
public void PixelOperations_Base()
{
new PixelOperations<TPixel>().ToVector4(this.source.GetSpan(), this.destination.GetSpan());
new PixelOperations<TPixel>().ToVector4(
this.Configuration,
this.source.GetSpan(),
this.destination.GetSpan());
}
[Benchmark]
public void PixelOperations_Specialized()
{
PixelOperations<TPixel>.Instance.ToVector4(this.source.GetSpan(), this.destination.GetSpan());
PixelOperations<TPixel>.Instance.ToVector4(
this.Configuration,
this.source.GetSpan(),
this.destination.GetSpan());
}
}

8
tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs

@ -17,6 +17,8 @@ namespace SixLabors.ImageSharp.Benchmarks
public class PorterDuffBulkVsPixel : BenchmarkBase
{
private Configuration Configuration => Configuration.Default;
private void BulkVectorConvert<TPixel>(
Span<TPixel> destination,
Span<TPixel> background,
@ -35,15 +37,15 @@ namespace SixLabors.ImageSharp.Benchmarks
Span<Vector4> backgroundSpan = buffer.Slice(destination.Length, destination.Length);
Span<Vector4> sourceSpan = buffer.Slice(destination.Length * 2, destination.Length);
PixelOperations<TPixel>.Instance.ToVector4(background, backgroundSpan);
PixelOperations<TPixel>.Instance.ToVector4(source, sourceSpan);
PixelOperations<TPixel>.Instance.ToVector4(this.Configuration, background, backgroundSpan);
PixelOperations<TPixel>.Instance.ToVector4(this.Configuration, source, sourceSpan);
for (int i = 0; i < destination.Length; i++)
{
destinationSpan[i] = PorterDuffFunctions.NormalSrcOver(backgroundSpan[i], sourceSpan[i], amount[i]);
}
PixelOperations<TPixel>.Instance.FromVector4(destinationSpan, destination);
PixelOperations<TPixel>.Instance.FromVector4(this.Configuration, destinationSpan, destination);
}
}

4
tests/ImageSharp.Tests/Formats/Jpg/JpegImagePostProcessorTests.cs

@ -48,7 +48,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
{
string imageFile = provider.SourceFileOrDescription;
using (JpegDecoderCore decoder = JpegFixture.ParseJpegStream(imageFile))
using (var pp = new JpegImagePostProcessor(Configuration.Default.MemoryAllocator, decoder))
using (var pp = new JpegImagePostProcessor(Configuration.Default, decoder))
using (var imageFrame = new ImageFrame<Rgba32>(Configuration.Default, decoder.ImageWidth, decoder.ImageHeight))
{
pp.DoPostProcessorStep(imageFrame);
@ -68,7 +68,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
{
string imageFile = provider.SourceFileOrDescription;
using (JpegDecoderCore decoder = JpegFixture.ParseJpegStream(imageFile))
using (var pp = new JpegImagePostProcessor(Configuration.Default.MemoryAllocator, decoder))
using (var pp = new JpegImagePostProcessor(Configuration.Default, decoder))
using (var image = new Image<Rgba32>(decoder.ImageWidth, decoder.ImageHeight))
{
pp.PostProcess(image.Frames.RootFrame);

20
tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests_TPixel.cs

@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders
{ new TestPixel<Rgba32>(1,1,1,1), new TestPixel<Rgba32>(0,0,0,.8f), .5f, new TestPixel<Rgba32>(0.6f, 0.6f, 0.6f, 1) },
};
private MemoryAllocator MemoryAllocator { get; } = Configuration.Default.MemoryAllocator;
private Configuration Configuration => Configuration.Default;
[Theory]
[MemberData(nameof(NormalBlendFunctionData))]
@ -50,7 +50,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders
where TPixel : struct, IPixel<TPixel>
{
var dest = new Span<TPixel>(new TPixel[1]);
new DefaultPixelBlenders<TPixel>.NormalSrcOver().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount));
new DefaultPixelBlenders<TPixel>.NormalSrcOver().Blend(this.Configuration, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount));
VectorAssert.Equal(expected, dest[0], 2);
}
@ -89,7 +89,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders
where TPixel : struct, IPixel<TPixel>
{
var dest = new Span<TPixel>(new TPixel[1]);
new DefaultPixelBlenders<TPixel>.MultiplySrcOver().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount));
new DefaultPixelBlenders<TPixel>.MultiplySrcOver().Blend(this.Configuration, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount));
VectorAssert.Equal(expected, dest[0], 2);
}
@ -128,7 +128,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders
where TPixel : struct, IPixel<TPixel>
{
var dest = new Span<TPixel>(new TPixel[1]);
new DefaultPixelBlenders<TPixel>.AddSrcOver().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount));
new DefaultPixelBlenders<TPixel>.AddSrcOver().Blend(this.Configuration, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount));
VectorAssert.Equal(expected, dest[0], 2);
}
@ -167,7 +167,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders
where TPixel : struct, IPixel<TPixel>
{
var dest = new Span<TPixel>(new TPixel[1]);
new DefaultPixelBlenders<TPixel>.SubtractSrcOver().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount));
new DefaultPixelBlenders<TPixel>.SubtractSrcOver().Blend(this.Configuration, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount));
VectorAssert.Equal(expected, dest[0], 2);
}
@ -206,7 +206,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders
where TPixel : struct, IPixel<TPixel>
{
var dest = new Span<TPixel>(new TPixel[1]);
new DefaultPixelBlenders<TPixel>.ScreenSrcOver().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount));
new DefaultPixelBlenders<TPixel>.ScreenSrcOver().Blend(this.Configuration, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount));
VectorAssert.Equal(expected, dest[0], 2);
}
@ -245,7 +245,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders
where TPixel : struct, IPixel<TPixel>
{
var dest = new Span<TPixel>(new TPixel[1]);
new DefaultPixelBlenders<TPixel>.DarkenSrcOver().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount));
new DefaultPixelBlenders<TPixel>.DarkenSrcOver().Blend(this.Configuration, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount));
VectorAssert.Equal(expected, dest[0], 2);
}
@ -284,7 +284,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders
where TPixel : struct, IPixel<TPixel>
{
var dest = new Span<TPixel>(new TPixel[1]);
new DefaultPixelBlenders<TPixel>.LightenSrcOver().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount));
new DefaultPixelBlenders<TPixel>.LightenSrcOver().Blend(this.Configuration, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount));
VectorAssert.Equal(expected, dest[0], 2);
}
@ -323,7 +323,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders
where TPixel : struct, IPixel<TPixel>
{
var dest = new Span<TPixel>(new TPixel[1]);
new DefaultPixelBlenders<TPixel>.OverlaySrcOver().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount));
new DefaultPixelBlenders<TPixel>.OverlaySrcOver().Blend(this.Configuration, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount));
VectorAssert.Equal(expected, dest[0], 2);
}
@ -362,7 +362,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelBlenders
where TPixel : struct, IPixel<TPixel>
{
var dest = new Span<TPixel>(new TPixel[1]);
new DefaultPixelBlenders<TPixel>.HardLightSrcOver().Blend(this.MemoryAllocator, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount));
new DefaultPixelBlenders<TPixel>.HardLightSrcOver().Blend(this.Configuration, dest, back.AsSpan(), source.AsSpan(), AsSpan(amount));
VectorAssert.Equal(expected, dest[0], 2);
}
}

15
tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs

@ -269,7 +269,10 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats
{
this.Measure(
times,
() => PixelOperations<Rgba32>.Instance.ToVector4(source.GetSpan(), dest.GetSpan()));
() => PixelOperations<Rgba32>.Instance.ToVector4(
this.Configuration,
source.GetSpan(),
dest.GetSpan()));
}
}
}
@ -333,6 +336,8 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats
public static TheoryData<int> ArraySizesData => new TheoryData<int> { 0, 1, 2, 7, 16, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 1111 };
protected Configuration Configuration => Configuration.Default;
internal static PixelOperations<TPixel> Operations => PixelOperations<TPixel>.Instance;
internal static TPixel[] CreateExpectedPixelData(Vector4[] source)
@ -367,7 +372,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats
TestOperation(
source,
expected,
(s, d) => Operations.FromVector4(s, d.GetSpan())
(s, d) => Operations.FromVector4(this.Configuration, s, d.GetSpan())
);
}
@ -381,7 +386,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats
TestOperation(
source,
expected,
(s, d) => Operations.FromScaledVector4(s, d.GetSpan())
(s, d) => Operations.FromScaledVector4(this.Configuration, s, d.GetSpan())
);
}
@ -417,7 +422,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats
TestOperation(
source,
expected,
(s, d) => Operations.ToVector4(s, d.GetSpan())
(s, d) => Operations.ToVector4(this.Configuration, s, d.GetSpan())
);
}
@ -431,7 +436,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats
TestOperation(
source,
expected,
(s, d) => Operations.ToScaledVector4(s, d.GetSpan())
(s, d) => Operations.ToScaledVector4(this.Configuration, s, d.GetSpan())
);
}

25
tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs

@ -10,6 +10,8 @@ namespace SixLabors.ImageSharp.Tests
{
public class QuantizedImageTests
{
private Configuration Configuration => Configuration.Default;
[Fact]
public void QuantizersDitherByDefault()
{
@ -21,15 +23,17 @@ namespace SixLabors.ImageSharp.Tests
Assert.NotNull(octree.Diffuser);
Assert.NotNull(wu.Diffuser);
Assert.True(palette.CreateFrameQuantizer<Rgba32>().Dither);
Assert.True(octree.CreateFrameQuantizer<Rgba32>().Dither);
Assert.True(wu.CreateFrameQuantizer<Rgba32>().Dither);
Assert.True(palette.CreateFrameQuantizer<Rgba32>(this.Configuration).Dither);
Assert.True(octree.CreateFrameQuantizer<Rgba32>(this.Configuration).Dither);
Assert.True(wu.CreateFrameQuantizer<Rgba32>(this.Configuration).Dither);
}
[Theory]
[WithFile(TestImages.Gif.Giphy, PixelTypes.Rgba32, true)]
[WithFile(TestImages.Gif.Giphy, PixelTypes.Rgba32, false)]
public void PaletteQuantizerYieldsCorrectTransparentPixel<TPixel>(TestImageProvider<TPixel> provider, bool dither)
public void PaletteQuantizerYieldsCorrectTransparentPixel<TPixel>(
TestImageProvider<TPixel> provider,
bool dither)
where TPixel : struct, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage())
@ -40,7 +44,8 @@ namespace SixLabors.ImageSharp.Tests
foreach (ImageFrame<TPixel> frame in image.Frames)
{
QuantizedFrame<TPixel> quantized = quantizer.CreateFrameQuantizer<TPixel>().QuantizeFrame(frame);
QuantizedFrame<TPixel> quantized =
quantizer.CreateFrameQuantizer<TPixel>(this.Configuration).QuantizeFrame(frame);
int index = this.GetTransparentIndex(quantized);
Assert.Equal(index, quantized.GetPixelSpan()[0]);
@ -51,7 +56,9 @@ namespace SixLabors.ImageSharp.Tests
[Theory]
[WithFile(TestImages.Gif.Giphy, PixelTypes.Rgba32, true)]
[WithFile(TestImages.Gif.Giphy, PixelTypes.Rgba32, false)]
public void OctreeQuantizerYieldsCorrectTransparentPixel<TPixel>(TestImageProvider<TPixel> provider, bool dither)
public void OctreeQuantizerYieldsCorrectTransparentPixel<TPixel>(
TestImageProvider<TPixel> provider,
bool dither)
where TPixel : struct, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage())
@ -62,7 +69,8 @@ namespace SixLabors.ImageSharp.Tests
foreach (ImageFrame<TPixel> frame in image.Frames)
{
QuantizedFrame<TPixel> quantized = quantizer.CreateFrameQuantizer<TPixel>().QuantizeFrame(frame);
QuantizedFrame<TPixel> quantized =
quantizer.CreateFrameQuantizer<TPixel>(this.Configuration).QuantizeFrame(frame);
int index = this.GetTransparentIndex(quantized);
Assert.Equal(index, quantized.GetPixelSpan()[0]);
@ -84,7 +92,8 @@ namespace SixLabors.ImageSharp.Tests
foreach (ImageFrame<TPixel> frame in image.Frames)
{
QuantizedFrame<TPixel> quantized = quantizer.CreateFrameQuantizer<TPixel>().QuantizeFrame(frame);
QuantizedFrame<TPixel> quantized =
quantizer.CreateFrameQuantizer<TPixel>(this.Configuration).QuantizeFrame(frame);
int index = this.GetTransparentIndex(quantized);
Assert.Equal(index, quantized.GetPixelSpan()[0]);

36
tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs

@ -30,27 +30,29 @@ namespace SixLabors.ImageSharp.Tests
{
MemoryAllocator memoryAllocator = ctx.MemoryAllocator;
ctx.Apply(img =>
{
using (Buffer2D<Vector4> temp = memoryAllocator.Allocate2D<Vector4>(img.Width, img.Height))
{
Span<Vector4> tempSpan = temp.GetSpan();
foreach (ImageFrame<TPixel> frame in img.Frames)
ctx.Apply(
img =>
{
Span<TPixel> pixelSpan = frame.GetPixelSpan();
Configuration configuration = img.GetConfiguration();
using (Buffer2D<Vector4> temp = memoryAllocator.Allocate2D<Vector4>(img.Width, img.Height))
{
Span<Vector4> tempSpan = temp.GetSpan();
foreach (ImageFrame<TPixel> frame in img.Frames)
{
Span<TPixel> pixelSpan = frame.GetPixelSpan();
PixelOperations<TPixel>.Instance.ToScaledVector4(pixelSpan, tempSpan);
PixelOperations<TPixel>.Instance.ToScaledVector4(configuration, pixelSpan, tempSpan);
for (int i = 0; i < tempSpan.Length; i++)
{
ref Vector4 v = ref tempSpan[i];
v.W = 1F;
}
for (int i = 0; i < tempSpan.Length; i++)
{
ref Vector4 v = ref tempSpan[i];
v.W = 1F;
}
PixelOperations<TPixel>.Instance.FromScaledVector4(tempSpan, pixelSpan);
}
}
});
PixelOperations<TPixel>.Instance.FromScaledVector4(configuration, tempSpan, pixelSpan);
}
}
});
}
public static Image<TPixel> DebugSave<TPixel>(

Loading…
Cancel
Save