Browse Source

Merge pull request #751 from SixLabors/af/extend-bulk-conversion

Introduce optimized conversion methods for RGBA-like types
pull/760/head
James Jackson-South 7 years ago
committed by GitHub
parent
commit
fc4da81123
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  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. 12
      src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
  8. 17
      src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
  9. 35
      src/ImageSharp/Formats/Gif/GifEncoderCore.cs
  10. 10
      src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegImagePostProcessor.cs
  11. 6
      src/ImageSharp/Formats/Jpeg/Components/Encoder/YCbCrForwardConverter{TPixel}.cs
  12. 2
      src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
  13. 2
      src/ImageSharp/Formats/Png/PngDecoderCore.cs
  14. 49
      src/ImageSharp/Formats/Png/PngEncoderCore.cs
  15. 8
      src/ImageSharp/Formats/Png/PngScanlineProcessor.cs
  16. 20
      src/ImageSharp/ImageFrame{TPixel}.cs
  17. 6
      src/ImageSharp/PixelFormats/NamedColors{TPixel}.cs
  18. 81
      src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs
  19. 22
      src/ImageSharp/PixelFormats/PixelExtensions.cs
  20. 126
      src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs
  21. 58
      src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs
  22. 126
      src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs
  23. 33
      src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs
  24. 33
      src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs
  25. 58
      src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs
  26. 33
      src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs
  27. 91
      src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs
  28. 33
      src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs
  29. 107
      src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude
  30. 2
      src/ImageSharp/PixelFormats/PixelImplementations/Gray8.cs
  31. 34
      src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.PixelOperations.cs
  32. 13
      src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.PixelOperations.cs
  33. 180
      src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs
  34. 20
      src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt
  35. 104
      src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs
  36. 108
      src/ImageSharp/PixelFormats/Utils/PixelConverter.cs
  37. 89
      src/ImageSharp/PixelFormats/Utils/Vector4Converters.Default.cs
  38. 154
      src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs
  39. 4
      src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs
  40. 4
      src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs
  41. 4
      src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs
  42. 19
      src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessorBase.cs
  43. 2
      src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor.cs
  44. 2
      src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs
  45. 2
      src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs
  46. 2
      src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerBase{TPixel}.cs
  47. 6
      src/ImageSharp/Processing/Processors/Quantization/IQuantizer.cs
  48. 5
      src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs
  49. 5
      src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs
  50. 15
      src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs
  51. 2
      src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor.cs
  52. 2
      src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs
  53. 5
      src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs
  54. 4
      src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs
  55. 39
      tests/ImageSharp.Benchmarks/Color/Bulk/FromRgba32Bytes.cs
  56. 10
      tests/ImageSharp.Benchmarks/Color/Bulk/FromVector4.cs
  57. 60
      tests/ImageSharp.Benchmarks/Color/Bulk/Rgb24Bytes.cs
  58. 37
      tests/ImageSharp.Benchmarks/Color/Bulk/ToRgba32Bytes.cs
  59. 176
      tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs
  60. 41
      tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Bgra32.cs
  61. 164
      tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Rgba32.cs
  62. 47
      tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs
  63. 145
      tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs
  64. 176
      tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Argb32.cs
  65. 392
      tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Bgra32.cs
  66. 62
      tests/ImageSharp.Benchmarks/General/PixelConversion/TestArgb.cs
  67. 14
      tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs
  68. 8
      tests/ImageSharp.Benchmarks/PixelBlenders/PorterDuffBulkVsPixel.cs
  69. 2
      tests/ImageSharp.Sandbox46/Program.cs
  70. 1
      tests/ImageSharp.Tests/ConfigurationTests.cs
  71. 4
      tests/ImageSharp.Tests/Drawing/FillLinearGradientBrushTests.cs
  72. 4
      tests/ImageSharp.Tests/Formats/Jpg/JpegImagePostProcessorTests.cs
  73. 21
      tests/ImageSharp.Tests/GraphicsOptionsTests.cs
  74. 3
      tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs
  75. 3
      tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs
  76. 5
      tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs
  77. 20
      tests/ImageSharp.Tests/PixelFormats/PixelBlenders/PorterDuffFunctionsTests_TPixel.cs
  78. 160
      tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.cs
  79. 25
      tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Argb32OperationsTests.cs
  80. 24
      tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgr24OperationsTests.cs
  81. 24
      tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgra32OperationsTests.cs
  82. 114
      tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Gray16OperationsTests.cs
  83. 114
      tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Gray8OperationsTests.cs
  84. 24
      tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgb48OperationsTests.cs
  85. 46
      tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgba32OperationsTests.cs
  86. 24
      tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgba64OperationsTests.cs
  87. 24
      tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.RgbaVectorOperationsTests.cs
  88. 429
      tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs
  89. 3
      tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs
  90. 3
      tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs
  91. 3
      tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs
  92. 1
      tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs
  93. 2
      tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs
  94. 4
      tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs
  95. 12
      tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs
  96. 6
      tests/ImageSharp.Tests/PixelFormats/UnPackedPixelTests.cs
  97. 28
      tests/ImageSharp.Tests/Quantization/QuantizedImageTests.cs
  98. 5
      tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs
  99. 5
      tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs
  100. 12
      tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.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);
}
}
}

12
src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs

@ -436,7 +436,11 @@ namespace SixLabors.ImageSharp.Formats.Bmp
this.stream.Read(row);
int newY = Invert(y, height, inverted);
Span<TPixel> pixelSpan = pixels.GetRowSpan(newY);
PixelOperations<TPixel>.Instance.FromBgr24Bytes(row.GetSpan(), pixelSpan, width);
PixelOperations<TPixel>.Instance.FromBgr24Bytes(
this.configuration,
row.GetSpan(),
pixelSpan,
width);
}
}
}
@ -461,7 +465,11 @@ namespace SixLabors.ImageSharp.Formats.Bmp
this.stream.Read(row);
int newY = Invert(y, height, inverted);
Span<TPixel> pixelSpan = pixels.GetRowSpan(newY);
PixelOperations<TPixel>.Instance.FromBgra32Bytes(row.GetSpan(), pixelSpan, width);
PixelOperations<TPixel>.Instance.FromBgra32Bytes(
this.configuration,
row.GetSpan(),
pixelSpan,
width);
}
}
}

17
src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs

@ -3,6 +3,8 @@
using System;
using System.IO;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Common.Helpers;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.MetaData;
@ -23,6 +25,8 @@ namespace SixLabors.ImageSharp.Formats.Bmp
private readonly MemoryAllocator memoryAllocator;
private Configuration configuration;
private BmpBitsPerPixel? bitsPerPixel;
/// <summary>
@ -48,6 +52,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
Guard.NotNull(image, nameof(image));
Guard.NotNull(stream, nameof(stream));
this.configuration = image.GetConfiguration();
ImageMetaData metaData = image.MetaData;
BmpMetaData bmpMetaData = metaData.GetFormatMetaData(BmpFormat.Instance);
this.bitsPerPixel = this.bitsPerPixel ?? bmpMetaData.BitsPerPixel;
@ -163,7 +168,11 @@ namespace SixLabors.ImageSharp.Formats.Bmp
for (int y = pixels.Height - 1; y >= 0; y--)
{
Span<TPixel> pixelSpan = pixels.GetRowSpan(y);
PixelOperations<TPixel>.Instance.ToBgra32Bytes(pixelSpan, row.GetSpan(), pixelSpan.Length);
PixelOperations<TPixel>.Instance.ToBgra32Bytes(
this.configuration,
pixelSpan,
row.GetSpan(),
pixelSpan.Length);
stream.Write(row.Array, 0, row.Length());
}
}
@ -183,7 +192,11 @@ namespace SixLabors.ImageSharp.Formats.Bmp
for (int y = pixels.Height - 1; y >= 0; y--)
{
Span<TPixel> pixelSpan = pixels.GetRowSpan(y);
PixelOperations<TPixel>.Instance.ToBgr24Bytes(pixelSpan, row.GetSpan(), pixelSpan.Length);
PixelOperations<TPixel>.Instance.ToBgr24Bytes(
this.configuration,
pixelSpan,
row.GetSpan(),
pixelSpan.Length);
stream.Write(row.Array, 0, row.Length());
}
}

35
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;
@ -26,6 +27,11 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// </summary>
private readonly MemoryAllocator memoryAllocator;
/// <summary>
/// Configuration bound to the encoding operation.
/// </summary>
private Configuration configuration;
/// <summary>
/// A reusable buffer used to reduce allocations.
/// </summary>
@ -81,6 +87,8 @@ namespace SixLabors.ImageSharp.Formats.Gif
Guard.NotNull(image, nameof(image));
Guard.NotNull(stream, nameof(stream));
this.configuration = image.GetConfiguration();
ImageMetaData metaData = image.MetaData;
this.gifMetaData = metaData.GetFormatMetaData(GifFormat.Instance);
this.colorTableMode = this.colorTableMode ?? this.gifMetaData.ColorTableMode;
@ -88,7 +96,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 +159,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 +179,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);
}
}
@ -217,7 +227,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
{
Span<Rgba32> rgbaSpan = rgbaBuffer.GetSpan();
ref Rgba32 paletteRef = ref MemoryMarshal.GetReference(rgbaSpan);
PixelOperations<TPixel>.Instance.ToRgba32(quantized.Palette, rgbaSpan);
PixelOperations<TPixel>.Instance.ToRgba32(this.configuration, quantized.Palette, rgbaSpan);
for (int i = quantized.Palette.Length - 1; i >= 0; i--)
{
@ -319,7 +329,8 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// <param name="stream">The stream to write to.</param>
private void WriteComments(ImageMetaData metadata, Stream stream)
{
if (!metadata.TryGetProperty(GifConstants.Comments, out ImageProperty property) || string.IsNullOrEmpty(property.Value))
if (!metadata.TryGetProperty(GifConstants.Comments, out ImageProperty property)
|| string.IsNullOrEmpty(property.Value))
{
return;
}
@ -417,7 +428,11 @@ namespace SixLabors.ImageSharp.Formats.Gif
using (IManagedByteBuffer colorTable = this.memoryAllocator.AllocateManagedByteBuffer(colorTableLength))
{
PixelOperations<TPixel>.Instance.ToRgb24Bytes(image.Palette.AsSpan(), colorTable.GetSpan(), pixelCount);
PixelOperations<TPixel>.Instance.ToRgb24Bytes(
this.configuration,
image.Palette.AsSpan(),
colorTable.GetSpan(),
pixelCount);
stream.Write(colorTable.Array, 0, colorTableLength);
}
}

10
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);
@ -160,7 +164,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
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);
}
}
}

6
src/ImageSharp/Formats/Jpeg/Components/Encoder/YCbCrForwardConverter{TPixel}.cs

@ -53,12 +53,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
/// <summary>
/// Converts a 8x8 image area inside 'pixels' at position (x,y) placing the result members of the structure (<see cref="Y"/>, <see cref="Cb"/>, <see cref="Cr"/>)
/// </summary>
public void Convert(IPixelSource<TPixel> pixels, int x, int y)
public void Convert(ImageFrame<TPixel> frame, int x, int y)
{
this.pixelBlock.LoadAndStretchEdges(pixels, x, y);
this.pixelBlock.LoadAndStretchEdges(frame, x, y);
Span<Rgb24> rgbSpan = this.rgbBlock.AsSpanUnsafe();
PixelOperations<TPixel>.Instance.ToRgb24(this.pixelBlock.AsSpanUnsafe(), rgbSpan);
PixelOperations<TPixel>.Instance.ToRgb24(frame.Configuration, this.pixelBlock.AsSpanUnsafe(), rgbSpan);
ref float yBlockStart = ref Unsafe.As<Block8x8F, float>(ref this.Y);
ref float cbBlockStart = ref Unsafe.As<Block8x8F, float>(ref this.Cb);

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);

2
src/ImageSharp/Formats/Png/PngDecoderCore.cs

@ -702,6 +702,7 @@ namespace SixLabors.ImageSharp.Formats.Png
case PngColorType.Rgb:
PngScanlineProcessor.ProcessRgbScanline(
this.configuration,
this.header,
scanlineSpan,
rowSpan,
@ -715,6 +716,7 @@ namespace SixLabors.ImageSharp.Formats.Png
case PngColorType.RgbWithAlpha:
PngScanlineProcessor.ProcessRgbaScanline(
this.configuration,
this.header,
scanlineSpan,
rowSpan,

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

@ -43,6 +43,11 @@ namespace SixLabors.ImageSharp.Formats.Png
/// </summary>
private readonly MemoryAllocator memoryAllocator;
/// <summary>
/// The configuration instance for the decoding operation
/// </summary>
private Configuration configuration;
/// <summary>
/// The maximum block size, defaults at 64k for uncompressed blocks.
/// </summary>
@ -201,6 +206,7 @@ namespace SixLabors.ImageSharp.Formats.Png
Guard.NotNull(image, nameof(image));
Guard.NotNull(stream, nameof(stream));
this.configuration = image.GetConfiguration();
this.width = image.Width;
this.height = image.Height;
@ -237,7 +243,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);
@ -327,7 +334,7 @@ namespace SixLabors.ImageSharp.Formats.Png
{
Span<Gray16> luminanceSpan = luminanceBuffer.GetSpan();
ref Gray16 luminanceRef = ref MemoryMarshal.GetReference(luminanceSpan);
PixelOperations<TPixel>.Instance.ToGray16(rowSpan, luminanceSpan);
PixelOperations<TPixel>.Instance.ToGray16(this.configuration, rowSpan, luminanceSpan);
// Can't map directly to byte array as it's big endian.
for (int x = 0, o = 0; x < luminanceSpan.Length; x++, o += 2)
@ -342,19 +349,28 @@ namespace SixLabors.ImageSharp.Formats.Png
if (this.bitDepth == 8)
{
// 8 bit grayscale
PixelOperations<TPixel>.Instance.ToGray8Bytes(rowSpan, rawScanlineSpan, rowSpan.Length);
PixelOperations<TPixel>.Instance.ToGray8Bytes(
this.configuration,
rowSpan,
rawScanlineSpan,
rowSpan.Length);
}
else
{
// 1, 2, and 4 bit grayscale
using (IManagedByteBuffer temp = this.memoryAllocator.AllocateManagedByteBuffer(rowSpan.Length, AllocationOptions.Clean))
using (IManagedByteBuffer temp = this.memoryAllocator.AllocateManagedByteBuffer(
rowSpan.Length,
AllocationOptions.Clean))
{
int scaleFactor = 255 / (ImageMaths.GetColorCountForBitDepth(this.bitDepth) - 1);
Span<byte> tempSpan = temp.GetSpan();
ref byte tempSpanRef = ref MemoryMarshal.GetReference(tempSpan);
// We need to first create an array of luminance bytes then scale them down to the correct bit depth.
PixelOperations<TPixel>.Instance.ToGray8Bytes(rowSpan, tempSpan, rowSpan.Length);
PixelOperations<TPixel>.Instance.ToGray8Bytes(
this.configuration,
rowSpan,
tempSpan,
rowSpan.Length);
this.ScaleDownFrom8BitArray(tempSpan, rawScanlineSpan, this.bitDepth, scaleFactor);
}
}
@ -370,7 +386,7 @@ namespace SixLabors.ImageSharp.Formats.Png
{
Span<Rgba64> rgbaSpan = rgbaBuffer.GetSpan();
ref Rgba64 rgbaRef = ref MemoryMarshal.GetReference(rgbaSpan);
PixelOperations<TPixel>.Instance.ToRgba64(rowSpan, rgbaSpan);
PixelOperations<TPixel>.Instance.ToRgba64(this.configuration, rowSpan, rgbaSpan);
// Can't map directly to byte array as it's big endian.
for (int x = 0, o = 0; x < rgbaSpan.Length; x++, o += 4)
@ -390,7 +406,8 @@ namespace SixLabors.ImageSharp.Formats.Png
for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 2)
{
Unsafe.Add(ref rowSpanRef, x).ToRgba32(ref rgba);
Unsafe.Add(ref rawScanlineSpanRef, o) = ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B);
Unsafe.Add(ref rawScanlineSpanRef, o) =
ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B);
Unsafe.Add(ref rawScanlineSpanRef, o + 1) = rgba.A;
}
}
@ -412,14 +429,22 @@ namespace SixLabors.ImageSharp.Formats.Png
case 4:
{
// 8 bit Rgba
PixelOperations<TPixel>.Instance.ToRgba32Bytes(rowSpan, rawScanlineSpan, this.width);
PixelOperations<TPixel>.Instance.ToRgba32Bytes(
this.configuration,
rowSpan,
rawScanlineSpan,
this.width);
break;
}
case 3:
{
// 8 bit Rgb
PixelOperations<TPixel>.Instance.ToRgb24Bytes(rowSpan, rawScanlineSpan, this.width);
PixelOperations<TPixel>.Instance.ToRgb24Bytes(
this.configuration,
rowSpan,
rawScanlineSpan,
this.width);
break;
}
@ -430,7 +455,7 @@ namespace SixLabors.ImageSharp.Formats.Png
{
Span<Rgba64> rgbaSpan = rgbaBuffer.GetSpan();
ref Rgba64 rgbaRef = ref MemoryMarshal.GetReference(rgbaSpan);
PixelOperations<TPixel>.Instance.ToRgba64(rowSpan, rgbaSpan);
PixelOperations<TPixel>.Instance.ToRgba64(this.configuration, rowSpan, rgbaSpan);
// Can't map directly to byte array as it's big endian.
for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 8)
@ -453,7 +478,7 @@ namespace SixLabors.ImageSharp.Formats.Png
{
Span<Rgb48> rgbSpan = rgbBuffer.GetSpan();
ref Rgb48 rgbRef = ref MemoryMarshal.GetReference(rgbSpan);
PixelOperations<TPixel>.Instance.ToRgb48(rowSpan, rgbSpan);
PixelOperations<TPixel>.Instance.ToRgb48(this.configuration, rowSpan, rgbSpan);
// Can't map directly to byte array as it's big endian.
for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 6)

8
src/ImageSharp/Formats/Png/PngScanlineProcessor.cs

@ -11,6 +11,7 @@ namespace SixLabors.ImageSharp.Formats.Png
{
/// <summary>
/// Provides methods to allow the decoding of raw scanlines to image rows of different pixel formats.
/// TODO: We should make this a stateful class or struct to reduce the number of arguments on methods (most are invariant).
/// </summary>
internal static class PngScanlineProcessor
{
@ -346,6 +347,7 @@ namespace SixLabors.ImageSharp.Formats.Png
}
public static void ProcessRgbScanline<TPixel>(
Configuration configuration,
in PngHeader header,
ReadOnlySpan<byte> scanlineSpan,
Span<TPixel> rowSpan,
@ -357,7 +359,6 @@ namespace SixLabors.ImageSharp.Formats.Png
where TPixel : struct, IPixel<TPixel>
{
TPixel pixel = default;
ref byte scanlineSpanRef = ref MemoryMarshal.GetReference(scanlineSpan);
ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan);
if (!hasTrans)
@ -377,7 +378,7 @@ namespace SixLabors.ImageSharp.Formats.Png
}
else
{
PixelOperations<TPixel>.Instance.FromRgb24Bytes(scanlineSpan, rowSpan, header.Width);
PixelOperations<TPixel>.Instance.FromRgb24Bytes(configuration, scanlineSpan, rowSpan, header.Width);
}
return;
@ -500,6 +501,7 @@ namespace SixLabors.ImageSharp.Formats.Png
}
public static void ProcessRgbaScanline<TPixel>(
Configuration configuration,
in PngHeader header,
ReadOnlySpan<byte> scanlineSpan,
Span<TPixel> rowSpan,
@ -526,7 +528,7 @@ namespace SixLabors.ImageSharp.Formats.Png
}
else
{
PixelOperations<TPixel>.Instance.FromRgba32Bytes(scanlineSpan, rowSpan, header.Width);
PixelOperations<TPixel>.Instance.FromRgba32Bytes(configuration, scanlineSpan, rowSpan, header.Width);
}
}

20
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>
@ -248,13 +252,13 @@ namespace SixLabors.ImageSharp
}
/// <inheritdoc/>
public override string ToString() => $"ImageFrame<{typeof(TPixel).Name}>: {this.Width}x{this.Height}";
public override string ToString() => $"ImageFrame<{typeof(TPixel).Name}>({this.Width}x{this.Height})";
/// <summary>
/// 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.
@ -296,7 +300,7 @@ namespace SixLabors.ImageSharp
{
Span<TPixel> sourceRow = this.GetPixelRowSpan(y);
Span<TPixel2> targetRow = target.GetPixelRowSpan(y);
PixelOperations<TPixel>.Instance.To(sourceRow, targetRow);
PixelOperations<TPixel>.Instance.To(configuration, sourceRow, targetRow);
}
});

6
src/ImageSharp/PixelFormats/NamedColors{TPixel}.cs

@ -739,7 +739,11 @@ namespace SixLabors.ImageSharp.PixelFormats
var safe = new TPixel[constants.Length + 1];
Span<byte> constantsBytes = MemoryMarshal.Cast<Rgba32, byte>(constants.AsSpan());
PixelOperations<TPixel>.Instance.FromRgba32Bytes(constantsBytes, safe, constants.Length);
PixelOperations<TPixel>.Instance.FromRgba32Bytes(
Configuration.Default,
constantsBytes,
safe,
constants.Length);
return safe;
}
}

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);
}
}
}
}
}

22
src/ImageSharp/PixelFormats/PixelExtensions.cs

@ -1,22 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.PixelFormats
{
/// <summary>
/// Low-performance extension methods to help conversion syntax, suitable for testing purposes.
/// </summary>
internal static class PixelExtensions
{
/// <summary>
/// Returns the result of <see cref="IPixel.ToRgba32"/> as a new <see cref="Rgba32"/> instance.
/// </summary>
public static Rgba32 ToRgba32<TPixel>(this TPixel pixel)
where TPixel : struct, IPixel<TPixel>
{
Rgba32 result = default;
pixel.ToRgba32(ref result);
return result;
}
}
}

126
src/ImageSharp/PixelFormats/PixelImplementations/Generated/Argb32.PixelOperations.Generated.cs

@ -3,7 +3,10 @@
// <auto-generated />
using SixLabors.ImageSharp.PixelFormats.Utils;
using System;
using System.Buffers;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@ -22,127 +25,187 @@ namespace SixLabors.ImageSharp.PixelFormats
{
/// <inheritdoc />
internal override void FromArgb32(ReadOnlySpan<Argb32> source, Span<Argb32> destPixels)
internal override void FromArgb32(Configuration configuration, ReadOnlySpan<Argb32> source, Span<Argb32> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels));
source.CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToArgb32(ReadOnlySpan<Argb32> sourcePixels, Span<Argb32> destPixels)
internal override void ToArgb32(Configuration configuration, ReadOnlySpan<Argb32> sourcePixels, Span<Argb32> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
sourcePixels.CopyTo(destPixels);
}
/// <inheritdoc />
internal override void FromVector4(Configuration configuration, ReadOnlySpan<Vector4> sourceVectors, Span<Argb32> destPixels)
{
Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false);
}
/// <inheritdoc />
internal override void ToVector4(Configuration configuration, ReadOnlySpan<Argb32> sourcePixels, Span<Vector4> destVectors)
{
Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false);
}
/// <inheritdoc />
internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan<Vector4> sourceVectors, Span<Argb32> destPixels)
{
Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, true);
}
/// <inheritdoc />
internal override void ToBgr24(ReadOnlySpan<Argb32> sourcePixels, Span<Bgr24> destPixels)
internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan<Argb32> sourcePixels, Span<Vector4> destVectors)
{
Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, true);
}
/// <inheritdoc />
internal override void ToRgba32(Configuration configuration, ReadOnlySpan<Argb32> sourcePixels, Span<Rgba32> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels);
ref uint sourceRef = ref Unsafe.As<Argb32,uint>(ref MemoryMarshal.GetReference(sourcePixels));
ref uint destRef = ref Unsafe.As<Rgba32, uint>(ref MemoryMarshal.GetReference(destPixels));
for (int i = 0; i < sourcePixels.Length; i++)
{
ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgr24 dp = ref Unsafe.Add(ref destRef, i);
dp.FromArgb32(sp);
uint sp = Unsafe.Add(ref sourceRef, i);
Unsafe.Add(ref destRef, i) = PixelConverter.FromArgb32.ToRgba32(sp);
}
}
/// <inheritdoc />
internal override void ToBgra32(ReadOnlySpan<Argb32> sourcePixels, Span<Bgra32> destPixels)
internal override void FromRgba32(Configuration configuration, ReadOnlySpan<Rgba32> sourcePixels, Span<Argb32> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref uint sourceRef = ref Unsafe.As<Rgba32,uint>(ref MemoryMarshal.GetReference(sourcePixels));
ref uint destRef = ref Unsafe.As<Argb32, uint>(ref MemoryMarshal.GetReference(destPixels));
ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < sourcePixels.Length; i++)
{
uint sp = Unsafe.Add(ref sourceRef, i);
Unsafe.Add(ref destRef, i) = PixelConverter.FromRgba32.ToArgb32(sp);
}
}
/// <inheritdoc />
internal override void ToBgra32(Configuration configuration, ReadOnlySpan<Argb32> sourcePixels, Span<Bgra32> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref uint sourceRef = ref Unsafe.As<Argb32,uint>(ref MemoryMarshal.GetReference(sourcePixels));
ref uint destRef = ref Unsafe.As<Bgra32, uint>(ref MemoryMarshal.GetReference(destPixels));
for (int i = 0; i < sourcePixels.Length; i++)
{
ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgra32 dp = ref Unsafe.Add(ref destRef, i);
uint sp = Unsafe.Add(ref sourceRef, i);
Unsafe.Add(ref destRef, i) = PixelConverter.FromArgb32.ToBgra32(sp);
}
}
dp.FromArgb32(sp);
/// <inheritdoc />
internal override void FromBgra32(Configuration configuration, ReadOnlySpan<Bgra32> sourcePixels, Span<Argb32> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref uint sourceRef = ref Unsafe.As<Bgra32,uint>(ref MemoryMarshal.GetReference(sourcePixels));
ref uint destRef = ref Unsafe.As<Argb32, uint>(ref MemoryMarshal.GetReference(destPixels));
for (int i = 0; i < sourcePixels.Length; i++)
{
uint sp = Unsafe.Add(ref sourceRef, i);
Unsafe.Add(ref destRef, i) = PixelConverter.FromBgra32.ToArgb32(sp);
}
}
/// <inheritdoc />
internal override void ToGray8(ReadOnlySpan<Argb32> sourcePixels, Span<Gray8> destPixels)
internal override void ToBgr24(Configuration configuration, ReadOnlySpan<Argb32> sourcePixels, Span<Bgr24> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels);
ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < sourcePixels.Length; i++)
{
ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Gray8 dp = ref Unsafe.Add(ref destRef, i);
ref Bgr24 dp = ref Unsafe.Add(ref destRef, i);
dp.FromArgb32(sp);
}
}
/// <inheritdoc />
internal override void ToGray16(ReadOnlySpan<Argb32> sourcePixels, Span<Gray16> destPixels)
internal override void ToGray8(Configuration configuration, ReadOnlySpan<Argb32> sourcePixels, Span<Gray8> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels);
ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < sourcePixels.Length; i++)
{
ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Gray16 dp = ref Unsafe.Add(ref destRef, i);
ref Gray8 dp = ref Unsafe.Add(ref destRef, i);
dp.FromArgb32(sp);
}
}
/// <inheritdoc />
internal override void ToRgb24(ReadOnlySpan<Argb32> sourcePixels, Span<Rgb24> destPixels)
internal override void ToGray16(Configuration configuration, ReadOnlySpan<Argb32> sourcePixels, Span<Gray16> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels);
ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < sourcePixels.Length; i++)
{
ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb24 dp = ref Unsafe.Add(ref destRef, i);
ref Gray16 dp = ref Unsafe.Add(ref destRef, i);
dp.FromArgb32(sp);
}
}
/// <inheritdoc />
internal override void ToRgba32(ReadOnlySpan<Argb32> sourcePixels, Span<Rgba32> destPixels)
internal override void ToRgb24(Configuration configuration, ReadOnlySpan<Argb32> sourcePixels, Span<Rgb24> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels);
ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < sourcePixels.Length; i++)
{
ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba32 dp = ref Unsafe.Add(ref destRef, i);
ref Rgb24 dp = ref Unsafe.Add(ref destRef, i);
dp.FromArgb32(sp);
}
}
/// <inheritdoc />
internal override void ToRgb48(ReadOnlySpan<Argb32> sourcePixels, Span<Rgb48> destPixels)
internal override void ToRgb48(Configuration configuration, ReadOnlySpan<Argb32> sourcePixels, Span<Rgb48> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
@ -158,8 +221,9 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
internal override void ToRgba64(ReadOnlySpan<Argb32> sourcePixels, Span<Rgba64> destPixels)
internal override void ToRgba64(Configuration configuration, ReadOnlySpan<Argb32> sourcePixels, Span<Rgba64> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);

58
src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgr24.PixelOperations.Generated.cs

@ -3,7 +3,10 @@
// <auto-generated />
using SixLabors.ImageSharp.PixelFormats.Utils;
using System;
using System.Buffers;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@ -22,25 +25,53 @@ namespace SixLabors.ImageSharp.PixelFormats
{
/// <inheritdoc />
internal override void FromBgr24(ReadOnlySpan<Bgr24> source, Span<Bgr24> destPixels)
internal override void FromBgr24(Configuration configuration, ReadOnlySpan<Bgr24> source, Span<Bgr24> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels));
source.CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToBgr24(ReadOnlySpan<Bgr24> sourcePixels, Span<Bgr24> destPixels)
internal override void ToBgr24(Configuration configuration, ReadOnlySpan<Bgr24> sourcePixels, Span<Bgr24> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
sourcePixels.CopyTo(destPixels);
}
/// <inheritdoc />
internal override void FromVector4(Configuration configuration, ReadOnlySpan<Vector4> sourceVectors, Span<Bgr24> destPixels)
{
Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false);
}
/// <inheritdoc />
internal override void ToVector4(Configuration configuration, ReadOnlySpan<Bgr24> sourcePixels, Span<Vector4> destVectors)
{
Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false);
}
/// <inheritdoc />
internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan<Vector4> sourceVectors, Span<Bgr24> destPixels)
{
Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, true);
}
/// <inheritdoc />
internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan<Bgr24> sourcePixels, Span<Vector4> destVectors)
{
Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, true);
}
/// <inheritdoc />
internal override void ToArgb32(ReadOnlySpan<Bgr24> sourcePixels, Span<Argb32> destPixels)
internal override void ToArgb32(Configuration configuration, ReadOnlySpan<Bgr24> sourcePixels, Span<Argb32> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
@ -56,8 +87,9 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
internal override void ToBgra32(ReadOnlySpan<Bgr24> sourcePixels, Span<Bgra32> destPixels)
internal override void ToBgra32(Configuration configuration, ReadOnlySpan<Bgr24> sourcePixels, Span<Bgra32> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
@ -73,8 +105,9 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
internal override void ToGray8(ReadOnlySpan<Bgr24> sourcePixels, Span<Gray8> destPixels)
internal override void ToGray8(Configuration configuration, ReadOnlySpan<Bgr24> sourcePixels, Span<Gray8> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
@ -90,8 +123,9 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
internal override void ToGray16(ReadOnlySpan<Bgr24> sourcePixels, Span<Gray16> destPixels)
internal override void ToGray16(Configuration configuration, ReadOnlySpan<Bgr24> sourcePixels, Span<Gray16> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
@ -107,8 +141,9 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
internal override void ToRgb24(ReadOnlySpan<Bgr24> sourcePixels, Span<Rgb24> destPixels)
internal override void ToRgb24(Configuration configuration, ReadOnlySpan<Bgr24> sourcePixels, Span<Rgb24> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
@ -124,8 +159,9 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
internal override void ToRgba32(ReadOnlySpan<Bgr24> sourcePixels, Span<Rgba32> destPixels)
internal override void ToRgba32(Configuration configuration, ReadOnlySpan<Bgr24> sourcePixels, Span<Rgba32> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
@ -141,8 +177,9 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
internal override void ToRgb48(ReadOnlySpan<Bgr24> sourcePixels, Span<Rgb48> destPixels)
internal override void ToRgb48(Configuration configuration, ReadOnlySpan<Bgr24> sourcePixels, Span<Rgb48> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
@ -158,8 +195,9 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
internal override void ToRgba64(ReadOnlySpan<Bgr24> sourcePixels, Span<Rgba64> destPixels)
internal override void ToRgba64(Configuration configuration, ReadOnlySpan<Bgr24> sourcePixels, Span<Rgba64> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);

126
src/ImageSharp/PixelFormats/PixelImplementations/Generated/Bgra32.PixelOperations.Generated.cs

@ -3,7 +3,10 @@
// <auto-generated />
using SixLabors.ImageSharp.PixelFormats.Utils;
using System;
using System.Buffers;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@ -22,127 +25,187 @@ namespace SixLabors.ImageSharp.PixelFormats
{
/// <inheritdoc />
internal override void FromBgra32(ReadOnlySpan<Bgra32> source, Span<Bgra32> destPixels)
internal override void FromBgra32(Configuration configuration, ReadOnlySpan<Bgra32> source, Span<Bgra32> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels));
source.CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToBgra32(ReadOnlySpan<Bgra32> sourcePixels, Span<Bgra32> destPixels)
internal override void ToBgra32(Configuration configuration, ReadOnlySpan<Bgra32> sourcePixels, Span<Bgra32> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
sourcePixels.CopyTo(destPixels);
}
/// <inheritdoc />
internal override void FromVector4(Configuration configuration, ReadOnlySpan<Vector4> sourceVectors, Span<Bgra32> destPixels)
{
Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false);
}
/// <inheritdoc />
internal override void ToVector4(Configuration configuration, ReadOnlySpan<Bgra32> sourcePixels, Span<Vector4> destVectors)
{
Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false);
}
/// <inheritdoc />
internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan<Vector4> sourceVectors, Span<Bgra32> destPixels)
{
Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, true);
}
/// <inheritdoc />
internal override void ToArgb32(ReadOnlySpan<Bgra32> sourcePixels, Span<Argb32> destPixels)
internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan<Bgra32> sourcePixels, Span<Vector4> destVectors)
{
Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, true);
}
/// <inheritdoc />
internal override void ToRgba32(Configuration configuration, ReadOnlySpan<Bgra32> sourcePixels, Span<Rgba32> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels);
ref uint sourceRef = ref Unsafe.As<Bgra32,uint>(ref MemoryMarshal.GetReference(sourcePixels));
ref uint destRef = ref Unsafe.As<Rgba32, uint>(ref MemoryMarshal.GetReference(destPixels));
for (int i = 0; i < sourcePixels.Length; i++)
{
ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Argb32 dp = ref Unsafe.Add(ref destRef, i);
dp.FromBgra32(sp);
uint sp = Unsafe.Add(ref sourceRef, i);
Unsafe.Add(ref destRef, i) = PixelConverter.FromBgra32.ToRgba32(sp);
}
}
/// <inheritdoc />
internal override void ToBgr24(ReadOnlySpan<Bgra32> sourcePixels, Span<Bgr24> destPixels)
internal override void FromRgba32(Configuration configuration, ReadOnlySpan<Rgba32> sourcePixels, Span<Bgra32> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref uint sourceRef = ref Unsafe.As<Rgba32,uint>(ref MemoryMarshal.GetReference(sourcePixels));
ref uint destRef = ref Unsafe.As<Bgra32, uint>(ref MemoryMarshal.GetReference(destPixels));
ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < sourcePixels.Length; i++)
{
uint sp = Unsafe.Add(ref sourceRef, i);
Unsafe.Add(ref destRef, i) = PixelConverter.FromRgba32.ToBgra32(sp);
}
}
/// <inheritdoc />
internal override void ToArgb32(Configuration configuration, ReadOnlySpan<Bgra32> sourcePixels, Span<Argb32> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref uint sourceRef = ref Unsafe.As<Bgra32,uint>(ref MemoryMarshal.GetReference(sourcePixels));
ref uint destRef = ref Unsafe.As<Argb32, uint>(ref MemoryMarshal.GetReference(destPixels));
for (int i = 0; i < sourcePixels.Length; i++)
{
ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgr24 dp = ref Unsafe.Add(ref destRef, i);
uint sp = Unsafe.Add(ref sourceRef, i);
Unsafe.Add(ref destRef, i) = PixelConverter.FromBgra32.ToArgb32(sp);
}
}
dp.FromBgra32(sp);
/// <inheritdoc />
internal override void FromArgb32(Configuration configuration, ReadOnlySpan<Argb32> sourcePixels, Span<Bgra32> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref uint sourceRef = ref Unsafe.As<Argb32,uint>(ref MemoryMarshal.GetReference(sourcePixels));
ref uint destRef = ref Unsafe.As<Bgra32, uint>(ref MemoryMarshal.GetReference(destPixels));
for (int i = 0; i < sourcePixels.Length; i++)
{
uint sp = Unsafe.Add(ref sourceRef, i);
Unsafe.Add(ref destRef, i) = PixelConverter.FromArgb32.ToBgra32(sp);
}
}
/// <inheritdoc />
internal override void ToGray8(ReadOnlySpan<Bgra32> sourcePixels, Span<Gray8> destPixels)
internal override void ToBgr24(Configuration configuration, ReadOnlySpan<Bgra32> sourcePixels, Span<Bgr24> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels);
ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < sourcePixels.Length; i++)
{
ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Gray8 dp = ref Unsafe.Add(ref destRef, i);
ref Bgr24 dp = ref Unsafe.Add(ref destRef, i);
dp.FromBgra32(sp);
}
}
/// <inheritdoc />
internal override void ToGray16(ReadOnlySpan<Bgra32> sourcePixels, Span<Gray16> destPixels)
internal override void ToGray8(Configuration configuration, ReadOnlySpan<Bgra32> sourcePixels, Span<Gray8> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels);
ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < sourcePixels.Length; i++)
{
ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Gray16 dp = ref Unsafe.Add(ref destRef, i);
ref Gray8 dp = ref Unsafe.Add(ref destRef, i);
dp.FromBgra32(sp);
}
}
/// <inheritdoc />
internal override void ToRgb24(ReadOnlySpan<Bgra32> sourcePixels, Span<Rgb24> destPixels)
internal override void ToGray16(Configuration configuration, ReadOnlySpan<Bgra32> sourcePixels, Span<Gray16> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels);
ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < sourcePixels.Length; i++)
{
ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb24 dp = ref Unsafe.Add(ref destRef, i);
ref Gray16 dp = ref Unsafe.Add(ref destRef, i);
dp.FromBgra32(sp);
}
}
/// <inheritdoc />
internal override void ToRgba32(ReadOnlySpan<Bgra32> sourcePixels, Span<Rgba32> destPixels)
internal override void ToRgb24(Configuration configuration, ReadOnlySpan<Bgra32> sourcePixels, Span<Rgb24> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels);
ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < sourcePixels.Length; i++)
{
ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba32 dp = ref Unsafe.Add(ref destRef, i);
ref Rgb24 dp = ref Unsafe.Add(ref destRef, i);
dp.FromBgra32(sp);
}
}
/// <inheritdoc />
internal override void ToRgb48(ReadOnlySpan<Bgra32> sourcePixels, Span<Rgb48> destPixels)
internal override void ToRgb48(Configuration configuration, ReadOnlySpan<Bgra32> sourcePixels, Span<Rgb48> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
@ -158,8 +221,9 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
internal override void ToRgba64(ReadOnlySpan<Bgra32> sourcePixels, Span<Rgba64> destPixels)
internal override void ToRgba64(Configuration configuration, ReadOnlySpan<Bgra32> sourcePixels, Span<Rgba64> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);

33
src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray16.PixelOperations.Generated.cs

@ -3,7 +3,10 @@
// <auto-generated />
using SixLabors.ImageSharp.PixelFormats.Utils;
using System;
using System.Buffers;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@ -22,16 +25,18 @@ namespace SixLabors.ImageSharp.PixelFormats
{
/// <inheritdoc />
internal override void FromGray16(ReadOnlySpan<Gray16> source, Span<Gray16> destPixels)
internal override void FromGray16(Configuration configuration, ReadOnlySpan<Gray16> source, Span<Gray16> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels));
source.CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToGray16(ReadOnlySpan<Gray16> sourcePixels, Span<Gray16> destPixels)
internal override void ToGray16(Configuration configuration, ReadOnlySpan<Gray16> sourcePixels, Span<Gray16> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
sourcePixels.CopyTo(destPixels);
@ -39,8 +44,9 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <inheritdoc />
internal override void ToArgb32(ReadOnlySpan<Gray16> sourcePixels, Span<Argb32> destPixels)
internal override void ToArgb32(Configuration configuration, ReadOnlySpan<Gray16> sourcePixels, Span<Argb32> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
@ -56,8 +62,9 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
internal override void ToBgr24(ReadOnlySpan<Gray16> sourcePixels, Span<Bgr24> destPixels)
internal override void ToBgr24(Configuration configuration, ReadOnlySpan<Gray16> sourcePixels, Span<Bgr24> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
@ -73,8 +80,9 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
internal override void ToBgra32(ReadOnlySpan<Gray16> sourcePixels, Span<Bgra32> destPixels)
internal override void ToBgra32(Configuration configuration, ReadOnlySpan<Gray16> sourcePixels, Span<Bgra32> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
@ -90,8 +98,9 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
internal override void ToGray8(ReadOnlySpan<Gray16> sourcePixels, Span<Gray8> destPixels)
internal override void ToGray8(Configuration configuration, ReadOnlySpan<Gray16> sourcePixels, Span<Gray8> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
@ -107,8 +116,9 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
internal override void ToRgb24(ReadOnlySpan<Gray16> sourcePixels, Span<Rgb24> destPixels)
internal override void ToRgb24(Configuration configuration, ReadOnlySpan<Gray16> sourcePixels, Span<Rgb24> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
@ -124,8 +134,9 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
internal override void ToRgba32(ReadOnlySpan<Gray16> sourcePixels, Span<Rgba32> destPixels)
internal override void ToRgba32(Configuration configuration, ReadOnlySpan<Gray16> sourcePixels, Span<Rgba32> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
@ -141,8 +152,9 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
internal override void ToRgb48(ReadOnlySpan<Gray16> sourcePixels, Span<Rgb48> destPixels)
internal override void ToRgb48(Configuration configuration, ReadOnlySpan<Gray16> sourcePixels, Span<Rgb48> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
@ -158,8 +170,9 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
internal override void ToRgba64(ReadOnlySpan<Gray16> sourcePixels, Span<Rgba64> destPixels)
internal override void ToRgba64(Configuration configuration, ReadOnlySpan<Gray16> sourcePixels, Span<Rgba64> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);

33
src/ImageSharp/PixelFormats/PixelImplementations/Generated/Gray8.PixelOperations.Generated.cs

@ -3,7 +3,10 @@
// <auto-generated />
using SixLabors.ImageSharp.PixelFormats.Utils;
using System;
using System.Buffers;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@ -22,16 +25,18 @@ namespace SixLabors.ImageSharp.PixelFormats
{
/// <inheritdoc />
internal override void FromGray8(ReadOnlySpan<Gray8> source, Span<Gray8> destPixels)
internal override void FromGray8(Configuration configuration, ReadOnlySpan<Gray8> source, Span<Gray8> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels));
source.CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToGray8(ReadOnlySpan<Gray8> sourcePixels, Span<Gray8> destPixels)
internal override void ToGray8(Configuration configuration, ReadOnlySpan<Gray8> sourcePixels, Span<Gray8> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
sourcePixels.CopyTo(destPixels);
@ -39,8 +44,9 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <inheritdoc />
internal override void ToArgb32(ReadOnlySpan<Gray8> sourcePixels, Span<Argb32> destPixels)
internal override void ToArgb32(Configuration configuration, ReadOnlySpan<Gray8> sourcePixels, Span<Argb32> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
@ -56,8 +62,9 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
internal override void ToBgr24(ReadOnlySpan<Gray8> sourcePixels, Span<Bgr24> destPixels)
internal override void ToBgr24(Configuration configuration, ReadOnlySpan<Gray8> sourcePixels, Span<Bgr24> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
@ -73,8 +80,9 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
internal override void ToBgra32(ReadOnlySpan<Gray8> sourcePixels, Span<Bgra32> destPixels)
internal override void ToBgra32(Configuration configuration, ReadOnlySpan<Gray8> sourcePixels, Span<Bgra32> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
@ -90,8 +98,9 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
internal override void ToGray16(ReadOnlySpan<Gray8> sourcePixels, Span<Gray16> destPixels)
internal override void ToGray16(Configuration configuration, ReadOnlySpan<Gray8> sourcePixels, Span<Gray16> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
@ -107,8 +116,9 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
internal override void ToRgb24(ReadOnlySpan<Gray8> sourcePixels, Span<Rgb24> destPixels)
internal override void ToRgb24(Configuration configuration, ReadOnlySpan<Gray8> sourcePixels, Span<Rgb24> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
@ -124,8 +134,9 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
internal override void ToRgba32(ReadOnlySpan<Gray8> sourcePixels, Span<Rgba32> destPixels)
internal override void ToRgba32(Configuration configuration, ReadOnlySpan<Gray8> sourcePixels, Span<Rgba32> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
@ -141,8 +152,9 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
internal override void ToRgb48(ReadOnlySpan<Gray8> sourcePixels, Span<Rgb48> destPixels)
internal override void ToRgb48(Configuration configuration, ReadOnlySpan<Gray8> sourcePixels, Span<Rgb48> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
@ -158,8 +170,9 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
internal override void ToRgba64(ReadOnlySpan<Gray8> sourcePixels, Span<Rgba64> destPixels)
internal override void ToRgba64(Configuration configuration, ReadOnlySpan<Gray8> sourcePixels, Span<Rgba64> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);

58
src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb24.PixelOperations.Generated.cs

@ -3,7 +3,10 @@
// <auto-generated />
using SixLabors.ImageSharp.PixelFormats.Utils;
using System;
using System.Buffers;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@ -22,25 +25,53 @@ namespace SixLabors.ImageSharp.PixelFormats
{
/// <inheritdoc />
internal override void FromRgb24(ReadOnlySpan<Rgb24> source, Span<Rgb24> destPixels)
internal override void FromRgb24(Configuration configuration, ReadOnlySpan<Rgb24> source, Span<Rgb24> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels));
source.CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToRgb24(ReadOnlySpan<Rgb24> sourcePixels, Span<Rgb24> destPixels)
internal override void ToRgb24(Configuration configuration, ReadOnlySpan<Rgb24> sourcePixels, Span<Rgb24> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
sourcePixels.CopyTo(destPixels);
}
/// <inheritdoc />
internal override void FromVector4(Configuration configuration, ReadOnlySpan<Vector4> sourceVectors, Span<Rgb24> destPixels)
{
Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false);
}
/// <inheritdoc />
internal override void ToVector4(Configuration configuration, ReadOnlySpan<Rgb24> sourcePixels, Span<Vector4> destVectors)
{
Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false);
}
/// <inheritdoc />
internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan<Vector4> sourceVectors, Span<Rgb24> destPixels)
{
Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, true);
}
/// <inheritdoc />
internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan<Rgb24> sourcePixels, Span<Vector4> destVectors)
{
Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, true);
}
/// <inheritdoc />
internal override void ToArgb32(ReadOnlySpan<Rgb24> sourcePixels, Span<Argb32> destPixels)
internal override void ToArgb32(Configuration configuration, ReadOnlySpan<Rgb24> sourcePixels, Span<Argb32> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
@ -56,8 +87,9 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
internal override void ToBgr24(ReadOnlySpan<Rgb24> sourcePixels, Span<Bgr24> destPixels)
internal override void ToBgr24(Configuration configuration, ReadOnlySpan<Rgb24> sourcePixels, Span<Bgr24> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
@ -73,8 +105,9 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
internal override void ToBgra32(ReadOnlySpan<Rgb24> sourcePixels, Span<Bgra32> destPixels)
internal override void ToBgra32(Configuration configuration, ReadOnlySpan<Rgb24> sourcePixels, Span<Bgra32> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
@ -90,8 +123,9 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
internal override void ToGray8(ReadOnlySpan<Rgb24> sourcePixels, Span<Gray8> destPixels)
internal override void ToGray8(Configuration configuration, ReadOnlySpan<Rgb24> sourcePixels, Span<Gray8> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
@ -107,8 +141,9 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
internal override void ToGray16(ReadOnlySpan<Rgb24> sourcePixels, Span<Gray16> destPixels)
internal override void ToGray16(Configuration configuration, ReadOnlySpan<Rgb24> sourcePixels, Span<Gray16> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
@ -124,8 +159,9 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
internal override void ToRgba32(ReadOnlySpan<Rgb24> sourcePixels, Span<Rgba32> destPixels)
internal override void ToRgba32(Configuration configuration, ReadOnlySpan<Rgb24> sourcePixels, Span<Rgba32> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
@ -141,8 +177,9 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
internal override void ToRgb48(ReadOnlySpan<Rgb24> sourcePixels, Span<Rgb48> destPixels)
internal override void ToRgb48(Configuration configuration, ReadOnlySpan<Rgb24> sourcePixels, Span<Rgb48> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
@ -158,8 +195,9 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
internal override void ToRgba64(ReadOnlySpan<Rgb24> sourcePixels, Span<Rgba64> destPixels)
internal override void ToRgba64(Configuration configuration, ReadOnlySpan<Rgb24> sourcePixels, Span<Rgba64> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);

33
src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgb48.PixelOperations.Generated.cs

@ -3,7 +3,10 @@
// <auto-generated />
using SixLabors.ImageSharp.PixelFormats.Utils;
using System;
using System.Buffers;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@ -22,16 +25,18 @@ namespace SixLabors.ImageSharp.PixelFormats
{
/// <inheritdoc />
internal override void FromRgb48(ReadOnlySpan<Rgb48> source, Span<Rgb48> destPixels)
internal override void FromRgb48(Configuration configuration, ReadOnlySpan<Rgb48> source, Span<Rgb48> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels));
source.CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToRgb48(ReadOnlySpan<Rgb48> sourcePixels, Span<Rgb48> destPixels)
internal override void ToRgb48(Configuration configuration, ReadOnlySpan<Rgb48> sourcePixels, Span<Rgb48> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
sourcePixels.CopyTo(destPixels);
@ -39,8 +44,9 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <inheritdoc />
internal override void ToArgb32(ReadOnlySpan<Rgb48> sourcePixels, Span<Argb32> destPixels)
internal override void ToArgb32(Configuration configuration, ReadOnlySpan<Rgb48> sourcePixels, Span<Argb32> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
@ -56,8 +62,9 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
internal override void ToBgr24(ReadOnlySpan<Rgb48> sourcePixels, Span<Bgr24> destPixels)
internal override void ToBgr24(Configuration configuration, ReadOnlySpan<Rgb48> sourcePixels, Span<Bgr24> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
@ -73,8 +80,9 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
internal override void ToBgra32(ReadOnlySpan<Rgb48> sourcePixels, Span<Bgra32> destPixels)
internal override void ToBgra32(Configuration configuration, ReadOnlySpan<Rgb48> sourcePixels, Span<Bgra32> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
@ -90,8 +98,9 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
internal override void ToGray8(ReadOnlySpan<Rgb48> sourcePixels, Span<Gray8> destPixels)
internal override void ToGray8(Configuration configuration, ReadOnlySpan<Rgb48> sourcePixels, Span<Gray8> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
@ -107,8 +116,9 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
internal override void ToGray16(ReadOnlySpan<Rgb48> sourcePixels, Span<Gray16> destPixels)
internal override void ToGray16(Configuration configuration, ReadOnlySpan<Rgb48> sourcePixels, Span<Gray16> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
@ -124,8 +134,9 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
internal override void ToRgb24(ReadOnlySpan<Rgb48> sourcePixels, Span<Rgb24> destPixels)
internal override void ToRgb24(Configuration configuration, ReadOnlySpan<Rgb48> sourcePixels, Span<Rgb24> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
@ -141,8 +152,9 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
internal override void ToRgba32(ReadOnlySpan<Rgb48> sourcePixels, Span<Rgba32> destPixels)
internal override void ToRgba32(Configuration configuration, ReadOnlySpan<Rgb48> sourcePixels, Span<Rgba32> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
@ -158,8 +170,9 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
internal override void ToRgba64(ReadOnlySpan<Rgb48> sourcePixels, Span<Rgba64> destPixels)
internal override void ToRgba64(Configuration configuration, ReadOnlySpan<Rgb48> sourcePixels, Span<Rgba64> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);

91
src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba32.PixelOperations.Generated.cs

@ -3,7 +3,10 @@
// <auto-generated />
using SixLabors.ImageSharp.PixelFormats.Utils;
using System;
using System.Buffers;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@ -22,76 +25,108 @@ namespace SixLabors.ImageSharp.PixelFormats
{
/// <inheritdoc />
internal override void FromRgba32(ReadOnlySpan<Rgba32> source, Span<Rgba32> destPixels)
internal override void FromRgba32(Configuration configuration, ReadOnlySpan<Rgba32> source, Span<Rgba32> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels));
source.CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToRgba32(ReadOnlySpan<Rgba32> sourcePixels, Span<Rgba32> destPixels)
internal override void ToRgba32(Configuration configuration, ReadOnlySpan<Rgba32> sourcePixels, Span<Rgba32> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
sourcePixels.CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToArgb32(ReadOnlySpan<Rgba32> sourcePixels, Span<Argb32> destPixels)
/// <inheritdoc />
internal override void ToArgb32(Configuration configuration, ReadOnlySpan<Rgba32> sourcePixels, Span<Argb32> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels);
ref uint sourceRef = ref Unsafe.As<Rgba32,uint>(ref MemoryMarshal.GetReference(sourcePixels));
ref uint destRef = ref Unsafe.As<Argb32, uint>(ref MemoryMarshal.GetReference(destPixels));
for (int i = 0; i < sourcePixels.Length; i++)
{
ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Argb32 dp = ref Unsafe.Add(ref destRef, i);
dp.FromRgba32(sp);
uint sp = Unsafe.Add(ref sourceRef, i);
Unsafe.Add(ref destRef, i) = PixelConverter.FromRgba32.ToArgb32(sp);
}
}
/// <inheritdoc />
internal override void ToBgr24(ReadOnlySpan<Rgba32> sourcePixels, Span<Bgr24> destPixels)
internal override void FromArgb32(Configuration configuration, ReadOnlySpan<Argb32> sourcePixels, Span<Rgba32> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref uint sourceRef = ref Unsafe.As<Argb32,uint>(ref MemoryMarshal.GetReference(sourcePixels));
ref uint destRef = ref Unsafe.As<Rgba32, uint>(ref MemoryMarshal.GetReference(destPixels));
ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < sourcePixels.Length; i++)
{
uint sp = Unsafe.Add(ref sourceRef, i);
Unsafe.Add(ref destRef, i) = PixelConverter.FromArgb32.ToRgba32(sp);
}
}
/// <inheritdoc />
internal override void ToBgra32(Configuration configuration, ReadOnlySpan<Rgba32> sourcePixels, Span<Bgra32> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref uint sourceRef = ref Unsafe.As<Rgba32,uint>(ref MemoryMarshal.GetReference(sourcePixels));
ref uint destRef = ref Unsafe.As<Bgra32, uint>(ref MemoryMarshal.GetReference(destPixels));
for (int i = 0; i < sourcePixels.Length; i++)
{
ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgr24 dp = ref Unsafe.Add(ref destRef, i);
uint sp = Unsafe.Add(ref sourceRef, i);
Unsafe.Add(ref destRef, i) = PixelConverter.FromRgba32.ToBgra32(sp);
}
}
dp.FromRgba32(sp);
/// <inheritdoc />
internal override void FromBgra32(Configuration configuration, ReadOnlySpan<Bgra32> sourcePixels, Span<Rgba32> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref uint sourceRef = ref Unsafe.As<Bgra32,uint>(ref MemoryMarshal.GetReference(sourcePixels));
ref uint destRef = ref Unsafe.As<Rgba32, uint>(ref MemoryMarshal.GetReference(destPixels));
for (int i = 0; i < sourcePixels.Length; i++)
{
uint sp = Unsafe.Add(ref sourceRef, i);
Unsafe.Add(ref destRef, i) = PixelConverter.FromBgra32.ToRgba32(sp);
}
}
/// <inheritdoc />
internal override void ToBgra32(ReadOnlySpan<Rgba32> sourcePixels, Span<Bgra32> destPixels)
internal override void ToBgr24(Configuration configuration, ReadOnlySpan<Rgba32> sourcePixels, Span<Bgr24> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels);
ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < sourcePixels.Length; i++)
{
ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgra32 dp = ref Unsafe.Add(ref destRef, i);
ref Bgr24 dp = ref Unsafe.Add(ref destRef, i);
dp.FromRgba32(sp);
}
}
/// <inheritdoc />
internal override void ToGray8(ReadOnlySpan<Rgba32> sourcePixels, Span<Gray8> destPixels)
internal override void ToGray8(Configuration configuration, ReadOnlySpan<Rgba32> sourcePixels, Span<Gray8> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
@ -107,8 +142,9 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
internal override void ToGray16(ReadOnlySpan<Rgba32> sourcePixels, Span<Gray16> destPixels)
internal override void ToGray16(Configuration configuration, ReadOnlySpan<Rgba32> sourcePixels, Span<Gray16> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
@ -124,8 +160,9 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
internal override void ToRgb24(ReadOnlySpan<Rgba32> sourcePixels, Span<Rgb24> destPixels)
internal override void ToRgb24(Configuration configuration, ReadOnlySpan<Rgba32> sourcePixels, Span<Rgb24> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
@ -141,8 +178,9 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
internal override void ToRgb48(ReadOnlySpan<Rgba32> sourcePixels, Span<Rgb48> destPixels)
internal override void ToRgb48(Configuration configuration, ReadOnlySpan<Rgba32> sourcePixels, Span<Rgb48> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
@ -158,8 +196,9 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
internal override void ToRgba64(ReadOnlySpan<Rgba32> sourcePixels, Span<Rgba64> destPixels)
internal override void ToRgba64(Configuration configuration, ReadOnlySpan<Rgba32> sourcePixels, Span<Rgba64> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);

33
src/ImageSharp/PixelFormats/PixelImplementations/Generated/Rgba64.PixelOperations.Generated.cs

@ -3,7 +3,10 @@
// <auto-generated />
using SixLabors.ImageSharp.PixelFormats.Utils;
using System;
using System.Buffers;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@ -22,16 +25,18 @@ namespace SixLabors.ImageSharp.PixelFormats
{
/// <inheritdoc />
internal override void FromRgba64(ReadOnlySpan<Rgba64> source, Span<Rgba64> destPixels)
internal override void FromRgba64(Configuration configuration, ReadOnlySpan<Rgba64> source, Span<Rgba64> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels));
source.CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToRgba64(ReadOnlySpan<Rgba64> sourcePixels, Span<Rgba64> destPixels)
internal override void ToRgba64(Configuration configuration, ReadOnlySpan<Rgba64> sourcePixels, Span<Rgba64> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
sourcePixels.CopyTo(destPixels);
@ -39,8 +44,9 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <inheritdoc />
internal override void ToArgb32(ReadOnlySpan<Rgba64> sourcePixels, Span<Argb32> destPixels)
internal override void ToArgb32(Configuration configuration, ReadOnlySpan<Rgba64> sourcePixels, Span<Argb32> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
@ -56,8 +62,9 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
internal override void ToBgr24(ReadOnlySpan<Rgba64> sourcePixels, Span<Bgr24> destPixels)
internal override void ToBgr24(Configuration configuration, ReadOnlySpan<Rgba64> sourcePixels, Span<Bgr24> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
@ -73,8 +80,9 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
internal override void ToBgra32(ReadOnlySpan<Rgba64> sourcePixels, Span<Bgra32> destPixels)
internal override void ToBgra32(Configuration configuration, ReadOnlySpan<Rgba64> sourcePixels, Span<Bgra32> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
@ -90,8 +98,9 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
internal override void ToGray8(ReadOnlySpan<Rgba64> sourcePixels, Span<Gray8> destPixels)
internal override void ToGray8(Configuration configuration, ReadOnlySpan<Rgba64> sourcePixels, Span<Gray8> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
@ -107,8 +116,9 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
internal override void ToGray16(ReadOnlySpan<Rgba64> sourcePixels, Span<Gray16> destPixels)
internal override void ToGray16(Configuration configuration, ReadOnlySpan<Rgba64> sourcePixels, Span<Gray16> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
@ -124,8 +134,9 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
internal override void ToRgb24(ReadOnlySpan<Rgba64> sourcePixels, Span<Rgb24> destPixels)
internal override void ToRgb24(Configuration configuration, ReadOnlySpan<Rgba64> sourcePixels, Span<Rgb24> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
@ -141,8 +152,9 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
internal override void ToRgba32(ReadOnlySpan<Rgba64> sourcePixels, Span<Rgba32> destPixels)
internal override void ToRgba32(Configuration configuration, ReadOnlySpan<Rgba64> sourcePixels, Span<Rgba32> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
@ -158,8 +170,9 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
internal override void ToRgb48(ReadOnlySpan<Rgba64> sourcePixels, Span<Rgb48> destPixels)
internal override void ToRgb48(Configuration configuration, ReadOnlySpan<Rgba64> sourcePixels, Span<Rgb48> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);

107
src/ImageSharp/PixelFormats/PixelImplementations/Generated/_Common.ttinclude

@ -8,27 +8,37 @@
// <auto-generated />
using SixLabors.ImageSharp.PixelFormats.Utils;
using System;
using System.Buffers;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
<#+
static readonly string[] CommonPixelTypeNames = { "Argb32", "Bgr24", "Bgra32", "Gray8", "Gray16", "Rgb24", "Rgba32", "Rgb48", "Rgba64" };
static readonly string[] CommonPixelTypes = { "Argb32", "Bgr24", "Bgra32", "Gray8", "Gray16", "Rgb24", "Rgba32", "Rgb48", "Rgba64" };
static readonly string[] Optimized32BitTypes = { "Rgba32", "Argb32", "Bgra32" };
// Types with Rgba32-combatible to/from Vector4 conversion
static readonly string[] Rgba32CompatibleTypes = { "Argb32", "Bgra32", "Rgb24", "Bgr24" };
void GenerateDefaultSelfConversionMethods(string pixelType)
{
#>
/// <inheritdoc />
internal override void From<#=pixelType#>(ReadOnlySpan<<#=pixelType#>> source, Span<<#=pixelType#>> destPixels)
internal override void From<#=pixelType#>(Configuration configuration, ReadOnlySpan<<#=pixelType#>> source, Span<<#=pixelType#>> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels));
source.CopyTo(destPixels);
}
/// <inheritdoc />
internal override void To<#=pixelType#>(ReadOnlySpan<<#=pixelType#>> sourcePixels, Span<<#=pixelType#>> destPixels)
internal override void To<#=pixelType#>(Configuration configuration, ReadOnlySpan<<#=pixelType#>> sourcePixels, Span<<#=pixelType#>> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
sourcePixels.CopyTo(destPixels);
@ -42,8 +52,9 @@ using System.Runtime.InteropServices;
#>
/// <inheritdoc />
internal override void To<#=toPixelType#>(ReadOnlySpan<<#=fromPixelType#>> sourcePixels, Span<<#=toPixelType#>> destPixels)
internal override void To<#=toPixelType#>(Configuration configuration, ReadOnlySpan<<#=fromPixelType#>> sourcePixels, Span<<#=toPixelType#>> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref <#=fromPixelType#> sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
@ -60,13 +71,97 @@ using System.Runtime.InteropServices;
<#+
}
void GenerateOptimized32BitConversionMethods(string thisPixelType, string otherPixelType)
{
#>
/// <inheritdoc />
internal override void To<#=otherPixelType#>(Configuration configuration, ReadOnlySpan<<#=thisPixelType#>> sourcePixels, Span<<#=otherPixelType#>> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref uint sourceRef = ref Unsafe.As<<#=thisPixelType#>,uint>(ref MemoryMarshal.GetReference(sourcePixels));
ref uint destRef = ref Unsafe.As<<#=otherPixelType#>, uint>(ref MemoryMarshal.GetReference(destPixels));
for (int i = 0; i < sourcePixels.Length; i++)
{
uint sp = Unsafe.Add(ref sourceRef, i);
Unsafe.Add(ref destRef, i) = PixelConverter.From<#=thisPixelType#>.To<#=otherPixelType#>(sp);
}
}
/// <inheritdoc />
internal override void From<#=otherPixelType#>(Configuration configuration, ReadOnlySpan<<#=otherPixelType#>> sourcePixels, Span<<#=thisPixelType#>> destPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
ref uint sourceRef = ref Unsafe.As<<#=otherPixelType#>,uint>(ref MemoryMarshal.GetReference(sourcePixels));
ref uint destRef = ref Unsafe.As<<#=thisPixelType#>, uint>(ref MemoryMarshal.GetReference(destPixels));
for (int i = 0; i < sourcePixels.Length; i++)
{
uint sp = Unsafe.Add(ref sourceRef, i);
Unsafe.Add(ref destRef, i) = PixelConverter.From<#=otherPixelType#>.To<#=thisPixelType#>(sp);
}
}
<#+
}
void GenerateRgba32CompatibleVector4ConversionMethods(string pixelType)
{
#>
/// <inheritdoc />
internal override void FromVector4(Configuration configuration, ReadOnlySpan<Vector4> sourceVectors, Span<<#=pixelType#>> destPixels)
{
Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, false);
}
/// <inheritdoc />
internal override void ToVector4(Configuration configuration, ReadOnlySpan<<#=pixelType#>> sourcePixels, Span<Vector4> destVectors)
{
Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, false);
}
/// <inheritdoc />
internal override void FromScaledVector4(Configuration configuration, ReadOnlySpan<Vector4> sourceVectors, Span<<#=pixelType#>> destPixels)
{
Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destPixels, true);
}
/// <inheritdoc />
internal override void ToScaledVector4(Configuration configuration, ReadOnlySpan<<#=pixelType#>> sourcePixels, Span<Vector4> destVectors)
{
Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, true);
}
<#+
}
void GenerateAllDefaultConversionMethods(string pixelType)
{
GenerateDefaultSelfConversionMethods(pixelType);
var allOtherPixelTypes = CommonPixelTypeNames.Where(p => p != pixelType);
if (Rgba32CompatibleTypes.Contains(pixelType))
{
GenerateRgba32CompatibleVector4ConversionMethods(pixelType);
}
var matching32BitTypes = Optimized32BitTypes.Contains(pixelType) ?
Optimized32BitTypes.Where(p => p != pixelType) :
Enumerable.Empty<string>();
foreach (string destPixelType in matching32BitTypes)
{
GenerateOptimized32BitConversionMethods(pixelType, destPixelType);
}
var otherCommonNon32Types = CommonPixelTypes
.Where(p => p != pixelType)
.Except(matching32BitTypes);
foreach (string destPixelType in allOtherPixelTypes)
foreach (string destPixelType in otherCommonNon32Types)
{
GenerateDefaultConvertToMethod(pixelType, destPixelType);
}

2
src/ImageSharp/PixelFormats/PixelImplementations/Gray8.cs

@ -140,7 +140,7 @@ namespace SixLabors.ImageSharp.PixelFormats
public bool Equals(Gray8 other) => this.PackedValue.Equals(other.PackedValue);
/// <inheritdoc />
public override string ToString() => $"Gray8({this.PackedValue}";
public override string ToString() => $"Gray8({this.PackedValue})";
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]

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

@ -19,41 +19,51 @@ 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> sourcePixels,
Span<Vector4> destVectors)
{
Guard.DestinationShouldNotBeTooShort(sourceColors, destinationVectors, nameof(destinationVectors));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destVectors, nameof(destVectors));
destinationVectors = destinationVectors.Slice(0, sourceColors.Length);
destVectors = destVectors.Slice(0, sourcePixels.Length);
SimdUtils.BulkConvertByteToNormalizedFloat(
MemoryMarshal.Cast<Rgba32, byte>(sourceColors),
MemoryMarshal.Cast<Vector4, float>(destinationVectors));
MemoryMarshal.Cast<Rgba32, byte>(sourcePixels),
MemoryMarshal.Cast<Vector4, float>(destVectors));
}
/// <inheritdoc />
internal override void FromVector4(ReadOnlySpan<Vector4> sourceVectors, Span<Rgba32> destinationColors)
internal override void FromVector4(
Configuration configuration,
ReadOnlySpan<Vector4> sourceVectors,
Span<Rgba32> destPixels)
{
Guard.DestinationShouldNotBeTooShort(sourceVectors, destinationColors, nameof(destinationColors));
Guard.DestinationShouldNotBeTooShort(sourceVectors, destPixels, nameof(destPixels));
destinationColors = destinationColors.Slice(0, sourceVectors.Length);
destPixels = destPixels.Slice(0, sourceVectors.Length);
SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows(
MemoryMarshal.Cast<Vector4, float>(sourceVectors),
MemoryMarshal.Cast<Rgba32, byte>(destinationColors));
MemoryMarshal.Cast<Rgba32, byte>(destPixels));
}
/// <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);
}
}
}

13
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,16 +30,20 @@ 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> sourcePixels,
Span<Vector4> destVectors)
{
Guard.DestinationShouldNotBeTooShort(sourceColors, destinationVectors, nameof(destinationVectors));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destVectors, nameof(destVectors));
MemoryMarshal.Cast<RgbaVector, Vector4>(sourceColors).CopyTo(destinationVectors);
MemoryMarshal.Cast<RgbaVector, Vector4>(sourcePixels).CopyTo(destVectors);
}
}
}

180
src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs

@ -13,9 +13,10 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <summary>
/// Converts all pixels in 'source` span of <see cref="Argb32"/> into a span of <typeparamref name="TPixel"/>-s.
/// </summary>
/// <param name="configuration">A <see cref="Configuration"/> to configure internal operations</param>
/// <param name="source">The source <see cref="Span{T}"/> of <see cref="Argb32"/> data.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
internal virtual void FromArgb32(ReadOnlySpan<Argb32> source, Span<TPixel> destPixels)
internal virtual void FromArgb32(Configuration configuration, ReadOnlySpan<Argb32> source, Span<TPixel> destPixels)
{
Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels));
@ -32,24 +33,26 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <summary>
/// A helper for <see cref="FromArgb32(ReadOnlySpan{Argb32}, Span{TPixel})"/> that expects a byte span.
/// A helper for <see cref="FromArgb32(Configuration, ReadOnlySpan{Argb32}, Span{TPixel})"/> that expects a byte span.
/// The layout of the data in 'sourceBytes' must be compatible with <see cref="Argb32"/> layout.
/// </summary>
/// <param name="configuration">A <see cref="Configuration"/> to configure internal operations</param>
/// <param name="sourceBytes">The <see cref="ReadOnlySpan{T}"/> to the source bytes.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
/// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void FromArgb32Bytes(ReadOnlySpan<byte> sourceBytes, Span<TPixel> destPixels, int count)
internal void FromArgb32Bytes(Configuration configuration, ReadOnlySpan<byte> sourceBytes, Span<TPixel> destPixels, int count)
{
this.FromArgb32(MemoryMarshal.Cast<byte, Argb32>(sourceBytes).Slice(0, count), destPixels);
this.FromArgb32(configuration, MemoryMarshal.Cast<byte, Argb32>(sourceBytes).Slice(0, count), destPixels);
}
/// <summary>
/// Converts all pixels of the 'sourcePixels` span to a span of <see cref="Argb32"/>-s.
/// </summary>
/// <param name="configuration">A <see cref="Configuration"/> to configure internal operations</param>
/// <param name="sourcePixels">The span of source pixels</param>
/// <param name="destPixels">The destination span of <see cref="Argb32"/> data.</param>
internal virtual void ToArgb32(ReadOnlySpan<TPixel> sourcePixels, Span<Argb32> destPixels)
internal virtual void ToArgb32(Configuration configuration, ReadOnlySpan<TPixel> sourcePixels, Span<Argb32> destPixels)
{
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
@ -66,24 +69,26 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <summary>
/// A helper for <see cref="ToArgb32(ReadOnlySpan{TPixel}, Span{Argb32})"/> that expects a byte span as destination.
/// A helper for <see cref="ToArgb32(Configuration, ReadOnlySpan{TPixel}, Span{Argb32})"/> that expects a byte span as destination.
/// The layout of the data in 'destBytes' must be compatible with <see cref="Argb32"/> layout.
/// </summary>
/// <param name="configuration">A <see cref="Configuration"/> to configure internal operations</param>
/// <param name="sourcePixels">The <see cref="Span{T}"/> to the source pixels.</param>
/// <param name="destBytes">The <see cref="Span{T}"/> to the destination bytes.</param>
/// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void ToArgb32Bytes(ReadOnlySpan<TPixel> sourcePixels, Span<byte> destBytes, int count)
internal void ToArgb32Bytes(Configuration configuration, ReadOnlySpan<TPixel> sourcePixels, Span<byte> destBytes, int count)
{
this.ToArgb32(sourcePixels.Slice(0, count), MemoryMarshal.Cast<byte, Argb32>(destBytes));
this.ToArgb32(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast<byte, Argb32>(destBytes));
}
/// <summary>
/// Converts all pixels in 'source` span of <see cref="Bgr24"/> into a span of <typeparamref name="TPixel"/>-s.
/// </summary>
/// <param name="configuration">A <see cref="Configuration"/> to configure internal operations</param>
/// <param name="source">The source <see cref="Span{T}"/> of <see cref="Bgr24"/> data.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
internal virtual void FromBgr24(ReadOnlySpan<Bgr24> source, Span<TPixel> destPixels)
internal virtual void FromBgr24(Configuration configuration, ReadOnlySpan<Bgr24> source, Span<TPixel> destPixels)
{
Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels));
@ -100,24 +105,26 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <summary>
/// A helper for <see cref="FromBgr24(ReadOnlySpan{Bgr24}, Span{TPixel})"/> that expects a byte span.
/// A helper for <see cref="FromBgr24(Configuration, ReadOnlySpan{Bgr24}, Span{TPixel})"/> that expects a byte span.
/// The layout of the data in 'sourceBytes' must be compatible with <see cref="Bgr24"/> layout.
/// </summary>
/// <param name="configuration">A <see cref="Configuration"/> to configure internal operations</param>
/// <param name="sourceBytes">The <see cref="ReadOnlySpan{T}"/> to the source bytes.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
/// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void FromBgr24Bytes(ReadOnlySpan<byte> sourceBytes, Span<TPixel> destPixels, int count)
internal void FromBgr24Bytes(Configuration configuration, ReadOnlySpan<byte> sourceBytes, Span<TPixel> destPixels, int count)
{
this.FromBgr24(MemoryMarshal.Cast<byte, Bgr24>(sourceBytes).Slice(0, count), destPixels);
this.FromBgr24(configuration, MemoryMarshal.Cast<byte, Bgr24>(sourceBytes).Slice(0, count), destPixels);
}
/// <summary>
/// Converts all pixels of the 'sourcePixels` span to a span of <see cref="Bgr24"/>-s.
/// </summary>
/// <param name="configuration">A <see cref="Configuration"/> to configure internal operations</param>
/// <param name="sourcePixels">The span of source pixels</param>
/// <param name="destPixels">The destination span of <see cref="Bgr24"/> data.</param>
internal virtual void ToBgr24(ReadOnlySpan<TPixel> sourcePixels, Span<Bgr24> destPixels)
internal virtual void ToBgr24(Configuration configuration, ReadOnlySpan<TPixel> sourcePixels, Span<Bgr24> destPixels)
{
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
@ -134,24 +141,26 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <summary>
/// A helper for <see cref="ToBgr24(ReadOnlySpan{TPixel}, Span{Bgr24})"/> that expects a byte span as destination.
/// A helper for <see cref="ToBgr24(Configuration, ReadOnlySpan{TPixel}, Span{Bgr24})"/> that expects a byte span as destination.
/// The layout of the data in 'destBytes' must be compatible with <see cref="Bgr24"/> layout.
/// </summary>
/// <param name="configuration">A <see cref="Configuration"/> to configure internal operations</param>
/// <param name="sourcePixels">The <see cref="Span{T}"/> to the source pixels.</param>
/// <param name="destBytes">The <see cref="Span{T}"/> to the destination bytes.</param>
/// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void ToBgr24Bytes(ReadOnlySpan<TPixel> sourcePixels, Span<byte> destBytes, int count)
internal void ToBgr24Bytes(Configuration configuration, ReadOnlySpan<TPixel> sourcePixels, Span<byte> destBytes, int count)
{
this.ToBgr24(sourcePixels.Slice(0, count), MemoryMarshal.Cast<byte, Bgr24>(destBytes));
this.ToBgr24(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast<byte, Bgr24>(destBytes));
}
/// <summary>
/// Converts all pixels in 'source` span of <see cref="Bgra32"/> into a span of <typeparamref name="TPixel"/>-s.
/// </summary>
/// <param name="configuration">A <see cref="Configuration"/> to configure internal operations</param>
/// <param name="source">The source <see cref="Span{T}"/> of <see cref="Bgra32"/> data.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
internal virtual void FromBgra32(ReadOnlySpan<Bgra32> source, Span<TPixel> destPixels)
internal virtual void FromBgra32(Configuration configuration, ReadOnlySpan<Bgra32> source, Span<TPixel> destPixels)
{
Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels));
@ -168,24 +177,26 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <summary>
/// A helper for <see cref="FromBgra32(ReadOnlySpan{Bgra32}, Span{TPixel})"/> that expects a byte span.
/// A helper for <see cref="FromBgra32(Configuration, ReadOnlySpan{Bgra32}, Span{TPixel})"/> that expects a byte span.
/// The layout of the data in 'sourceBytes' must be compatible with <see cref="Bgra32"/> layout.
/// </summary>
/// <param name="configuration">A <see cref="Configuration"/> to configure internal operations</param>
/// <param name="sourceBytes">The <see cref="ReadOnlySpan{T}"/> to the source bytes.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
/// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void FromBgra32Bytes(ReadOnlySpan<byte> sourceBytes, Span<TPixel> destPixels, int count)
internal void FromBgra32Bytes(Configuration configuration, ReadOnlySpan<byte> sourceBytes, Span<TPixel> destPixels, int count)
{
this.FromBgra32(MemoryMarshal.Cast<byte, Bgra32>(sourceBytes).Slice(0, count), destPixels);
this.FromBgra32(configuration, MemoryMarshal.Cast<byte, Bgra32>(sourceBytes).Slice(0, count), destPixels);
}
/// <summary>
/// Converts all pixels of the 'sourcePixels` span to a span of <see cref="Bgra32"/>-s.
/// </summary>
/// <param name="configuration">A <see cref="Configuration"/> to configure internal operations</param>
/// <param name="sourcePixels">The span of source pixels</param>
/// <param name="destPixels">The destination span of <see cref="Bgra32"/> data.</param>
internal virtual void ToBgra32(ReadOnlySpan<TPixel> sourcePixels, Span<Bgra32> destPixels)
internal virtual void ToBgra32(Configuration configuration, ReadOnlySpan<TPixel> sourcePixels, Span<Bgra32> destPixels)
{
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
@ -202,24 +213,26 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <summary>
/// A helper for <see cref="ToBgra32(ReadOnlySpan{TPixel}, Span{Bgra32})"/> that expects a byte span as destination.
/// A helper for <see cref="ToBgra32(Configuration, ReadOnlySpan{TPixel}, Span{Bgra32})"/> that expects a byte span as destination.
/// The layout of the data in 'destBytes' must be compatible with <see cref="Bgra32"/> layout.
/// </summary>
/// <param name="configuration">A <see cref="Configuration"/> to configure internal operations</param>
/// <param name="sourcePixels">The <see cref="Span{T}"/> to the source pixels.</param>
/// <param name="destBytes">The <see cref="Span{T}"/> to the destination bytes.</param>
/// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void ToBgra32Bytes(ReadOnlySpan<TPixel> sourcePixels, Span<byte> destBytes, int count)
internal void ToBgra32Bytes(Configuration configuration, ReadOnlySpan<TPixel> sourcePixels, Span<byte> destBytes, int count)
{
this.ToBgra32(sourcePixels.Slice(0, count), MemoryMarshal.Cast<byte, Bgra32>(destBytes));
this.ToBgra32(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast<byte, Bgra32>(destBytes));
}
/// <summary>
/// Converts all pixels in 'source` span of <see cref="Gray8"/> into a span of <typeparamref name="TPixel"/>-s.
/// </summary>
/// <param name="configuration">A <see cref="Configuration"/> to configure internal operations</param>
/// <param name="source">The source <see cref="Span{T}"/> of <see cref="Gray8"/> data.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
internal virtual void FromGray8(ReadOnlySpan<Gray8> source, Span<TPixel> destPixels)
internal virtual void FromGray8(Configuration configuration, ReadOnlySpan<Gray8> source, Span<TPixel> destPixels)
{
Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels));
@ -236,24 +249,26 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <summary>
/// A helper for <see cref="FromGray8(ReadOnlySpan{Gray8}, Span{TPixel})"/> that expects a byte span.
/// A helper for <see cref="FromGray8(Configuration, ReadOnlySpan{Gray8}, Span{TPixel})"/> that expects a byte span.
/// The layout of the data in 'sourceBytes' must be compatible with <see cref="Gray8"/> layout.
/// </summary>
/// <param name="configuration">A <see cref="Configuration"/> to configure internal operations</param>
/// <param name="sourceBytes">The <see cref="ReadOnlySpan{T}"/> to the source bytes.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
/// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void FromGray8Bytes(ReadOnlySpan<byte> sourceBytes, Span<TPixel> destPixels, int count)
internal void FromGray8Bytes(Configuration configuration, ReadOnlySpan<byte> sourceBytes, Span<TPixel> destPixels, int count)
{
this.FromGray8(MemoryMarshal.Cast<byte, Gray8>(sourceBytes).Slice(0, count), destPixels);
this.FromGray8(configuration, MemoryMarshal.Cast<byte, Gray8>(sourceBytes).Slice(0, count), destPixels);
}
/// <summary>
/// Converts all pixels of the 'sourcePixels` span to a span of <see cref="Gray8"/>-s.
/// </summary>
/// <param name="configuration">A <see cref="Configuration"/> to configure internal operations</param>
/// <param name="sourcePixels">The span of source pixels</param>
/// <param name="destPixels">The destination span of <see cref="Gray8"/> data.</param>
internal virtual void ToGray8(ReadOnlySpan<TPixel> sourcePixels, Span<Gray8> destPixels)
internal virtual void ToGray8(Configuration configuration, ReadOnlySpan<TPixel> sourcePixels, Span<Gray8> destPixels)
{
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
@ -270,24 +285,26 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <summary>
/// A helper for <see cref="ToGray8(ReadOnlySpan{TPixel}, Span{Gray8})"/> that expects a byte span as destination.
/// A helper for <see cref="ToGray8(Configuration, ReadOnlySpan{TPixel}, Span{Gray8})"/> that expects a byte span as destination.
/// The layout of the data in 'destBytes' must be compatible with <see cref="Gray8"/> layout.
/// </summary>
/// <param name="configuration">A <see cref="Configuration"/> to configure internal operations</param>
/// <param name="sourcePixels">The <see cref="Span{T}"/> to the source pixels.</param>
/// <param name="destBytes">The <see cref="Span{T}"/> to the destination bytes.</param>
/// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void ToGray8Bytes(ReadOnlySpan<TPixel> sourcePixels, Span<byte> destBytes, int count)
internal void ToGray8Bytes(Configuration configuration, ReadOnlySpan<TPixel> sourcePixels, Span<byte> destBytes, int count)
{
this.ToGray8(sourcePixels.Slice(0, count), MemoryMarshal.Cast<byte, Gray8>(destBytes));
this.ToGray8(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast<byte, Gray8>(destBytes));
}
/// <summary>
/// Converts all pixels in 'source` span of <see cref="Gray16"/> into a span of <typeparamref name="TPixel"/>-s.
/// </summary>
/// <param name="configuration">A <see cref="Configuration"/> to configure internal operations</param>
/// <param name="source">The source <see cref="Span{T}"/> of <see cref="Gray16"/> data.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
internal virtual void FromGray16(ReadOnlySpan<Gray16> source, Span<TPixel> destPixels)
internal virtual void FromGray16(Configuration configuration, ReadOnlySpan<Gray16> source, Span<TPixel> destPixels)
{
Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels));
@ -304,24 +321,26 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <summary>
/// A helper for <see cref="FromGray16(ReadOnlySpan{Gray16}, Span{TPixel})"/> that expects a byte span.
/// A helper for <see cref="FromGray16(Configuration, ReadOnlySpan{Gray16}, Span{TPixel})"/> that expects a byte span.
/// The layout of the data in 'sourceBytes' must be compatible with <see cref="Gray16"/> layout.
/// </summary>
/// <param name="configuration">A <see cref="Configuration"/> to configure internal operations</param>
/// <param name="sourceBytes">The <see cref="ReadOnlySpan{T}"/> to the source bytes.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
/// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void FromGray16Bytes(ReadOnlySpan<byte> sourceBytes, Span<TPixel> destPixels, int count)
internal void FromGray16Bytes(Configuration configuration, ReadOnlySpan<byte> sourceBytes, Span<TPixel> destPixels, int count)
{
this.FromGray16(MemoryMarshal.Cast<byte, Gray16>(sourceBytes).Slice(0, count), destPixels);
this.FromGray16(configuration, MemoryMarshal.Cast<byte, Gray16>(sourceBytes).Slice(0, count), destPixels);
}
/// <summary>
/// Converts all pixels of the 'sourcePixels` span to a span of <see cref="Gray16"/>-s.
/// </summary>
/// <param name="configuration">A <see cref="Configuration"/> to configure internal operations</param>
/// <param name="sourcePixels">The span of source pixels</param>
/// <param name="destPixels">The destination span of <see cref="Gray16"/> data.</param>
internal virtual void ToGray16(ReadOnlySpan<TPixel> sourcePixels, Span<Gray16> destPixels)
internal virtual void ToGray16(Configuration configuration, ReadOnlySpan<TPixel> sourcePixels, Span<Gray16> destPixels)
{
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
@ -338,24 +357,26 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <summary>
/// A helper for <see cref="ToGray16(ReadOnlySpan{TPixel}, Span{Gray16})"/> that expects a byte span as destination.
/// A helper for <see cref="ToGray16(Configuration, ReadOnlySpan{TPixel}, Span{Gray16})"/> that expects a byte span as destination.
/// The layout of the data in 'destBytes' must be compatible with <see cref="Gray16"/> layout.
/// </summary>
/// <param name="configuration">A <see cref="Configuration"/> to configure internal operations</param>
/// <param name="sourcePixels">The <see cref="Span{T}"/> to the source pixels.</param>
/// <param name="destBytes">The <see cref="Span{T}"/> to the destination bytes.</param>
/// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void ToGray16Bytes(ReadOnlySpan<TPixel> sourcePixels, Span<byte> destBytes, int count)
internal void ToGray16Bytes(Configuration configuration, ReadOnlySpan<TPixel> sourcePixels, Span<byte> destBytes, int count)
{
this.ToGray16(sourcePixels.Slice(0, count), MemoryMarshal.Cast<byte, Gray16>(destBytes));
this.ToGray16(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast<byte, Gray16>(destBytes));
}
/// <summary>
/// Converts all pixels in 'source` span of <see cref="Rgb24"/> into a span of <typeparamref name="TPixel"/>-s.
/// </summary>
/// <param name="configuration">A <see cref="Configuration"/> to configure internal operations</param>
/// <param name="source">The source <see cref="Span{T}"/> of <see cref="Rgb24"/> data.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
internal virtual void FromRgb24(ReadOnlySpan<Rgb24> source, Span<TPixel> destPixels)
internal virtual void FromRgb24(Configuration configuration, ReadOnlySpan<Rgb24> source, Span<TPixel> destPixels)
{
Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels));
@ -372,24 +393,26 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <summary>
/// A helper for <see cref="FromRgb24(ReadOnlySpan{Rgb24}, Span{TPixel})"/> that expects a byte span.
/// A helper for <see cref="FromRgb24(Configuration, ReadOnlySpan{Rgb24}, Span{TPixel})"/> that expects a byte span.
/// The layout of the data in 'sourceBytes' must be compatible with <see cref="Rgb24"/> layout.
/// </summary>
/// <param name="configuration">A <see cref="Configuration"/> to configure internal operations</param>
/// <param name="sourceBytes">The <see cref="ReadOnlySpan{T}"/> to the source bytes.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
/// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void FromRgb24Bytes(ReadOnlySpan<byte> sourceBytes, Span<TPixel> destPixels, int count)
internal void FromRgb24Bytes(Configuration configuration, ReadOnlySpan<byte> sourceBytes, Span<TPixel> destPixels, int count)
{
this.FromRgb24(MemoryMarshal.Cast<byte, Rgb24>(sourceBytes).Slice(0, count), destPixels);
this.FromRgb24(configuration, MemoryMarshal.Cast<byte, Rgb24>(sourceBytes).Slice(0, count), destPixels);
}
/// <summary>
/// Converts all pixels of the 'sourcePixels` span to a span of <see cref="Rgb24"/>-s.
/// </summary>
/// <param name="configuration">A <see cref="Configuration"/> to configure internal operations</param>
/// <param name="sourcePixels">The span of source pixels</param>
/// <param name="destPixels">The destination span of <see cref="Rgb24"/> data.</param>
internal virtual void ToRgb24(ReadOnlySpan<TPixel> sourcePixels, Span<Rgb24> destPixels)
internal virtual void ToRgb24(Configuration configuration, ReadOnlySpan<TPixel> sourcePixels, Span<Rgb24> destPixels)
{
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
@ -406,24 +429,26 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <summary>
/// A helper for <see cref="ToRgb24(ReadOnlySpan{TPixel}, Span{Rgb24})"/> that expects a byte span as destination.
/// A helper for <see cref="ToRgb24(Configuration, ReadOnlySpan{TPixel}, Span{Rgb24})"/> that expects a byte span as destination.
/// The layout of the data in 'destBytes' must be compatible with <see cref="Rgb24"/> layout.
/// </summary>
/// <param name="configuration">A <see cref="Configuration"/> to configure internal operations</param>
/// <param name="sourcePixels">The <see cref="Span{T}"/> to the source pixels.</param>
/// <param name="destBytes">The <see cref="Span{T}"/> to the destination bytes.</param>
/// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void ToRgb24Bytes(ReadOnlySpan<TPixel> sourcePixels, Span<byte> destBytes, int count)
internal void ToRgb24Bytes(Configuration configuration, ReadOnlySpan<TPixel> sourcePixels, Span<byte> destBytes, int count)
{
this.ToRgb24(sourcePixels.Slice(0, count), MemoryMarshal.Cast<byte, Rgb24>(destBytes));
this.ToRgb24(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast<byte, Rgb24>(destBytes));
}
/// <summary>
/// Converts all pixels in 'source` span of <see cref="Rgba32"/> into a span of <typeparamref name="TPixel"/>-s.
/// </summary>
/// <param name="configuration">A <see cref="Configuration"/> to configure internal operations</param>
/// <param name="source">The source <see cref="Span{T}"/> of <see cref="Rgba32"/> data.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
internal virtual void FromRgba32(ReadOnlySpan<Rgba32> source, Span<TPixel> destPixels)
internal virtual void FromRgba32(Configuration configuration, ReadOnlySpan<Rgba32> source, Span<TPixel> destPixels)
{
Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels));
@ -440,24 +465,26 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <summary>
/// A helper for <see cref="FromRgba32(ReadOnlySpan{Rgba32}, Span{TPixel})"/> that expects a byte span.
/// A helper for <see cref="FromRgba32(Configuration, ReadOnlySpan{Rgba32}, Span{TPixel})"/> that expects a byte span.
/// The layout of the data in 'sourceBytes' must be compatible with <see cref="Rgba32"/> layout.
/// </summary>
/// <param name="configuration">A <see cref="Configuration"/> to configure internal operations</param>
/// <param name="sourceBytes">The <see cref="ReadOnlySpan{T}"/> to the source bytes.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
/// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void FromRgba32Bytes(ReadOnlySpan<byte> sourceBytes, Span<TPixel> destPixels, int count)
internal void FromRgba32Bytes(Configuration configuration, ReadOnlySpan<byte> sourceBytes, Span<TPixel> destPixels, int count)
{
this.FromRgba32(MemoryMarshal.Cast<byte, Rgba32>(sourceBytes).Slice(0, count), destPixels);
this.FromRgba32(configuration, MemoryMarshal.Cast<byte, Rgba32>(sourceBytes).Slice(0, count), destPixels);
}
/// <summary>
/// Converts all pixels of the 'sourcePixels` span to a span of <see cref="Rgba32"/>-s.
/// </summary>
/// <param name="configuration">A <see cref="Configuration"/> to configure internal operations</param>
/// <param name="sourcePixels">The span of source pixels</param>
/// <param name="destPixels">The destination span of <see cref="Rgba32"/> data.</param>
internal virtual void ToRgba32(ReadOnlySpan<TPixel> sourcePixels, Span<Rgba32> destPixels)
internal virtual void ToRgba32(Configuration configuration, ReadOnlySpan<TPixel> sourcePixels, Span<Rgba32> destPixels)
{
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
@ -474,24 +501,26 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <summary>
/// A helper for <see cref="ToRgba32(ReadOnlySpan{TPixel}, Span{Rgba32})"/> that expects a byte span as destination.
/// A helper for <see cref="ToRgba32(Configuration, ReadOnlySpan{TPixel}, Span{Rgba32})"/> that expects a byte span as destination.
/// The layout of the data in 'destBytes' must be compatible with <see cref="Rgba32"/> layout.
/// </summary>
/// <param name="configuration">A <see cref="Configuration"/> to configure internal operations</param>
/// <param name="sourcePixels">The <see cref="Span{T}"/> to the source pixels.</param>
/// <param name="destBytes">The <see cref="Span{T}"/> to the destination bytes.</param>
/// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void ToRgba32Bytes(ReadOnlySpan<TPixel> sourcePixels, Span<byte> destBytes, int count)
internal void ToRgba32Bytes(Configuration configuration, ReadOnlySpan<TPixel> sourcePixels, Span<byte> destBytes, int count)
{
this.ToRgba32(sourcePixels.Slice(0, count), MemoryMarshal.Cast<byte, Rgba32>(destBytes));
this.ToRgba32(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast<byte, Rgba32>(destBytes));
}
/// <summary>
/// Converts all pixels in 'source` span of <see cref="Rgb48"/> into a span of <typeparamref name="TPixel"/>-s.
/// </summary>
/// <param name="configuration">A <see cref="Configuration"/> to configure internal operations</param>
/// <param name="source">The source <see cref="Span{T}"/> of <see cref="Rgb48"/> data.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
internal virtual void FromRgb48(ReadOnlySpan<Rgb48> source, Span<TPixel> destPixels)
internal virtual void FromRgb48(Configuration configuration, ReadOnlySpan<Rgb48> source, Span<TPixel> destPixels)
{
Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels));
@ -508,24 +537,26 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <summary>
/// A helper for <see cref="FromRgb48(ReadOnlySpan{Rgb48}, Span{TPixel})"/> that expects a byte span.
/// A helper for <see cref="FromRgb48(Configuration, ReadOnlySpan{Rgb48}, Span{TPixel})"/> that expects a byte span.
/// The layout of the data in 'sourceBytes' must be compatible with <see cref="Rgb48"/> layout.
/// </summary>
/// <param name="configuration">A <see cref="Configuration"/> to configure internal operations</param>
/// <param name="sourceBytes">The <see cref="ReadOnlySpan{T}"/> to the source bytes.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
/// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void FromRgb48Bytes(ReadOnlySpan<byte> sourceBytes, Span<TPixel> destPixels, int count)
internal void FromRgb48Bytes(Configuration configuration, ReadOnlySpan<byte> sourceBytes, Span<TPixel> destPixels, int count)
{
this.FromRgb48(MemoryMarshal.Cast<byte, Rgb48>(sourceBytes).Slice(0, count), destPixels);
this.FromRgb48(configuration, MemoryMarshal.Cast<byte, Rgb48>(sourceBytes).Slice(0, count), destPixels);
}
/// <summary>
/// Converts all pixels of the 'sourcePixels` span to a span of <see cref="Rgb48"/>-s.
/// </summary>
/// <param name="configuration">A <see cref="Configuration"/> to configure internal operations</param>
/// <param name="sourcePixels">The span of source pixels</param>
/// <param name="destPixels">The destination span of <see cref="Rgb48"/> data.</param>
internal virtual void ToRgb48(ReadOnlySpan<TPixel> sourcePixels, Span<Rgb48> destPixels)
internal virtual void ToRgb48(Configuration configuration, ReadOnlySpan<TPixel> sourcePixels, Span<Rgb48> destPixels)
{
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
@ -542,24 +573,26 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <summary>
/// A helper for <see cref="ToRgb48(ReadOnlySpan{TPixel}, Span{Rgb48})"/> that expects a byte span as destination.
/// A helper for <see cref="ToRgb48(Configuration, ReadOnlySpan{TPixel}, Span{Rgb48})"/> that expects a byte span as destination.
/// The layout of the data in 'destBytes' must be compatible with <see cref="Rgb48"/> layout.
/// </summary>
/// <param name="configuration">A <see cref="Configuration"/> to configure internal operations</param>
/// <param name="sourcePixels">The <see cref="Span{T}"/> to the source pixels.</param>
/// <param name="destBytes">The <see cref="Span{T}"/> to the destination bytes.</param>
/// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void ToRgb48Bytes(ReadOnlySpan<TPixel> sourcePixels, Span<byte> destBytes, int count)
internal void ToRgb48Bytes(Configuration configuration, ReadOnlySpan<TPixel> sourcePixels, Span<byte> destBytes, int count)
{
this.ToRgb48(sourcePixels.Slice(0, count), MemoryMarshal.Cast<byte, Rgb48>(destBytes));
this.ToRgb48(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast<byte, Rgb48>(destBytes));
}
/// <summary>
/// Converts all pixels in 'source` span of <see cref="Rgba64"/> into a span of <typeparamref name="TPixel"/>-s.
/// </summary>
/// <param name="configuration">A <see cref="Configuration"/> to configure internal operations</param>
/// <param name="source">The source <see cref="Span{T}"/> of <see cref="Rgba64"/> data.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
internal virtual void FromRgba64(ReadOnlySpan<Rgba64> source, Span<TPixel> destPixels)
internal virtual void FromRgba64(Configuration configuration, ReadOnlySpan<Rgba64> source, Span<TPixel> destPixels)
{
Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels));
@ -576,24 +609,26 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <summary>
/// A helper for <see cref="FromRgba64(ReadOnlySpan{Rgba64}, Span{TPixel})"/> that expects a byte span.
/// A helper for <see cref="FromRgba64(Configuration, ReadOnlySpan{Rgba64}, Span{TPixel})"/> that expects a byte span.
/// The layout of the data in 'sourceBytes' must be compatible with <see cref="Rgba64"/> layout.
/// </summary>
/// <param name="configuration">A <see cref="Configuration"/> to configure internal operations</param>
/// <param name="sourceBytes">The <see cref="ReadOnlySpan{T}"/> to the source bytes.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
/// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void FromRgba64Bytes(ReadOnlySpan<byte> sourceBytes, Span<TPixel> destPixels, int count)
internal void FromRgba64Bytes(Configuration configuration, ReadOnlySpan<byte> sourceBytes, Span<TPixel> destPixels, int count)
{
this.FromRgba64(MemoryMarshal.Cast<byte, Rgba64>(sourceBytes).Slice(0, count), destPixels);
this.FromRgba64(configuration, MemoryMarshal.Cast<byte, Rgba64>(sourceBytes).Slice(0, count), destPixels);
}
/// <summary>
/// Converts all pixels of the 'sourcePixels` span to a span of <see cref="Rgba64"/>-s.
/// </summary>
/// <param name="configuration">A <see cref="Configuration"/> to configure internal operations</param>
/// <param name="sourcePixels">The span of source pixels</param>
/// <param name="destPixels">The destination span of <see cref="Rgba64"/> data.</param>
internal virtual void ToRgba64(ReadOnlySpan<TPixel> sourcePixels, Span<Rgba64> destPixels)
internal virtual void ToRgba64(Configuration configuration, ReadOnlySpan<TPixel> sourcePixels, Span<Rgba64> destPixels)
{
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
@ -610,16 +645,17 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <summary>
/// A helper for <see cref="ToRgba64(ReadOnlySpan{TPixel}, Span{Rgba64})"/> that expects a byte span as destination.
/// A helper for <see cref="ToRgba64(Configuration, ReadOnlySpan{TPixel}, Span{Rgba64})"/> that expects a byte span as destination.
/// The layout of the data in 'destBytes' must be compatible with <see cref="Rgba64"/> layout.
/// </summary>
/// <param name="configuration">A <see cref="Configuration"/> to configure internal operations</param>
/// <param name="sourcePixels">The <see cref="Span{T}"/> to the source pixels.</param>
/// <param name="destBytes">The <see cref="Span{T}"/> to the destination bytes.</param>
/// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void ToRgba64Bytes(ReadOnlySpan<TPixel> sourcePixels, Span<byte> destBytes, int count)
internal void ToRgba64Bytes(Configuration configuration, ReadOnlySpan<TPixel> sourcePixels, Span<byte> destBytes, int count)
{
this.ToRgba64(sourcePixels.Slice(0, count), MemoryMarshal.Cast<byte, Rgba64>(destBytes));
this.ToRgba64(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast<byte, Rgba64>(destBytes));
}
}
}

20
src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt

@ -18,9 +18,10 @@
/// <summary>
/// Converts all pixels in 'source` span of <see cref="<#=pixelType#>"/> into a span of <typeparamref name="TPixel"/>-s.
/// </summary>
/// <param name="configuration">A <see cref="Configuration"/> to configure internal operations</param>
/// <param name="source">The source <see cref="Span{T}"/> of <see cref="<#=pixelType#>"/> data.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
internal virtual void From<#=pixelType#>(ReadOnlySpan<<#=pixelType#>> source, Span<TPixel> destPixels)
internal virtual void From<#=pixelType#>(Configuration configuration, ReadOnlySpan<<#=pixelType#>> source, Span<TPixel> destPixels)
{
Guard.DestinationShouldNotBeTooShort(source, destPixels, nameof(destPixels));
@ -37,16 +38,17 @@
}
/// <summary>
/// A helper for <see cref="From<#=pixelType#>(ReadOnlySpan{<#=pixelType#>}, Span{TPixel})"/> that expects a byte span.
/// A helper for <see cref="From<#=pixelType#>(Configuration, ReadOnlySpan{<#=pixelType#>}, Span{TPixel})"/> that expects a byte span.
/// The layout of the data in 'sourceBytes' must be compatible with <see cref="<#=pixelType#>"/> layout.
/// </summary>
/// <param name="configuration">A <see cref="Configuration"/> to configure internal operations</param>
/// <param name="sourceBytes">The <see cref="ReadOnlySpan{T}"/> to the source bytes.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
/// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void From<#=pixelType#>Bytes(ReadOnlySpan<byte> sourceBytes, Span<TPixel> destPixels, int count)
internal void From<#=pixelType#>Bytes(Configuration configuration, ReadOnlySpan<byte> sourceBytes, Span<TPixel> destPixels, int count)
{
this.From<#=pixelType#>(MemoryMarshal.Cast<byte, <#=pixelType#>>(sourceBytes).Slice(0, count), destPixels);
this.From<#=pixelType#>(configuration, MemoryMarshal.Cast<byte, <#=pixelType#>>(sourceBytes).Slice(0, count), destPixels);
}
<#
@ -58,9 +60,10 @@
/// <summary>
/// Converts all pixels of the 'sourcePixels` span to a span of <see cref="<#=pixelType#>"/>-s.
/// </summary>
/// <param name="configuration">A <see cref="Configuration"/> to configure internal operations</param>
/// <param name="sourcePixels">The span of source pixels</param>
/// <param name="destPixels">The destination span of <see cref="<#=pixelType#>"/> data.</param>
internal virtual void To<#=pixelType#>(ReadOnlySpan<TPixel> sourcePixels, Span<<#=pixelType#>> destPixels)
internal virtual void To<#=pixelType#>(Configuration configuration, ReadOnlySpan<TPixel> sourcePixels, Span<<#=pixelType#>> destPixels)
{
Guard.DestinationShouldNotBeTooShort(sourcePixels, destPixels, nameof(destPixels));
@ -77,16 +80,17 @@
}
/// <summary>
/// A helper for <see cref="To<#=pixelType#>(ReadOnlySpan{TPixel}, Span{<#=pixelType#>})"/> that expects a byte span as destination.
/// A helper for <see cref="To<#=pixelType#>(Configuration, ReadOnlySpan{TPixel}, Span{<#=pixelType#>})"/> that expects a byte span as destination.
/// The layout of the data in 'destBytes' must be compatible with <see cref="<#=pixelType#>"/> layout.
/// </summary>
/// <param name="configuration">A <see cref="Configuration"/> to configure internal operations</param>
/// <param name="sourcePixels">The <see cref="Span{T}"/> to the source pixels.</param>
/// <param name="destBytes">The <see cref="Span{T}"/> to the destination bytes.</param>
/// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void To<#=pixelType#>Bytes(ReadOnlySpan<TPixel> sourcePixels, Span<byte> destBytes, int count)
internal void To<#=pixelType#>Bytes(Configuration configuration, ReadOnlySpan<TPixel> sourcePixels, Span<byte> destBytes, int count)
{
this.To<#=pixelType#>(sourcePixels.Slice(0, count), MemoryMarshal.Cast<byte, <#=pixelType#>>(destBytes));
this.To<#=pixelType#>(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast<byte, <#=pixelType#>>(destBytes));
}
<#
}

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

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@ -24,94 +25,85 @@ 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)
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination colors.</param>
internal virtual void FromVector4(
Configuration configuration,
ReadOnlySpan<Vector4> sourceVectors,
Span<TPixel> destPixels)
{
Guard.DestinationShouldNotBeTooShort(sourceVectors, destinationColors, nameof(destinationColors));
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourceVectors, destPixels, nameof(destPixels));
ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceVectors);
ref TPixel destRef = ref MemoryMarshal.GetReference(destinationColors);
for (int i = 0; i < sourceVectors.Length; i++)
{
ref Vector4 sp = ref Unsafe.Add(ref sourceRef, i);
ref TPixel dp = ref Unsafe.Add(ref destRef, i);
dp.FromVector4(sp);
}
Utils.Vector4Converters.Default.DangerousFromVector4(sourceVectors, destPixels);
}
/// <summary>
/// Bulk version of <see cref="IPixel.ToVector4()"/> converting 'sourceColors.Length' pixels into 'destinationVectors'.
/// </summary>
/// <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)
/// <param name="configuration">A <see cref="Configuration"/> to configure internal operations</param>
/// <param name="sourcePixels">The <see cref="Span{T}"/> to the source colors.</param>
/// <param name="destVectors">The <see cref="Span{T}"/> to the destination vectors.</param>
internal virtual void ToVector4(
Configuration configuration,
ReadOnlySpan<TPixel> sourcePixels,
Span<Vector4> destVectors)
{
Guard.DestinationShouldNotBeTooShort(sourceColors, destinationVectors, nameof(destinationVectors));
ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourceColors);
ref Vector4 destRef = ref MemoryMarshal.GetReference(destinationVectors);
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destVectors, nameof(destVectors));
for (int i = 0; i < sourceColors.Length; i++)
{
ref TPixel sp = ref Unsafe.Add(ref sourceRef, i);
ref Vector4 dp = ref Unsafe.Add(ref destRef, i);
dp = sp.ToVector4();
}
Utils.Vector4Converters.Default.DangerousToVector4(sourcePixels, destVectors);
}
/// <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);
ref TPixel destRef = ref MemoryMarshal.GetReference(destinationColors);
for (int i = 0; i < sourceVectors.Length; i++)
{
ref Vector4 sp = ref Unsafe.Add(ref sourceRef, i);
ref TPixel dp = ref Unsafe.Add(ref destRef, i);
dp.FromScaledVector4(sp);
}
Utils.Vector4Converters.Default.DangerousFromScaledVector4(sourceVectors, destinationColors);
}
/// <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);
ref Vector4 destRef = ref MemoryMarshal.GetReference(destinationVectors);
for (int i = 0; i < sourceColors.Length; i++)
{
ref TPixel sp = ref Unsafe.Add(ref sourceRef, i);
ref Vector4 dp = ref Unsafe.Add(ref destRef, i);
dp = sp.ToScaledVector4();
}
Utils.Vector4Converters.Default.DangerousToScaledVector4(sourceColors, destinationVectors);
}
/// <summary>
/// Converts 'sourceColors.Length' pixels from 'sourceColors' into 'destinationColors'.
/// </summary>
/// <typeparam name="TDestinationPixel">The destination pixel type.</typeparam>
/// <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="destinationColors">The <see cref="Span{T}"/> to the destination colors.</param>
internal virtual void To<TDestinationPixel>(
Configuration configuration,
ReadOnlySpan<TPixel> sourceColors,
Span<TDestinationPixel> destinationColors)
where TDestinationPixel : struct, IPixel<TDestinationPixel>
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourceColors, destinationColors, nameof(destinationColors));
int count = sourceColors.Length;
@ -156,27 +148,5 @@ namespace SixLabors.ImageSharp.PixelFormats
dp.FromScaledVector4(sp.ToScaledVector4());
}
}
/// <summary>
/// Verifies that the given 'source' and 'destination' spans are at least of 'minLength' size.
/// Throwing an <see cref="ArgumentException"/> if the condition is not met.
/// </summary>
/// <typeparam name="TSource">The source element type</typeparam>
/// <typeparam name="TDest">The destination element type</typeparam>
/// <param name="source">The source span</param>
/// <param name="sourceParamName">The source parameter name</param>
/// <param name="destination">The destination span</param>
/// <param name="destinationParamName">The destination parameter name</param>
/// <param name="minLength">The minimum length</param>
protected internal static void GuardSpans<TSource, TDest>(
ReadOnlySpan<TSource> source,
string sourceParamName,
Span<TDest> destination,
string destinationParamName,
int minLength)
{
Guard.MustBeSizedAtLeast(source, minLength, sourceParamName);
Guard.MustBeSizedAtLeast(destination, minLength, destinationParamName);
}
}
}

108
src/ImageSharp/PixelFormats/Utils/PixelConverter.cs

@ -0,0 +1,108 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System.Buffers.Binary;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.PixelFormats.Utils
{
/// <summary>
/// Contains optimized implementations for conversion between pixel formats.
/// </summary>
/// <remarks>
/// Implementations are based on ideas in:
/// https://github.com/dotnet/coreclr/blob/master/src/System.Private.CoreLib/shared/System/Buffers/Binary/Reader.cs#L84
/// The JIT can detect and optimize rotation idioms ROTL (Rotate Left)
/// and ROTR (Rotate Right) emitting efficient CPU instructions:
/// https://github.com/dotnet/coreclr/pull/1830
/// </remarks>
internal static class PixelConverter
{
public static class FromRgba32
{
/// <summary>
/// Converts a packed <see cref="Rgba32"/> to <see cref="Argb32"/>.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
public static uint ToArgb32(uint packedRgba)
{
// packedRgba = [aa bb gg rr]
// ROTL(8, packedRgba) = [bb gg rr aa]
return (packedRgba << 8) | (packedRgba >> 24);
}
/// <summary>
/// Converts a packed <see cref="Rgba32"/> to <see cref="Bgra32"/>.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
public static uint ToBgra32(uint packedRgba)
{
// packedRgba = [aa bb gg rr]
// tmp1 = [aa 00 gg 00]
// tmp2 = [00 bb 00 rr]
// tmp3=ROTL(16, tmp2) = [00 rr 00 bb]
// tmp1 + tmp3 = [aa rr gg bb]
uint tmp1 = packedRgba & 0xFF00FF00;
uint tmp2 = packedRgba & 0x00FF00FF;
uint tmp3 = (tmp2 << 16) | (tmp2 >> 16);
return tmp1 + tmp3;
}
}
public static class FromArgb32
{
/// <summary>
/// Converts a packed <see cref="Argb32"/> to <see cref="Rgba32"/>.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
public static uint ToRgba32(uint packedArgb)
{
// packedArgb = [bb gg rr aa]
// ROTR(8, packedArgb) = [aa bb gg rr]
return (packedArgb >> 8) | (packedArgb << 24);
}
/// <summary>
/// Converts a packed <see cref="Argb32"/> to <see cref="Bgra32"/>.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
public static uint ToBgra32(uint packedArgb)
{
// packedArgb = [bb gg rr aa]
// REVERSE(packedArgb) = [aa rr gg bb]
return BinaryPrimitives.ReverseEndianness(packedArgb);
}
}
public static class FromBgra32
{
/// <summary>
/// Converts a packed <see cref="Bgra32"/> to <see cref="Argb32"/>.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
public static uint ToArgb32(uint packedBgra)
{
// packedBgra = [aa rr gg bb]
// REVERSE(packedBgra) = [bb gg rr aa]
return BinaryPrimitives.ReverseEndianness(packedBgra);
}
/// <summary>
/// Converts a packed <see cref="Rgba32"/> to <see cref="Bgra32"/>.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
public static uint ToRgba32(uint packedBgra)
{
// packedRgba = [aa rr gg bb]
// tmp1 = [aa 00 gg 00]
// tmp2 = [00 rr 00 bb]
// tmp3=ROTL(16, tmp2) = [00 bb 00 rr]
// tmp1 + tmp3 = [aa bb gg rr]
uint tmp1 = packedBgra & 0xFF00FF00;
uint tmp2 = packedBgra & 0x00FF00FF;
uint tmp3 = (tmp2 << 16) | (tmp2 >> 16);
return tmp1 + tmp3;
}
}
}
}

89
src/ImageSharp/PixelFormats/Utils/Vector4Converters.Default.cs

@ -0,0 +1,89 @@
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.PixelFormats.Utils
{
/// <summary>
/// Helper class for (bulk) conversion of <see cref="Vector4"/> buffers to/from other buffer types.
/// </summary>
internal static partial class Vector4Converters
{
/// <summary>
/// Provides default implementations for batched to/from <see cref="Vector4"/> conversion.
/// WARNING: The methods are operating without bounds checking and input validation!
/// Input validation is the responsibility of the caller!
/// </summary>
public static class Default
{
[MethodImpl(InliningOptions.ShortMethod)]
internal static void DangerousFromVector4<TPixel>(
ReadOnlySpan<Vector4> sourceVectors,
Span<TPixel> destPixels)
where TPixel : struct, IPixel<TPixel>
{
ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceVectors);
ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < sourceVectors.Length; i++)
{
ref Vector4 sp = ref Unsafe.Add(ref sourceRef, i);
ref TPixel dp = ref Unsafe.Add(ref destRef, i);
dp.FromVector4(sp);
}
}
[MethodImpl(InliningOptions.ShortMethod)]
internal static void DangerousToVector4<TPixel>(
ReadOnlySpan<TPixel> sourcePixels,
Span<Vector4> destVectors)
where TPixel : struct, IPixel<TPixel>
{
ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Vector4 destRef = ref MemoryMarshal.GetReference(destVectors);
for (int i = 0; i < sourcePixels.Length; i++)
{
ref TPixel sp = ref Unsafe.Add(ref sourceRef, i);
ref Vector4 dp = ref Unsafe.Add(ref destRef, i);
dp = sp.ToVector4();
}
}
[MethodImpl(InliningOptions.ShortMethod)]
internal static void DangerousFromScaledVector4<TPixel>(
ReadOnlySpan<Vector4> sourceVectors,
Span<TPixel> destinationColors)
where TPixel : struct, IPixel<TPixel>
{
ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceVectors);
ref TPixel destRef = ref MemoryMarshal.GetReference(destinationColors);
for (int i = 0; i < sourceVectors.Length; i++)
{
ref Vector4 sp = ref Unsafe.Add(ref sourceRef, i);
ref TPixel dp = ref Unsafe.Add(ref destRef, i);
dp.FromScaledVector4(sp);
}
}
[MethodImpl(InliningOptions.ShortMethod)]
internal static void DangerousToScaledVector4<TPixel>(
ReadOnlySpan<TPixel> sourceColors,
Span<Vector4> destinationVectors)
where TPixel : struct, IPixel<TPixel>
{
ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourceColors);
ref Vector4 destRef = ref MemoryMarshal.GetReference(destinationVectors);
for (int i = 0; i < sourceColors.Length; i++)
{
ref TPixel sp = ref Unsafe.Add(ref sourceRef, i);
ref Vector4 dp = ref Unsafe.Add(ref destRef, i);
dp = sp.ToScaledVector4();
}
}
}
}
}

154
src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs

@ -0,0 +1,154 @@
using System;
using System.Buffers;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.PixelFormats.Utils
{
/// <content>
/// Contains <see cref="RgbaCompatible"/>
/// </content>
internal static partial class Vector4Converters
{
/// <summary>
/// Provides efficient implementations for batched to/from <see cref="Vector4"/> conversion.
/// which is applicable for <see cref="Rgba32"/>-compatible pixel types where <see cref="IPixel.ToVector4"/>
/// returns the same scaled result as <see cref="IPixel.ToScaledVector4"/>.
/// The method is works by internally converting to a <see cref="Rgba32"/> therefore it's not applicable for that type!
/// </summary>
public static class RgbaCompatible
{
/// <summary>
/// It's not worth to bother the transitive pixel conversion method below this limit.
/// The value depends on the actual gain brought by the SIMD characteristics of the executing CPU and JIT.
/// </summary>
private static readonly int Vector4ConversionThreshold = CalculateVector4ConversionThreshold();
/// <summary>
/// Provides an efficient default implementation for <see cref="PixelOperations{TPixel}.ToVector4"/>
/// and <see cref="PixelOperations{TPixel}.ToScaledVector4"/>
/// which is applicable for <see cref="Rgba32"/>-compatible pixel types where <see cref="IPixel.ToVector4"/>
/// returns the same scaled result as <see cref="IPixel.ToScaledVector4"/>.
/// The method is works by internally converting to a <see cref="Rgba32"/> therefore it's not applicable for that type!
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
internal static void ToVector4<TPixel>(
Configuration configuration,
PixelOperations<TPixel> pixelOperations,
ReadOnlySpan<TPixel> sourcePixels,
Span<Vector4> destVectors,
bool scaled)
where TPixel : struct, IPixel<TPixel>
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destVectors, nameof(destVectors));
int count = sourcePixels.Length;
// Not worth for small buffers:
if (count < Vector4ConversionThreshold)
{
ToVector4Fallback(sourcePixels, destVectors, scaled);
return;
}
// Using the last quarter of 'destVectors' as a temporary buffer to avoid allocation:
int countWithoutLastItem = count - 1;
ReadOnlySpan<TPixel> reducedSource = sourcePixels.Slice(0, countWithoutLastItem);
Span<Rgba32> lastQuarterOfDestBuffer = MemoryMarshal.Cast<Vector4, Rgba32>(destVectors).Slice((3 * count) + 1, countWithoutLastItem);
pixelOperations.ToRgba32(configuration, reducedSource, lastQuarterOfDestBuffer);
// 'destVectors' and 'lastQuarterOfDestBuffer' are ovelapping buffers,
// but we are always reading/writing at different positions:
SimdUtils.BulkConvertByteToNormalizedFloat(
MemoryMarshal.Cast<Rgba32, byte>(lastQuarterOfDestBuffer),
MemoryMarshal.Cast<Vector4, float>(destVectors.Slice(0, countWithoutLastItem)));
destVectors[countWithoutLastItem] = sourcePixels[countWithoutLastItem].ToVector4();
}
/// <summary>
/// Provides an efficient default implementation for <see cref="PixelOperations{TPixel}.FromVector4"/>
/// and <see cref="PixelOperations{TPixel}.FromScaledVector4"/>
/// which is applicable for <see cref="Rgba32"/>-compatible pixel types where <see cref="IPixel.ToVector4"/>
/// returns the same scaled result as <see cref="IPixel.ToScaledVector4"/>.
/// The method is works by internally converting to a <see cref="Rgba32"/> therefore it's not applicable for that type!
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
internal static void FromVector4<TPixel>(
Configuration configuration,
PixelOperations<TPixel> pixelOperations,
ReadOnlySpan<Vector4> sourceVectors,
Span<TPixel> destPixels,
bool scaled)
where TPixel : struct, IPixel<TPixel>
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourceVectors, destPixels, nameof(destPixels));
int count = sourceVectors.Length;
// Not worth for small buffers:
if (count < Vector4ConversionThreshold)
{
FromVector4Fallback(sourceVectors, destPixels, scaled);
return;
}
// For the opposite direction it's not easy to implement the trick used in RunRgba32CompatibleToVector4Conversion,
// so let's allocate a temporary buffer as usually:
using (IMemoryOwner<Rgba32> tempBuffer = configuration.MemoryAllocator.Allocate<Rgba32>(count))
{
Span<Rgba32> tempSpan = tempBuffer.Memory.Span;
SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows(
MemoryMarshal.Cast<Vector4, float>(sourceVectors),
MemoryMarshal.Cast<Rgba32, byte>(tempSpan));
pixelOperations.FromRgba32(configuration, tempSpan, destPixels);
}
}
[MethodImpl(InliningOptions.ColdPath)]
private static void ToVector4Fallback<TPixel>(ReadOnlySpan<TPixel> sourcePixels, Span<Vector4> destVectors, bool scaled)
where TPixel : struct, IPixel<TPixel>
{
if (scaled)
{
Default.DangerousToScaledVector4(sourcePixels, destVectors);
}
else
{
Default.DangerousToVector4(sourcePixels, destVectors);
}
}
[MethodImpl(InliningOptions.ColdPath)]
private static void FromVector4Fallback<TPixel>(ReadOnlySpan<Vector4> sourceVectors, Span<TPixel> destPixels, bool scaled)
where TPixel : struct, IPixel<TPixel>
{
if (scaled)
{
Default.DangerousFromScaledVector4(sourceVectors, destPixels);
}
else
{
Default.DangerousFromVector4(sourceVectors, destPixels);
}
}
private static int CalculateVector4ConversionThreshold()
{
if (!Vector.IsHardwareAccelerated)
{
return int.MaxValue;
}
return SimdUtils.ExtendedIntrinsics.IsAvailable && SimdUtils.IsAvx2CompatibleArchitecture ? 256 : 128;
}
}
}
}

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(),

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

@ -79,7 +79,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;

2
src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs

@ -448,7 +448,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
{
Span<TPixel> row = source.GetPixelRowSpan(y);
Span<Rgba32> rgbaSpan = rgbaBuffer.GetSpan();
PixelOperations<TPixel>.Instance.ToRgba32(row, rgbaSpan);
PixelOperations<TPixel>.Instance.ToRgba32(source.Configuration, row, rgbaSpan);
ref Rgba32 scanBaseRef = ref MemoryMarshal.GetReference(rgbaSpan);
// And loop through each column

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);
}
});
}

39
tests/ImageSharp.Benchmarks/Color/Bulk/FromRgba32Bytes.cs

@ -20,14 +20,20 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
private IMemoryOwner<byte> source;
[Params(16, 128, 1024)]
private Configuration configuration;
[Params(
128,
1024,
2048)]
public int Count { get; set; }
[GlobalSetup]
public void Setup()
{
this.destination = Configuration.Default.MemoryAllocator.Allocate<TPixel>(this.Count);
this.source = Configuration.Default.MemoryAllocator.Allocate<byte>(this.Count * 4);
this.configuration = Configuration.Default;
this.destination = this.configuration.MemoryAllocator.Allocate<TPixel>(this.Count);
this.source = this.configuration.MemoryAllocator.Allocate<byte>(this.Count * 4);
}
[GlobalCleanup]
@ -37,8 +43,8 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
this.source.Dispose();
}
[Benchmark(Baseline = true)]
public void PerElement()
//[Benchmark]
public void Naive()
{
Span<byte> s = this.source.GetSpan();
Span<TPixel> d = this.destination.GetSpan();
@ -52,20 +58,35 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
}
}
[Benchmark]
[Benchmark(Baseline = true)]
public void CommonBulk()
{
new PixelOperations<TPixel>().FromRgba32Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count);
new PixelOperations<TPixel>().FromRgba32Bytes(this.configuration, this.source.GetSpan(), this.destination.GetSpan(), this.Count);
}
[Benchmark]
public void OptimizedBulk()
{
PixelOperations<TPixel>.Instance.FromRgba32Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count);
PixelOperations<TPixel>.Instance.FromRgba32Bytes(this.configuration, this.source.GetSpan(), this.destination.GetSpan(), this.Count);
}
}
public class FromRgba32BytesRgba32 : FromRgba32Bytes<Rgba32>
public class FromRgba32Bytes_ToRgba32 : FromRgba32Bytes<Rgba32>
{
}
public class FromRgba32Bytes_ToBgra32 : FromRgba32Bytes<Bgra32>
{
// RESULTS:
// Method | Count | Mean | Error | StdDev | Scaled |
// -------------- |------ |-----------:|----------:|----------:|-------:|
// CommonBulk | 128 | 207.1 ns | 3.723 ns | 3.300 ns | 1.00 |
// OptimizedBulk | 128 | 166.5 ns | 1.204 ns | 1.005 ns | 0.80 |
// | | | | | |
// CommonBulk | 1024 | 1,333.9 ns | 12.426 ns | 11.624 ns | 1.00 |
// OptimizedBulk | 1024 | 974.1 ns | 18.803 ns | 16.669 ns | 0.73 |
// | | | | | |
// CommonBulk | 2048 | 2,625.4 ns | 30.143 ns | 26.721 ns | 1.00 |
// OptimizedBulk | 2048 | 1,843.0 ns | 20.505 ns | 18.177 ns | 0.70 |
}
}

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());
}
}

60
tests/ImageSharp.Benchmarks/Color/Bulk/Rgb24Bytes.cs

@ -0,0 +1,60 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// ReSharper disable InconsistentNaming
using System.Buffers;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
{
public abstract class Rgb24Bytes<TPixel>
where TPixel : struct, IPixel<TPixel>
{
private IMemoryOwner<TPixel> source;
private IMemoryOwner<byte> destination;
private Configuration configuration;
[Params(16, 128, 1024)]
public int Count { get; set; }
[GlobalSetup]
public void Setup()
{
this.configuration = Configuration.Default;
this.source = this.configuration.MemoryAllocator.Allocate<TPixel>(this.Count);
this.destination = this.configuration.MemoryAllocator.Allocate<byte>(this.Count * 3);
}
[GlobalCleanup]
public void Cleanup()
{
this.source.Dispose();
this.destination.Dispose();
}
[Benchmark(Baseline = true)]
public void CommonBulk() =>
new PixelOperations<TPixel>().ToRgb24Bytes(
this.configuration,
this.source.GetSpan(),
this.destination.GetSpan(),
this.Count);
[Benchmark]
public void OptimizedBulk() =>
PixelOperations<TPixel>.Instance.ToRgb24Bytes(
this.configuration,
this.source.GetSpan(),
this.destination.GetSpan(),
this.Count);
}
public class Rgb24Bytes_Rgba32 : Rgb24Bytes<Rgba32>
{
}
}

37
tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs → tests/ImageSharp.Benchmarks/Color/Bulk/ToRgba32Bytes.cs

@ -12,21 +12,24 @@ using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
{
public abstract class ToXyzw<TPixel>
public abstract class ToRgba32Bytes<TPixel>
where TPixel : struct, IPixel<TPixel>
{
private IMemoryOwner<TPixel> source;
private IMemoryOwner<byte> destination;
private Configuration configuration;
[Params(16, 128, 1024)]
public int Count { get; set; }
[GlobalSetup]
public void Setup()
{
this.source = Configuration.Default.MemoryAllocator.Allocate<TPixel>(this.Count);
this.destination = Configuration.Default.MemoryAllocator.Allocate<byte>(this.Count * 4);
this.configuration = Configuration.Default;
this.source = this.configuration.MemoryAllocator.Allocate<TPixel>(this.Count);
this.destination = this.configuration.MemoryAllocator.Allocate<byte>(this.Count * 4);
}
[GlobalCleanup]
@ -36,8 +39,8 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
this.destination.Dispose();
}
[Benchmark(Baseline = true)]
public void PerElement()
//[Benchmark]
public void Naive()
{
Span<TPixel> s = this.source.GetSpan();
Span<byte> d = this.destination.GetSpan();
@ -55,18 +58,32 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
}
}
[Benchmark]
public void CommonBulk() => new PixelOperations<TPixel>().ToRgba32Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count);
[Benchmark(Baseline = true)]
public void CommonBulk() =>
new PixelOperations<TPixel>().ToRgba32Bytes(
this.configuration,
this.source.GetSpan(),
this.destination.GetSpan(),
this.Count);
[Benchmark]
public void OptimizedBulk() => PixelOperations<TPixel>.Instance.ToRgba32Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count);
public void OptimizedBulk() =>
PixelOperations<TPixel>.Instance.ToRgba32Bytes(
this.configuration,
this.source.GetSpan(),
this.destination.GetSpan(),
this.Count);
}
public class ToRgba32Bytes_FromRgba32 : ToRgba32Bytes<Rgba32>
{
}
public class ToXyzw_Rgba32 : ToXyzw<Rgba32>
public class ToRgba32Bytes_FromArgb32 : ToRgba32Bytes<Argb32>
{
}
public class ToXyzw_Argb32 : ToXyzw<Argb32>
public class ToRgba32Bytes_FromBgra32 : ToRgba32Bytes<Bgra32>
{
}
}

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

@ -6,14 +6,8 @@
using System.Buffers;
using System;
using System.Numerics;
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 +21,21 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
protected IMemoryOwner<Vector4> destination;
protected Configuration Configuration => Configuration.Default;
[Params(
64,
//256,
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]
@ -51,7 +46,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
}
//[Benchmark]
public void PerElement()
public void Naive()
{
Span<TPixel> s = this.source.GetSpan();
Span<Vector4> d = this.destination.GetSpan();
@ -61,160 +56,15 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
d[i] = s[i].ToVector4();
}
}
[Benchmark]
public void PixelOperations_Base()
{
new PixelOperations<TPixel>().ToVector4(this.source.GetSpan(), this.destination.GetSpan());
}
[Benchmark]
public void PixelOperations_Specialized()
{
PixelOperations<TPixel>.Instance.ToVector4(this.source.GetSpan(), this.destination.GetSpan());
}
}
[Config(typeof(Config.ShortClr))]
public class ToVector4_Rgba32 : ToVector4<Rgba32>
{
[Benchmark]
public void FallbackIntrinsics128()
{
Span<byte> sBytes = MemoryMarshal.Cast<Rgba32, byte>(this.source.GetSpan());
Span<float> dFloats = MemoryMarshal.Cast<Vector4, float>(this.destination.GetSpan());
SimdUtils.FallbackIntrinsics128.BulkConvertByteToNormalizedFloat(sBytes, dFloats);
}
[Benchmark(Baseline = true)]
public void BasicIntrinsics256()
{
Span<byte> sBytes = MemoryMarshal.Cast<Rgba32, byte>(this.source.GetSpan());
Span<float> dFloats = MemoryMarshal.Cast<Vector4, float>(this.destination.GetSpan());
SimdUtils.BasicIntrinsics256.BulkConvertByteToNormalizedFloat(sBytes, dFloats);
}
[Benchmark]
public void ExtendedIntrinsics()
{
Span<byte> sBytes = MemoryMarshal.Cast<Rgba32, byte>(this.source.GetSpan());
Span<float> dFloats = MemoryMarshal.Cast<Vector4, float>(this.destination.GetSpan());
SimdUtils.ExtendedIntrinsics.BulkConvertByteToNormalizedFloat(sBytes, dFloats);
}
//[Benchmark]
public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat_2Loops()
{
Span<byte> sBytes = MemoryMarshal.Cast<Rgba32, byte>(this.source.GetSpan());
Span<float> dFloats = MemoryMarshal.Cast<Vector4, float>(this.destination.GetSpan());
int n = dFloats.Length / Vector<byte>.Count;
ref Vector<byte> sourceBase = ref Unsafe.As<byte, Vector<byte>>(ref MemoryMarshal.GetReference((ReadOnlySpan<byte>)sBytes));
ref Vector<float> destBase = ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(dFloats));
ref Vector<uint> destBaseU = ref Unsafe.As<Vector<float>, Vector<uint>>(ref destBase);
for (int i = 0; i < n; i++)
{
Vector<byte> b = Unsafe.Add(ref sourceBase, i);
Vector.Widen(b, out Vector<ushort> s0, out Vector<ushort> s1);
Vector.Widen(s0, out Vector<uint> w0, out Vector<uint> w1);
Vector.Widen(s1, out Vector<uint> w2, out Vector<uint> w3);
ref Vector<uint> d = ref Unsafe.Add(ref destBaseU, i * 4);
d = w0;
Unsafe.Add(ref d, 1) = w1;
Unsafe.Add(ref d, 2) = w2;
Unsafe.Add(ref d, 3) = w3;
}
n = dFloats.Length / Vector<float>.Count;
var scale = new Vector<float>(1f / 255f);
for (int i = 0; i < n; i++)
{
ref Vector<float> dRef = ref Unsafe.Add(ref destBase, i);
Vector<int> du = Vector.AsVectorInt32(dRef);
Vector<float> v = Vector.ConvertToSingle(du);
v *= scale;
dRef = v;
}
}
//[Benchmark]
public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat_ConvertInSameLoop()
{
Span<byte> sBytes = MemoryMarshal.Cast<Rgba32, byte>(this.source.GetSpan());
Span<float> dFloats = MemoryMarshal.Cast<Vector4, float>(this.destination.GetSpan());
int n = dFloats.Length / Vector<byte>.Count;
ref Vector<byte> sourceBase = ref Unsafe.As<byte, Vector<byte>>(ref MemoryMarshal.GetReference((ReadOnlySpan<byte>)sBytes));
ref Vector<float> destBase = ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(dFloats));
var scale = new Vector<float>(1f / 255f);
for (int i = 0; i < n; i++)
{
Vector<byte> b = Unsafe.Add(ref sourceBase, i);
Vector.Widen(b, out Vector<ushort> s0, out Vector<ushort> s1);
Vector.Widen(s0, out Vector<uint> w0, out Vector<uint> w1);
Vector.Widen(s1, out Vector<uint> w2, out Vector<uint> w3);
Vector<float> f0 = ConvertToNormalizedSingle(w0, scale);
Vector<float> f1 = ConvertToNormalizedSingle(w1, scale);
Vector<float> f2 = ConvertToNormalizedSingle(w2, scale);
Vector<float> f3 = ConvertToNormalizedSingle(w3, scale);
ref Vector<float> d = ref Unsafe.Add(ref destBase, i * 4);
d = f0;
Unsafe.Add(ref d, 1) = f1;
Unsafe.Add(ref d, 2) = f2;
Unsafe.Add(ref d, 3) = f3;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Vector<float> ConvertToNormalizedSingle(Vector<uint> u, Vector<float> scale)
public void PixelOperations_Specialized()
{
Vector<int> vi = Vector.AsVectorInt32(u);
Vector<float> v = Vector.ConvertToSingle(vi);
v *= scale;
return v;
PixelOperations<TPixel>.Instance.ToVector4(
this.Configuration,
this.source.GetSpan(),
this.destination.GetSpan());
}
// RESULTS (2018 October):
//
// Method | Runtime | Count | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Allocated |
// ---------------------------- |-------- |------ |------------:|-------------:|------------:|-------:|---------:|-------:|----------:|
// FallbackIntrinsics128 | Clr | 64 | 287.62 ns | 6.026 ns | 0.3405 ns | 1.19 | 0.00 | - | 0 B |
// BasicIntrinsics256 | Clr | 64 | 240.83 ns | 10.585 ns | 0.5981 ns | 1.00 | 0.00 | - | 0 B |
// ExtendedIntrinsics | Clr | 64 | 168.28 ns | 11.478 ns | 0.6485 ns | 0.70 | 0.00 | - | 0 B |
// PixelOperations_Base | Clr | 64 | 334.08 ns | 38.048 ns | 2.1498 ns | 1.39 | 0.01 | 0.0072 | 24 B |
// PixelOperations_Specialized | Clr | 64 | 255.41 ns | 10.939 ns | 0.6181 ns | 1.06 | 0.00 | - | 0 B | <--- ceremonial overhead has been minimized!
// | | | | | | | | | |
// FallbackIntrinsics128 | Core | 64 | 183.29 ns | 8.931 ns | 0.5046 ns | 1.32 | 0.00 | - | 0 B |
// BasicIntrinsics256 | Core | 64 | 139.18 ns | 7.633 ns | 0.4313 ns | 1.00 | 0.00 | - | 0 B |
// ExtendedIntrinsics | Core | 64 | 66.29 ns | 16.366 ns | 0.9247 ns | 0.48 | 0.01 | - | 0 B |
// PixelOperations_Base | Core | 64 | 257.75 ns | 16.959 ns | 0.9582 ns | 1.85 | 0.01 | 0.0072 | 24 B |
// PixelOperations_Specialized | Core | 64 | 90.14 ns | 9.955 ns | 0.5625 ns | 0.65 | 0.00 | - | 0 B |
// | | | | | | | | | |
// FallbackIntrinsics128 | Clr | 2048 | 5,011.84 ns | 347.991 ns | 19.6621 ns | 1.22 | 0.01 | - | 0 B |
// BasicIntrinsics256 | Clr | 2048 | 4,119.35 ns | 720.153 ns | 40.6900 ns | 1.00 | 0.00 | - | 0 B |
// ExtendedIntrinsics | Clr | 2048 | 1,195.29 ns | 164.389 ns | 9.2883 ns |!! 0.29 | 0.00 | - | 0 B | <--- ExtendedIntrinsics rock!
// PixelOperations_Base | Clr | 2048 | 6,820.58 ns | 823.433 ns | 46.5255 ns | 1.66 | 0.02 | - | 24 B |
// PixelOperations_Specialized | Clr | 2048 | 4,203.53 ns | 176.714 ns | 9.9847 ns | 1.02 | 0.01 | - | 0 B | <--- can't yet detect whether ExtendedIntrinsics are available :(
// | | | | | | | | | |
// FallbackIntrinsics128 | Core | 2048 | 5,017.89 ns | 4,021.533 ns | 227.2241 ns | 1.24 | 0.05 | - | 0 B |
// BasicIntrinsics256 | Core | 2048 | 4,046.51 ns | 1,150.390 ns | 64.9992 ns | 1.00 | 0.00 | - | 0 B |
// ExtendedIntrinsics | Core | 2048 | 1,130.59 ns | 832.588 ns | 47.0427 ns |!! 0.28 | 0.01 | - | 0 B | <--- ExtendedIntrinsics rock!
// PixelOperations_Base | Core | 2048 | 6,752.68 ns | 272.820 ns | 15.4148 ns | 1.67 | 0.02 | - | 24 B |
// PixelOperations_Specialized | Core | 2048 | 1,126.13 ns | 79.192 ns | 4.4745 ns |!! 0.28 | 0.00 | - | 0 B | <--- ExtendedIntrinsics rock!
}
}

41
tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Bgra32.cs

@ -0,0 +1,41 @@
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
{
[Config(typeof(Config.ShortClr))]
public class ToVector4_Bgra32 : ToVector4<Bgra32>
{
[Benchmark(Baseline = true)]
public void PixelOperations_Base()
{
new PixelOperations<Bgra32>().ToVector4(
this.Configuration,
this.source.GetSpan(),
this.destination.GetSpan());
}
// RESULTS:
// Method | Runtime | Count | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Allocated |
// ---------------------------- |-------- |------ |-----------:|------------:|-----------:|-------:|---------:|-------:|----------:|
// PixelOperations_Base | Clr | 64 | 339.9 ns | 138.30 ns | 7.8144 ns | 1.00 | 0.00 | 0.0072 | 24 B |
// PixelOperations_Specialized | Clr | 64 | 338.1 ns | 13.30 ns | 0.7515 ns | 0.99 | 0.02 | - | 0 B |
// | | | | | | | | | |
// PixelOperations_Base | Core | 64 | 245.6 ns | 29.05 ns | 1.6413 ns | 1.00 | 0.00 | 0.0072 | 24 B |
// PixelOperations_Specialized | Core | 64 | 257.1 ns | 37.89 ns | 2.1407 ns | 1.05 | 0.01 | - | 0 B |
// | | | | | | | | | |
// PixelOperations_Base | Clr | 256 | 972.7 ns | 61.98 ns | 3.5020 ns | 1.00 | 0.00 | 0.0057 | 24 B |
// PixelOperations_Specialized | Clr | 256 | 882.9 ns | 126.21 ns | 7.1312 ns | 0.91 | 0.01 | - | 0 B |
// | | | | | | | | | |
// PixelOperations_Base | Core | 256 | 910.0 ns | 90.87 ns | 5.1346 ns | 1.00 | 0.00 | 0.0067 | 24 B |
// PixelOperations_Specialized | Core | 256 | 448.4 ns | 15.77 ns | 0.8910 ns | 0.49 | 0.00 | - | 0 B |
// | | | | | | | | | |
// PixelOperations_Base | Clr | 2048 | 6,951.8 ns | 1,299.01 ns | 73.3963 ns | 1.00 | 0.00 | - | 24 B |
// PixelOperations_Specialized | Clr | 2048 | 5,852.3 ns | 630.56 ns | 35.6279 ns | 0.84 | 0.01 | - | 0 B |
// | | | | | | | | | |
// PixelOperations_Base | Core | 2048 | 6,937.5 ns | 1,692.19 ns | 95.6121 ns | 1.00 | 0.00 | - | 24 B |
// PixelOperations_Specialized | Core | 2048 | 2,994.5 ns | 1,126.65 ns | 63.6578 ns | 0.43 | 0.01 | - | 0 B |
}
}

164
tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4_Rgba32.cs

@ -0,0 +1,164 @@
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
{
[Config(typeof(Config.ShortClr))]
public class ToVector4_Rgba32 : ToVector4<Rgba32>
{
[Benchmark]
public void FallbackIntrinsics128()
{
Span<byte> sBytes = MemoryMarshal.Cast<Rgba32, byte>(this.source.GetSpan());
Span<float> dFloats = MemoryMarshal.Cast<Vector4, float>(this.destination.GetSpan());
SimdUtils.FallbackIntrinsics128.BulkConvertByteToNormalizedFloat(sBytes, dFloats);
}
[Benchmark]
public void PixelOperations_Base()
{
new PixelOperations<Rgba32>().ToVector4(
this.Configuration,
this.source.GetSpan(),
this.destination.GetSpan());
}
[Benchmark(Baseline = true)]
public void BasicIntrinsics256()
{
Span<byte> sBytes = MemoryMarshal.Cast<Rgba32, byte>(this.source.GetSpan());
Span<float> dFloats = MemoryMarshal.Cast<Vector4, float>(this.destination.GetSpan());
SimdUtils.BasicIntrinsics256.BulkConvertByteToNormalizedFloat(sBytes, dFloats);
}
[Benchmark]
public void ExtendedIntrinsics()
{
Span<byte> sBytes = MemoryMarshal.Cast<Rgba32, byte>(this.source.GetSpan());
Span<float> dFloats = MemoryMarshal.Cast<Vector4, float>(this.destination.GetSpan());
SimdUtils.ExtendedIntrinsics.BulkConvertByteToNormalizedFloat(sBytes, dFloats);
}
//[Benchmark]
public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat_2Loops()
{
Span<byte> sBytes = MemoryMarshal.Cast<Rgba32, byte>(this.source.GetSpan());
Span<float> dFloats = MemoryMarshal.Cast<Vector4, float>(this.destination.GetSpan());
int n = dFloats.Length / Vector<byte>.Count;
ref Vector<byte> sourceBase = ref Unsafe.As<byte, Vector<byte>>(ref MemoryMarshal.GetReference((ReadOnlySpan<byte>)sBytes));
ref Vector<float> destBase = ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(dFloats));
ref Vector<uint> destBaseU = ref Unsafe.As<Vector<float>, Vector<uint>>(ref destBase);
for (int i = 0; i < n; i++)
{
Vector<byte> b = Unsafe.Add(ref sourceBase, i);
Vector.Widen(b, out Vector<ushort> s0, out Vector<ushort> s1);
Vector.Widen(s0, out Vector<uint> w0, out Vector<uint> w1);
Vector.Widen(s1, out Vector<uint> w2, out Vector<uint> w3);
ref Vector<uint> d = ref Unsafe.Add(ref destBaseU, i * 4);
d = w0;
Unsafe.Add(ref d, 1) = w1;
Unsafe.Add(ref d, 2) = w2;
Unsafe.Add(ref d, 3) = w3;
}
n = dFloats.Length / Vector<float>.Count;
var scale = new Vector<float>(1f / 255f);
for (int i = 0; i < n; i++)
{
ref Vector<float> dRef = ref Unsafe.Add(ref destBase, i);
Vector<int> du = Vector.AsVectorInt32(dRef);
Vector<float> v = Vector.ConvertToSingle(du);
v *= scale;
dRef = v;
}
}
//[Benchmark]
public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat_ConvertInSameLoop()
{
Span<byte> sBytes = MemoryMarshal.Cast<Rgba32, byte>(this.source.GetSpan());
Span<float> dFloats = MemoryMarshal.Cast<Vector4, float>(this.destination.GetSpan());
int n = dFloats.Length / Vector<byte>.Count;
ref Vector<byte> sourceBase = ref Unsafe.As<byte, Vector<byte>>(ref MemoryMarshal.GetReference((ReadOnlySpan<byte>)sBytes));
ref Vector<float> destBase = ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(dFloats));
var scale = new Vector<float>(1f / 255f);
for (int i = 0; i < n; i++)
{
Vector<byte> b = Unsafe.Add(ref sourceBase, i);
Vector.Widen(b, out Vector<ushort> s0, out Vector<ushort> s1);
Vector.Widen(s0, out Vector<uint> w0, out Vector<uint> w1);
Vector.Widen(s1, out Vector<uint> w2, out Vector<uint> w3);
Vector<float> f0 = ConvertToNormalizedSingle(w0, scale);
Vector<float> f1 = ConvertToNormalizedSingle(w1, scale);
Vector<float> f2 = ConvertToNormalizedSingle(w2, scale);
Vector<float> f3 = ConvertToNormalizedSingle(w3, scale);
ref Vector<float> d = ref Unsafe.Add(ref destBase, i * 4);
d = f0;
Unsafe.Add(ref d, 1) = f1;
Unsafe.Add(ref d, 2) = f2;
Unsafe.Add(ref d, 3) = f3;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Vector<float> ConvertToNormalizedSingle(Vector<uint> u, Vector<float> scale)
{
Vector<int> vi = Vector.AsVectorInt32(u);
Vector<float> v = Vector.ConvertToSingle(vi);
v *= scale;
return v;
}
// RESULTS (2018 October):
//
// Method | Runtime | Count | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Allocated |
// ---------------------------- |-------- |------ |------------:|-------------:|------------:|-------:|---------:|-------:|----------:|
// FallbackIntrinsics128 | Clr | 64 | 287.62 ns | 6.026 ns | 0.3405 ns | 1.19 | 0.00 | - | 0 B |
// BasicIntrinsics256 | Clr | 64 | 240.83 ns | 10.585 ns | 0.5981 ns | 1.00 | 0.00 | - | 0 B |
// ExtendedIntrinsics | Clr | 64 | 168.28 ns | 11.478 ns | 0.6485 ns | 0.70 | 0.00 | - | 0 B |
// PixelOperations_Base | Clr | 64 | 334.08 ns | 38.048 ns | 2.1498 ns | 1.39 | 0.01 | 0.0072 | 24 B |
// PixelOperations_Specialized | Clr | 64 | 255.41 ns | 10.939 ns | 0.6181 ns | 1.06 | 0.00 | - | 0 B | <--- ceremonial overhead has been minimized!
// | | | | | | | | | |
// FallbackIntrinsics128 | Core | 64 | 183.29 ns | 8.931 ns | 0.5046 ns | 1.32 | 0.00 | - | 0 B |
// BasicIntrinsics256 | Core | 64 | 139.18 ns | 7.633 ns | 0.4313 ns | 1.00 | 0.00 | - | 0 B |
// ExtendedIntrinsics | Core | 64 | 66.29 ns | 16.366 ns | 0.9247 ns | 0.48 | 0.01 | - | 0 B |
// PixelOperations_Base | Core | 64 | 257.75 ns | 16.959 ns | 0.9582 ns | 1.85 | 0.01 | 0.0072 | 24 B |
// PixelOperations_Specialized | Core | 64 | 90.14 ns | 9.955 ns | 0.5625 ns | 0.65 | 0.00 | - | 0 B |
// | | | | | | | | | |
// FallbackIntrinsics128 | Clr | 2048 | 5,011.84 ns | 347.991 ns | 19.6621 ns | 1.22 | 0.01 | - | 0 B |
// BasicIntrinsics256 | Clr | 2048 | 4,119.35 ns | 720.153 ns | 40.6900 ns | 1.00 | 0.00 | - | 0 B |
// ExtendedIntrinsics | Clr | 2048 | 1,195.29 ns | 164.389 ns | 9.2883 ns |!! 0.29 | 0.00 | - | 0 B | <--- ExtendedIntrinsics rock!
// PixelOperations_Base | Clr | 2048 | 6,820.58 ns | 823.433 ns | 46.5255 ns | 1.66 | 0.02 | - | 24 B |
// PixelOperations_Specialized | Clr | 2048 | 4,203.53 ns | 176.714 ns | 9.9847 ns | 1.02 | 0.01 | - | 0 B | <--- can't yet detect whether ExtendedIntrinsics are available :(
// | | | | | | | | | |
// FallbackIntrinsics128 | Core | 2048 | 5,017.89 ns | 4,021.533 ns | 227.2241 ns | 1.24 | 0.05 | - | 0 B |
// BasicIntrinsics256 | Core | 2048 | 4,046.51 ns | 1,150.390 ns | 64.9992 ns | 1.00 | 0.00 | - | 0 B |
// ExtendedIntrinsics | Core | 2048 | 1,130.59 ns | 832.588 ns | 47.0427 ns |!! 0.28 | 0.01 | - | 0 B | <--- ExtendedIntrinsics rock!
// PixelOperations_Base | Core | 2048 | 6,752.68 ns | 272.820 ns | 15.4148 ns | 1.67 | 0.02 | - | 24 B |
// PixelOperations_Specialized | Core | 2048 | 1,126.13 ns | 79.192 ns | 4.4745 ns |!! 0.28 | 0.00 | - | 0 B | <--- ExtendedIntrinsics rock!
}
}

47
tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs

@ -1,47 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// ReSharper disable InconsistentNaming
using System.Buffers;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
{
public abstract class ToXyz<TPixel>
where TPixel : struct, IPixel<TPixel>
{
private IMemoryOwner<TPixel> source;
private IMemoryOwner<byte> destination;
[Params(16, 128, 1024)]
public int Count { get; set; }
[GlobalSetup]
public void Setup()
{
this.source = Configuration.Default.MemoryAllocator.Allocate<TPixel>(this.Count);
this.destination = Configuration.Default.MemoryAllocator.Allocate<byte>(this.Count * 3);
}
[GlobalCleanup]
public void Cleanup()
{
this.source.Dispose();
this.destination.Dispose();
}
[Benchmark(Baseline = true)]
public void CommonBulk() => new PixelOperations<TPixel>().ToRgb24Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count);
[Benchmark]
public void OptimizedBulk() => PixelOperations<TPixel>.Instance.ToRgb24Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count);
}
public class ToXyz_Rgba32 : ToXyz<Rgba32>
{
}
}

145
tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs

@ -1,21 +1,24 @@
// ReSharper disable InconsistentNaming
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.PixelFormats.Utils;
namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion
{
public class PixelConversion_ConvertFromRgba32
public abstract class PixelConversion_ConvertFromRgba32
{
struct ConversionRunner<T>
internal struct ConversionRunner<T>
where T : struct, ITestPixel<T>
{
private T[] dest;
public readonly T[] dest;
private Rgba32[] source;
public readonly Rgba32[] source;
public ConversionRunner(int count)
{
@ -67,72 +70,146 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion
}
}
private ConversionRunner<TestRgba> compatibleMemLayoutRunner;
internal ConversionRunner<TestRgba> compatibleMemLayoutRunner;
private ConversionRunner<TestArgb> permutedRunner;
internal ConversionRunner<TestArgb> permutedRunnerRgbaToArgb;
[Params(32)]
[Params(
256,
2048
)]
public int Count { get; set; }
[GlobalSetup]
public void Setup()
{
this.compatibleMemLayoutRunner = new ConversionRunner<TestRgba>(this.Count);
this.permutedRunner = new ConversionRunner<TestArgb>(this.Count);
this.permutedRunnerRgbaToArgb = new ConversionRunner<TestArgb>(this.Count);
}
}
public class PixelConversion_ConvertFromRgba32_Compatible : PixelConversion_ConvertFromRgba32
{
[Benchmark(Baseline = true)]
public void CompatibleByRef()
public void ByRef()
{
this.compatibleMemLayoutRunner.RunByRefConversion();
}
[Benchmark]
public void CompatibleByVal()
public void ByVal()
{
this.compatibleMemLayoutRunner.RunByValConversion();
}
[Benchmark]
public void CompatibleFromBytes()
public void FromBytes()
{
this.compatibleMemLayoutRunner.RunFromBytesConversion();
}
[Benchmark]
public void Inline()
{
ref Rgba32 sBase = ref this.compatibleMemLayoutRunner.source[0];
ref Rgba32 dBase = ref Unsafe.As<TestRgba, Rgba32>(ref this.compatibleMemLayoutRunner.dest[0]);
for (int i = 0; i < this.Count; i++)
{
Unsafe.Add(ref dBase, i) = Unsafe.Add(ref sBase, i);
}
}
// Method | Count | Mean | Error | StdDev | Scaled | ScaledSD |
// ---------- |------ |---------:|---------:|---------:|-------:|---------:|
// ByRef | 256 | 128.5 ns | 1.217 ns | 1.138 ns | 1.00 | 0.00 |
// ByVal | 256 | 196.7 ns | 2.792 ns | 2.612 ns | 1.53 | 0.02 |
// FromBytes | 256 | 321.7 ns | 2.180 ns | 1.820 ns | 2.50 | 0.03 |
// Inline | 256 | 129.9 ns | 2.759 ns | 2.581 ns | 1.01 | 0.02 |
}
public class PixelConversion_ConvertFromRgba32_Permuted_RgbaToArgb : PixelConversion_ConvertFromRgba32
{
[Benchmark(Baseline = true)]
public void ByRef()
{
this.permutedRunnerRgbaToArgb.RunByRefConversion();
}
[Benchmark]
public void ByVal()
{
this.permutedRunnerRgbaToArgb.RunByValConversion();
}
[Benchmark]
public void FromBytes()
{
this.permutedRunnerRgbaToArgb.RunFromBytesConversion();
}
[Benchmark]
public void PermutedByRef()
public void InlineShuffle()
{
this.permutedRunner.RunByRefConversion();
ref Rgba32 sBase = ref this.permutedRunnerRgbaToArgb.source[0];
ref TestArgb dBase = ref this.permutedRunnerRgbaToArgb.dest[0];
for (int i = 0; i < this.Count; i++)
{
Rgba32 s = Unsafe.Add(ref sBase, i);
ref TestArgb d = ref Unsafe.Add(ref dBase, i);
d.R = s.R;
d.G = s.G;
d.B = s.B;
d.A = s.A;
}
}
[Benchmark]
public void PermutedByVal()
public void PixelConverter_Rgba32_ToArgb32()
{
this.permutedRunner.RunByValConversion();
ref uint sBase = ref Unsafe.As<Rgba32, uint>(ref this.permutedRunnerRgbaToArgb.source[0]);
ref uint dBase = ref Unsafe.As<TestArgb, uint>(ref this.permutedRunnerRgbaToArgb.dest[0]);
for (int i = 0; i < this.Count; i++)
{
uint s = Unsafe.Add(ref sBase, i);
Unsafe.Add(ref dBase, i) = PixelConverter.FromRgba32.ToArgb32(s);
}
}
[Benchmark]
public void PermutedFromBytes()
public void PixelConverter_Rgba32_ToArgb32_CopyThenWorkOnSingleBuffer()
{
this.permutedRunner.RunFromBytesConversion();
Span<uint> source = MemoryMarshal.Cast<Rgba32, uint>(this.permutedRunnerRgbaToArgb.source);
Span<uint> dest = MemoryMarshal.Cast<TestArgb, uint>(this.permutedRunnerRgbaToArgb.dest);
source.CopyTo(dest);
ref uint dBase = ref MemoryMarshal.GetReference(dest);
for (int i = 0; i < this.Count; i++)
{
uint s = Unsafe.Add(ref dBase, i);
Unsafe.Add(ref dBase, i) = PixelConverter.FromRgba32.ToArgb32(s);
}
}
}
/*
* Results:
* Method | Count | Mean | StdDev | Scaled | Scaled-StdDev |
* ------------------ |------ |----------- |---------- |------- |-------------- |
* CompatibleByRef | 32 | 20.6339 ns | 0.0742 ns | 1.00 | 0.00 |
* CompatibleByVal | 32 | 23.7425 ns | 0.0997 ns | 1.15 | 0.01 |
* CompatibleFromBytes | 32 | 38.7017 ns | 0.1103 ns | 1.88 | 0.01 |
* PermutedByRef | 32 | 39.2892 ns | 0.1366 ns | 1.90 | 0.01 |
* PermutedByVal | 32 | 38.5178 ns | 0.1946 ns | 1.87 | 0.01 |
* PermutedFromBytes | 32 | 38.6683 ns | 0.0801 ns | 1.87 | 0.01 |
*
* !!! Conclusion !!!
* All memory-incompatible (permuted) variants are equivalent with the the "FromBytes" solution.
* In memory compatible cases we should use the optimized Bulk-copying variant anyways,
* so there is no benefit introducing non-bulk API-s other than FromBytes() OR FromRgba32().
*/
// RESULTS:
// Method | Count | Mean | Error | StdDev | Scaled | ScaledSD |
// ---------------------------------------------------------- |------ |-----------:|-----------:|-----------:|-------:|---------:|
// ByRef | 256 | 328.7 ns | 6.6141 ns | 6.1868 ns | 1.00 | 0.00 |
// ByVal | 256 | 322.0 ns | 4.3541 ns | 4.0728 ns | 0.98 | 0.02 |
// FromBytes | 256 | 321.5 ns | 3.3499 ns | 3.1335 ns | 0.98 | 0.02 |
// InlineShuffle | 256 | 330.7 ns | 4.2525 ns | 3.9778 ns | 1.01 | 0.02 |
// PixelConverter_Rgba32_ToArgb32 | 256 | 167.4 ns | 0.6357 ns | 0.5309 ns | 0.51 | 0.01 |
// PixelConverter_Rgba32_ToArgb32_CopyThenWorkOnSingleBuffer | 256 | 196.6 ns | 0.8929 ns | 0.7915 ns | 0.60 | 0.01 |
// | | | | | | |
// ByRef | 2048 | 2,534.4 ns | 8.2947 ns | 6.9265 ns | 1.00 | 0.00 |
// ByVal | 2048 | 2,638.5 ns | 52.6843 ns | 70.3320 ns | 1.04 | 0.03 |
// FromBytes | 2048 | 2,517.2 ns | 40.8055 ns | 38.1695 ns | 0.99 | 0.01 |
// InlineShuffle | 2048 | 2,546.5 ns | 21.2506 ns | 19.8778 ns | 1.00 | 0.01 |
// PixelConverter_Rgba32_ToArgb32 | 2048 | 1,265.7 ns | 5.1397 ns | 4.5562 ns | 0.50 | 0.00 |
// PixelConverter_Rgba32_ToArgb32_CopyThenWorkOnSingleBuffer | 2048 | 1,410.3 ns | 11.1939 ns | 9.9231 ns | 0.56 | 0.00 |//
}
}

176
tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Argb32.cs

@ -0,0 +1,176 @@
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion
{
public class PixelConversion_Rgba32_To_Argb32
{
private Rgba32[] source;
private Argb32[] dest;
[Params(64)]
public int Count { get; set; }
[GlobalSetup]
public void Setup()
{
this.source = new Rgba32[this.Count];
this.dest = new Argb32[this.Count];
}
[Benchmark(Baseline = true)]
public void Default()
{
ref Rgba32 sBase = ref this.source[0];
ref Argb32 dBase = ref this.dest[0];
for (int i = 0; i < this.Count; i++)
{
Rgba32 s = Unsafe.Add(ref sBase, i);
Unsafe.Add(ref dBase, i).FromRgba32(s);
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static void Default_GenericImpl<TPixel>(ReadOnlySpan<Rgba32> source, Span<TPixel> dest)
where TPixel : struct, IPixel<TPixel>
{
ref Rgba32 sBase = ref MemoryMarshal.GetReference(source);
ref TPixel dBase = ref MemoryMarshal.GetReference(dest);
for (int i = 0; i < source.Length; i++)
{
Rgba32 s = Unsafe.Add(ref sBase, i);
Unsafe.Add(ref dBase, i).FromRgba32(s);
}
}
[Benchmark]
public void Default_Generic()
{
Default_GenericImpl(this.source.AsSpan(), this.dest.AsSpan());
}
[Benchmark]
public void Default_Group2()
{
ref Rgba32 sBase = ref this.source[0];
ref Argb32 dBase = ref this.dest[0];
for (int i = 0; i < this.Count; i += 2)
{
ref Rgba32 s0 = ref Unsafe.Add(ref sBase, i);
Rgba32 s1 = Unsafe.Add(ref s0, 1);
ref Argb32 d0 = ref Unsafe.Add(ref dBase, i);
d0.FromRgba32(s0);
Unsafe.Add(ref d0, 1).FromRgba32(s1);
}
}
[Benchmark]
public void Default_Group4()
{
ref Rgba32 sBase = ref this.source[0];
ref Argb32 dBase = ref this.dest[0];
for (int i = 0; i < this.Count; i += 4)
{
ref Rgba32 s0 = ref Unsafe.Add(ref sBase, i);
ref Rgba32 s1 = ref Unsafe.Add(ref s0, 1);
ref Rgba32 s2 = ref Unsafe.Add(ref s1, 1);
Rgba32 s3 = Unsafe.Add(ref s2, 1);
ref Argb32 d0 = ref Unsafe.Add(ref dBase, i);
ref Argb32 d1 = ref Unsafe.Add(ref d0, 1);
ref Argb32 d2 = ref Unsafe.Add(ref d1, 1);
d0.FromRgba32(s0);
d1.FromRgba32(s1);
d2.FromRgba32(s2);
Unsafe.Add(ref d2, 1).FromRgba32(s3);
}
}
[Benchmark]
public void BitOps()
{
ref uint sBase = ref Unsafe.As<Rgba32, uint>(ref this.source[0]);
ref uint dBase = ref Unsafe.As<Argb32, uint>(ref this.dest[0]);
for (int i = 0; i < this.Count; i++)
{
uint s = Unsafe.Add(ref sBase, i);
Unsafe.Add(ref dBase, i) = FromRgba32.ToArgb32(s);
}
}
[Benchmark]
public void BitOps_GroupAsULong()
{
ref ulong sBase = ref Unsafe.As<Rgba32, ulong>(ref this.source[0]);
ref ulong dBase = ref Unsafe.As<Argb32, ulong>(ref this.dest[0]);
for (int i = 0; i < this.Count / 2; i++)
{
ulong s = Unsafe.Add(ref sBase, i);
uint lo = (uint)s;
uint hi = (uint)(s >> 32);
lo = FromRgba32.ToArgb32(lo);
hi = FromRgba32.ToArgb32(hi);
s = (ulong)(hi << 32) | lo;
Unsafe.Add(ref dBase, i) = s;
}
}
public static class FromRgba32
{
/// <summary>
/// Converts a packed <see cref="Rgba32"/> to <see cref="Argb32"/>.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
public static uint ToArgb32(uint packedRgba)
{
// packedRgba = [aa bb gg rr]
// ROL(8, packedRgba) = [bb gg rr aa]
return (packedRgba << 8) | (packedRgba >> 24);
}
/// <summary>
/// Converts a packed <see cref="Rgba32"/> to <see cref="Bgra32"/>.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
public static uint ToBgra32(uint packedRgba)
{
// packedRgba = [aa bb gg rr]
// tmp1 = [aa 00 gg 00]
// tmp2 = [00 bb 00 rr]
// tmp3=ROL(16, tmp2) = [00 rr 00 bb]
// tmp1 + tmp3 = [aa rr gg bb]
uint tmp1 = packedRgba & 0xFF00FF00;
uint tmp2 = packedRgba & 0x00FF00FF;
uint tmp3 = (tmp2 << 16) | (tmp2 >> 16);
return tmp1 + tmp3;
}
}
// RESULTS:
// Method | Count | Mean | Error | StdDev | Scaled |
// -------------------- |------ |----------:|----------:|----------:|-------:|
// Default | 64 | 107.33 ns | 1.0633 ns | 0.9426 ns | 1.00 |
// Default_Generic | 64 | 111.15 ns | 0.3789 ns | 0.3544 ns | 1.04 |
// Default_Group2 | 64 | 90.36 ns | 0.7779 ns | 0.6896 ns | 0.84 |
// Default_Group4 | 64 | 82.39 ns | 0.2726 ns | 0.2550 ns | 0.77 |
// BitOps | 64 | 39.25 ns | 0.3266 ns | 0.2895 ns | 0.37 |
// BitOps_GroupAsULong | 64 | 41.80 ns | 0.2227 ns | 0.2083 ns | 0.39 |
}
}

392
tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Bgra32.cs

@ -0,0 +1,392 @@
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Attributes.Jobs;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Tuples;
namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion
{
//[MonoJob]
//[RyuJitX64Job]
public class PixelConversion_Rgba32_To_Bgra32
{
private Rgba32[] source;
private Bgra32[] dest;
[StructLayout(LayoutKind.Sequential)]
struct Tuple4OfUInt32
{
public uint V0, V1, V2, V3;
public void ConvertMe()
{
this.V0 = FromRgba32.ToBgra32(this.V0);
this.V1 = FromRgba32.ToBgra32(this.V1);
this.V2 = FromRgba32.ToBgra32(this.V2);
this.V3 = FromRgba32.ToBgra32(this.V3);
}
}
[Params(64)]
public int Count { get; set; }
[GlobalSetup]
public void Setup()
{
this.source = new Rgba32[this.Count];
this.dest = new Bgra32[this.Count];
}
[Benchmark(Baseline = true)]
public void Default()
{
ref Rgba32 sBase = ref this.source[0];
ref Bgra32 dBase = ref this.dest[0];
for (int i = 0; i < this.Count; i++)
{
ref Rgba32 s = ref Unsafe.Add(ref sBase, i);
Unsafe.Add(ref dBase, i).FromRgba32(s);
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static void Default_GenericImpl<TPixel>(ReadOnlySpan<Rgba32> source, Span<TPixel> dest)
where TPixel : struct, IPixel<TPixel>
{
ref Rgba32 sBase = ref MemoryMarshal.GetReference(source);
ref TPixel dBase = ref MemoryMarshal.GetReference(dest);
for (int i = 0; i < source.Length; i++)
{
ref Rgba32 s = ref Unsafe.Add(ref sBase, i);
Unsafe.Add(ref dBase, i).FromRgba32(s);
}
}
[Benchmark]
public void Default_Generic()
{
Default_GenericImpl(this.source.AsSpan(), this.dest.AsSpan());
}
[Benchmark]
public void Default_Group2()
{
ref Rgba32 sBase = ref this.source[0];
ref Bgra32 dBase = ref this.dest[0];
for (int i = 0; i < this.Count; i+=2)
{
ref Rgba32 s0 = ref Unsafe.Add(ref sBase, i);
Rgba32 s1 = Unsafe.Add(ref s0, 1);
ref Bgra32 d0 = ref Unsafe.Add(ref dBase, i);
d0.FromRgba32(s0);
Unsafe.Add(ref d0, 1).FromRgba32(s1);
}
}
[Benchmark]
public void Default_Group4()
{
ref Rgba32 sBase = ref this.source[0];
ref Bgra32 dBase = ref this.dest[0];
for (int i = 0; i < this.Count; i += 4)
{
ref Rgba32 s0 = ref Unsafe.Add(ref sBase, i);
ref Rgba32 s1 = ref Unsafe.Add(ref s0, 1);
ref Rgba32 s2 = ref Unsafe.Add(ref s1, 1);
Rgba32 s3 = Unsafe.Add(ref s2, 1);
ref Bgra32 d0 = ref Unsafe.Add(ref dBase, i);
ref Bgra32 d1 = ref Unsafe.Add(ref d0, 1);
ref Bgra32 d2 = ref Unsafe.Add(ref d1, 1);
d0.FromRgba32(s0);
d1.FromRgba32(s1);
d2.FromRgba32(s2);
Unsafe.Add(ref d2, 1).FromRgba32(s3);
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static void Group4GenericImpl<TPixel>(ReadOnlySpan<Rgba32> source, Span<TPixel> dest)
where TPixel : struct, IPixel<TPixel>
{
ref Rgba32 sBase = ref MemoryMarshal.GetReference(source);
ref TPixel dBase = ref MemoryMarshal.GetReference(dest);
for (int i = 0; i < source.Length; i += 4)
{
ref Rgba32 s0 = ref Unsafe.Add(ref sBase, i);
ref Rgba32 s1 = ref Unsafe.Add(ref s0, 1);
ref Rgba32 s2 = ref Unsafe.Add(ref s1, 1);
Rgba32 s3 = Unsafe.Add(ref s2, 1);
ref TPixel d0 = ref Unsafe.Add(ref dBase, i);
ref TPixel d1 = ref Unsafe.Add(ref d0, 1);
ref TPixel d2 = ref Unsafe.Add(ref d1, 1);
d0.FromRgba32(s0);
d1.FromRgba32(s1);
d2.FromRgba32(s2);
Unsafe.Add(ref d2, 1).FromRgba32(s3);
}
}
//[Benchmark]
public void Default_Group4_Generic()
{
Group4GenericImpl(this.source.AsSpan(), this.dest.AsSpan());
}
//[Benchmark]
public void Default_Group8()
{
ref Rgba32 sBase = ref this.source[0];
ref Bgra32 dBase = ref this.dest[0];
for (int i = 0; i < this.Count / 4; i += 4)
{
ref Rgba32 s0 = ref Unsafe.Add(ref sBase, i);
ref Rgba32 s1 = ref Unsafe.Add(ref s0, 1);
ref Rgba32 s2 = ref Unsafe.Add(ref s1, 1);
ref Rgba32 s3 = ref Unsafe.Add(ref s1, 1);
ref Rgba32 s4 = ref Unsafe.Add(ref s3, 1);
ref Rgba32 s5 = ref Unsafe.Add(ref s4, 1);
ref Rgba32 s6 = ref Unsafe.Add(ref s5, 1);
Rgba32 s7 = Unsafe.Add(ref s6, 1);
ref Bgra32 d0 = ref Unsafe.Add(ref dBase, i);
ref Bgra32 d1 = ref Unsafe.Add(ref d0, 1);
ref Bgra32 d2 = ref Unsafe.Add(ref d1, 1);
ref Bgra32 d3 = ref Unsafe.Add(ref d2, 1);
ref Bgra32 d4 = ref Unsafe.Add(ref d3, 1);
ref Bgra32 d5 = ref Unsafe.Add(ref d4, 1);
ref Bgra32 d6 = ref Unsafe.Add(ref d5, 1);
d0.FromRgba32(s0);
d1.FromRgba32(s1);
d2.FromRgba32(s2);
d3.FromRgba32(s3);
d4.FromRgba32(s4);
d5.FromRgba32(s5);
d6.FromRgba32(s6);
Unsafe.Add(ref d6, 1).FromRgba32(s7);
}
}
[Benchmark]
public void BitOps()
{
ref uint sBase = ref Unsafe.As<Rgba32, uint>(ref this.source[0]);
ref uint dBase = ref Unsafe.As<Bgra32, uint>(ref this.dest[0]);
for (int i = 0; i < this.Count; i++)
{
uint s = Unsafe.Add(ref sBase, i);
Unsafe.Add(ref dBase, i) = FromRgba32.ToBgra32(s);
}
}
[Benchmark]
public void Bitops_Tuple()
{
ref Tuple4OfUInt32 sBase = ref Unsafe.As<Rgba32, Tuple4OfUInt32>(ref this.source[0]);
ref Tuple4OfUInt32 dBase = ref Unsafe.As<Bgra32, Tuple4OfUInt32>(ref this.dest[0]);
for (int i = 0; i < this.Count / 4; i++)
{
ref Tuple4OfUInt32 d = ref Unsafe.Add(ref dBase, i);
d = Unsafe.Add(ref sBase, i);
d.ConvertMe();
}
}
//[Benchmark]
public void Bitops_SingleTuple()
{
ref Tuple4OfUInt32 sBase = ref Unsafe.As<Rgba32, Tuple4OfUInt32>(ref this.source[0]);
for (int i = 0; i < this.Count / 4; i++)
{
Unsafe.Add(ref sBase, i).ConvertMe();
}
}
//[Benchmark]
public void Bitops_Simd()
{
ref Octet.OfUInt32 sBase = ref Unsafe.As<Rgba32, Octet.OfUInt32>(ref this.source[0]);
ref Octet.OfUInt32 dBase = ref Unsafe.As<Bgra32, Octet.OfUInt32>(ref this.dest[0]);
for (int i = 0; i < this.Count / 8; i++)
{
BitopsSimdImpl(ref Unsafe.Add(ref sBase, i), ref Unsafe.Add(ref dBase, i));
}
}
[StructLayout(LayoutKind.Sequential)]
struct B
{
public uint tmp2, tmp5, tmp8, tmp11, tmp14, tmp17, tmp20, tmp23;
}
[StructLayout(LayoutKind.Sequential)]
struct C
{
public uint tmp3, tmp6, tmp9, tmp12, tmp15, tmp18, tmp21, tmp24;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void BitopsSimdImpl(ref Octet.OfUInt32 s, ref Octet.OfUInt32 d)
{
Vector<uint> sVec = Unsafe.As<Octet.OfUInt32, Vector<uint>>(ref s);
Vector<uint> aMask = new Vector<uint>(0xFF00FF00);
Vector<uint> bMask = new Vector<uint>(0x00FF00FF);
Vector<uint> aa = sVec & aMask;
Vector<uint> bb = sVec & bMask;
B b = Unsafe.As<Vector<uint>, B>(ref bb);
C c = default;
c.tmp3 = (b.tmp2 << 16) | (b.tmp2 >> 16);
c.tmp6 = (b.tmp5 << 16) | (b.tmp5 >> 16);
c.tmp9 = (b.tmp8 << 16) | (b.tmp8 >> 16);
c.tmp12 = (b.tmp11 << 16) | (b.tmp11 >> 16);
c.tmp15 = (b.tmp14 << 16) | (b.tmp14 >> 16);
c.tmp18 = (b.tmp17 << 16) | (b.tmp17 >> 16);
c.tmp21 = (b.tmp20 << 16) | (b.tmp20 >> 16);
c.tmp24 = (b.tmp23 << 16) | (b.tmp23 >> 16);
Vector<uint> cc = Unsafe.As<C, Vector<uint>>(ref c);
Vector<uint> dd = aa + cc;
d = Unsafe.As<Vector<uint>, Octet.OfUInt32>(ref dd);
}
//[Benchmark]
public void BitOps_Group2()
{
ref uint sBase = ref Unsafe.As<Rgba32, uint>(ref this.source[0]);
ref uint dBase = ref Unsafe.As<Bgra32, uint>(ref this.dest[0]);
for (int i = 0; i < this.Count; i++)
{
ref uint s0 = ref Unsafe.Add(ref sBase, i);
uint s1 = Unsafe.Add(ref s0, 1);
ref uint d0 = ref Unsafe.Add(ref dBase, i);
d0 = FromRgba32.ToBgra32(s0);
Unsafe.Add(ref d0, 1) = FromRgba32.ToBgra32(s1);
}
}
[Benchmark]
public void BitOps_GroupAsULong()
{
ref ulong sBase = ref Unsafe.As<Rgba32, ulong>(ref this.source[0]);
ref ulong dBase = ref Unsafe.As<Bgra32, ulong>(ref this.dest[0]);
for (int i = 0; i < this.Count / 2; i++)
{
ulong s = Unsafe.Add(ref sBase, i);
uint lo = (uint)s;
uint hi = (uint)(s >> 32);
lo = FromRgba32.ToBgra32(lo);
hi = FromRgba32.ToBgra32(hi);
s = (ulong)(hi << 32) | lo;
Unsafe.Add(ref dBase, i) = s;
}
}
//[Benchmark]
public void BitOps_GroupAsULong_V2()
{
ref ulong sBase = ref Unsafe.As<Rgba32, ulong>(ref this.source[0]);
ref ulong dBase = ref Unsafe.As<Bgra32, ulong>(ref this.dest[0]);
for (int i = 0; i < this.Count / 2; i++)
{
ulong s = Unsafe.Add(ref sBase, i);
uint lo = (uint)s;
uint hi = (uint)(s >> 32);
uint tmp1 = lo & 0xFF00FF00;
uint tmp4 = hi & 0xFF00FF00;
uint tmp2 = lo & 0x00FF00FF;
uint tmp5 = hi & 0x00FF00FF;
uint tmp3 = (tmp2 << 16) | (tmp2 >> 16);
uint tmp6 = (tmp5 << 16) | (tmp5 >> 16);
lo = tmp1 + tmp3;
hi = tmp4 + tmp6;
s = (ulong)(hi << 32) | lo;
Unsafe.Add(ref dBase, i) = s;
}
}
public static class FromRgba32
{
/// <summary>
/// Converts a packed <see cref="Rgba32"/> to <see cref="Argb32"/>.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
public static uint ToArgb32(uint packedRgba)
{
// packedRgba = [aa bb gg rr]
// ROL(8, packedRgba) = [bb gg rr aa]
return (packedRgba << 8) | (packedRgba >> 24);
}
/// <summary>
/// Converts a packed <see cref="Rgba32"/> to <see cref="Bgra32"/>.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
public static uint ToBgra32(uint packedRgba)
{
// packedRgba = [aa bb gg rr]
// tmp1 = [aa 00 gg 00]
// tmp2 = [00 bb 00 rr]
// tmp3=ROL(16, tmp2) = [00 rr 00 bb]
// tmp1 + tmp3 = [aa rr gg bb]
uint tmp1 = packedRgba & 0xFF00FF00;
uint tmp2 = packedRgba & 0x00FF00FF;
uint tmp3 = (tmp2 << 16) | (tmp2 >> 16);
return tmp1 + tmp3;
}
}
// RESULTS:
// Method | Count | Mean | Error | StdDev | Scaled | ScaledSD |
// -------------------- |------ |---------:|----------:|----------:|-------:|---------:|
// Default | 64 | 82.67 ns | 0.6737 ns | 0.5625 ns | 1.00 | 0.00 |
// Default_Generic | 64 | 88.73 ns | 1.7959 ns | 1.7638 ns | 1.07 | 0.02 |
// Default_Group2 | 64 | 91.03 ns | 1.5237 ns | 1.3508 ns | 1.10 | 0.02 |
// Default_Group4 | 64 | 86.62 ns | 1.5737 ns | 1.4720 ns | 1.05 | 0.02 |
// BitOps | 64 | 57.45 ns | 0.6067 ns | 0.5066 ns | 0.69 | 0.01 |
// Bitops_Tuple | 64 | 75.47 ns | 1.1824 ns | 1.1060 ns | 0.91 | 0.01 |
// BitOps_GroupAsULong | 64 | 65.42 ns | 0.7157 ns | 0.6695 ns | 0.79 | 0.01 |
}
}

62
tests/ImageSharp.Benchmarks/General/PixelConversion/TestArgb.cs

@ -9,81 +9,81 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion
[StructLayout(LayoutKind.Sequential)]
struct TestArgb : ITestPixel<TestArgb>
{
private byte a, r, g, b;
public byte A, R, G, B;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void FromRgba32(Rgba32 p)
{
this.r = p.R;
this.g = p.G;
this.b = p.B;
this.a = p.A;
this.R = p.R;
this.G = p.G;
this.B = p.B;
this.A = p.A;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void FromRgba32(ref Rgba32 p)
{
this.r = p.R;
this.g = p.G;
this.b = p.B;
this.a = p.A;
this.R = p.R;
this.G = p.G;
this.B = p.B;
this.A = p.A;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void FromBytes(byte r, byte g, byte b, byte a)
{
this.r = r;
this.g = g;
this.b = b;
this.a = a;
this.R = r;
this.G = g;
this.B = b;
this.A = a;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void FromVector4(Vector4 p)
{
this.r = (byte)p.X;
this.g = (byte)p.Y;
this.b = (byte)p.Z;
this.a = (byte)p.W;
this.R = (byte)p.X;
this.G = (byte)p.Y;
this.B = (byte)p.Z;
this.A = (byte)p.W;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void FromVector4(ref Vector4 p)
{
this.r = (byte)p.X;
this.g = (byte)p.Y;
this.b = (byte)p.Z;
this.a = (byte)p.W;
this.R = (byte)p.X;
this.G = (byte)p.Y;
this.B = (byte)p.Z;
this.A = (byte)p.W;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Rgba32 ToRgba32()
{
return new Rgba32(this.r, this.g, this.b, this.a);
return new Rgba32(this.R, this.G, this.B, this.A);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void CopyToRgba32(ref Rgba32 dest)
{
dest.R = this.r;
dest.G = this.g;
dest.B = this.b;
dest.A = this.a;
dest.R = this.R;
dest.G = this.G;
dest.B = this.B;
dest.A = this.A;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToVector4()
{
return new Vector4(this.r, this.g, this.b, this.a);
return new Vector4(this.R, this.G, this.B, this.A);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void CopyToVector4(ref Vector4 dest)
{
dest.X = this.r;
dest.Y = this.g;
dest.Z = this.b;
dest.W = this.a;
dest.X = this.R;
dest.Y = this.G;
dest.Z = this.B;
dest.W = this.A;
}
}
}

14
tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs

@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion
[StructLayout(LayoutKind.Sequential)]
struct TestRgba : ITestPixel<TestRgba>
{
private byte r, g, b, a;
public byte R, G, B, A;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void FromRgba32(Rgba32 source)
@ -26,10 +26,10 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void FromBytes(byte r, byte g, byte b, byte a)
{
this.r = r;
this.g = g;
this.b = b;
this.a = a;
this.R = r;
this.G = g;
this.B = b;
this.A = a;
}
public void FromVector4(Vector4 source)
@ -57,13 +57,13 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToVector4()
{
return new Vector4(this.r, this.g, this.b, this.a) * new Vector4(1f / 255f);
return new Vector4(this.R, this.G, this.B, this.A) * new Vector4(1f / 255f);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void CopyToVector4(ref Vector4 dest)
{
var tmp = new Vector4(this.r, this.g, this.b, this.a);
var tmp = new Vector4(this.R, this.G, this.B, this.A);
tmp *= new Vector4(1f / 255f);
dest = tmp;
}

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);
}
}

2
tests/ImageSharp.Sandbox46/Program.cs

@ -3,6 +3,8 @@
// Licensed under the Apache License, Version 2.0.
// </copyright>
using SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations;
namespace SixLabors.ImageSharp.Sandbox46
{
using System;

1
tests/ImageSharp.Tests/ConfigurationTests.cs

@ -6,6 +6,7 @@ using System.Linq;
using Moq;
using SixLabors.ImageSharp.Formats.Bmp;
using SixLabors.ImageSharp.IO;
using Xunit;
// ReSharper disable InconsistentNaming

4
tests/ImageSharp.Tests/Drawing/FillLinearGradientBrushTests.cs

@ -328,7 +328,9 @@ namespace SixLabors.ImageSharp.Tests.Drawing
TPixel color = colors[stopColorCodes[i % colors.Length]];
float position = stopPositions[i];
colorStops[i] = new ColorStop<TPixel>(position, color);
coloringVariant.AppendFormat(CultureInfo.InvariantCulture, "{0}@{1};", color.ToRgba32().ToHex(), position);
Rgba32 rgba = default;
color.ToRgba32(ref rgba);
coloringVariant.AppendFormat(CultureInfo.InvariantCulture, "{0}@{1};", rgba.ToHex(), position);
}
FormattableString variant = $"({startX},{startY})_TO_({endX},{endY})__[{coloringVariant}]";

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);

21
tests/ImageSharp.Tests/GraphicsOptionsTests.cs

@ -0,0 +1,21 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using Xunit;
namespace SixLabors.ImageSharp.Tests
{
public class GraphicsOptionsTests
{
[Fact]
public void IsOpaqueColor()
{
Assert.True(new GraphicsOptions(true).IsOpaqueColorWithoutBlending(Rgba32.Red));
Assert.False(new GraphicsOptions(true, 0.5f).IsOpaqueColorWithoutBlending(Rgba32.Red));
Assert.False(new GraphicsOptions(true).IsOpaqueColorWithoutBlending(Rgba32.Transparent));
Assert.False(new GraphicsOptions(true, PixelColorBlendingMode.Lighten, 1).IsOpaqueColorWithoutBlending(Rgba32.Red));
Assert.False(new GraphicsOptions(true, PixelColorBlendingMode.Normal, PixelAlphaCompositionMode.DestOver, 1).IsOpaqueColorWithoutBlending(Rgba32.Red));
}
}
}

3
tests/ImageSharp.Tests/PixelFormats/Alpha8Tests.cs

@ -90,7 +90,8 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats
var input = new Alpha8(128);
var expected = new Rgba32(0, 0, 0, 128);
var actual = input.ToRgba32();
Rgba32 actual = default;
input.ToRgba32(ref actual);
Assert.Equal(expected, actual);
}
}

3
tests/ImageSharp.Tests/PixelFormats/Gray16Tests.cs

@ -117,7 +117,8 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats
var gray = new Gray16(input);
// Act
var actual = gray.ToRgba32();
Rgba32 actual = default;
gray.ToRgba32(ref actual);
// Assert
Assert.Equal(expected, actual.R);

5
tests/ImageSharp.Tests/PixelFormats/Gray8Tests.cs

@ -115,10 +115,11 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats
var gray = new Gray8(input);
// Act
var actual = gray.ToRgba32();
Rgba32 actual = default;
gray.ToRgba32(ref actual);
// Assert
Assert.Equal(input, actual.R);
Assert.Equal(input, actual.R);
Assert.Equal(input, actual.G);
Assert.Equal(input, actual.B);
Assert.Equal(byte.MaxValue, actual.A);

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);
}
}

160
tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.cs

@ -0,0 +1,160 @@
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.PixelFormats.Utils;
using Xunit;
namespace SixLabors.ImageSharp.Tests.PixelFormats
{
public abstract class PixelConverterTests
{
public static readonly TheoryData<byte, byte, byte, byte> RgbaData =
new TheoryData<byte, byte, byte, byte>
{
{ 0, 0, 0, 0 },
{ 0, 0, 0, 255 },
{ 0, 0, 255, 0 },
{ 0, 255, 0, 0 },
{ 255, 0, 0, 0 },
{ 255, 255, 255, 255 },
{ 0, 0, 0, 1 },
{ 0, 0, 1, 0 },
{ 0, 1, 0, 0 },
{ 1, 0, 0, 0 },
{ 3, 5, 7, 11 },
{ 67, 71, 101, 109 }
};
public class FromRgba32 : PixelConverterTests
{
[Theory]
[MemberData(nameof(RgbaData))]
public void ToArgb32(byte r, byte g, byte b, byte a)
{
Rgba32 s = ReferenceImplementations.MakeRgba32(r, g, b, a);
// Act:
uint actualPacked = PixelConverter.FromRgba32.ToArgb32(s.PackedValue);
// Assert:
uint expectedPacked = ReferenceImplementations.MakeArgb32(r, g, b, a).PackedValue;
Assert.Equal(expectedPacked, actualPacked);
}
[Theory]
[MemberData(nameof(RgbaData))]
public void ToBgra32(byte r, byte g, byte b, byte a)
{
Rgba32 s = ReferenceImplementations.MakeRgba32(r, g, b, a);
// Act:
uint actualPacked = PixelConverter.FromRgba32.ToBgra32(s.PackedValue);
// Assert:
uint expectedPacked = ReferenceImplementations.MakeBgra32(r, g, b, a).PackedValue;
Assert.Equal(expectedPacked, actualPacked);
}
}
public class FromArgb32 : PixelConverterTests
{
[Theory]
[MemberData(nameof(RgbaData))]
public void ToRgba32(byte r, byte g, byte b, byte a)
{
Argb32 s = ReferenceImplementations.MakeArgb32(r, g, b, a);
// Act:
uint actualPacked = PixelConverter.FromArgb32.ToRgba32(s.PackedValue);
// Assert:
uint expectedPacked = ReferenceImplementations.MakeRgba32(r, g, b, a).PackedValue;
Assert.Equal(expectedPacked, actualPacked);
}
[Theory]
[MemberData(nameof(RgbaData))]
public void ToBgra32(byte r, byte g, byte b, byte a)
{
Argb32 s = ReferenceImplementations.MakeArgb32(r, g, b, a);
// Act:
uint actualPacked = PixelConverter.FromArgb32.ToBgra32(s.PackedValue);
// Assert:
uint expectedPacked = ReferenceImplementations.MakeBgra32(r, g, b, a).PackedValue;
Assert.Equal(expectedPacked, actualPacked);
}
}
public class FromBgra32 : PixelConverterTests
{
[Theory]
[MemberData(nameof(RgbaData))]
public void ToArgb32(byte r, byte g, byte b, byte a)
{
Bgra32 s = ReferenceImplementations.MakeBgra32(r, g, b, a);
// Act:
uint actualPacked = PixelConverter.FromBgra32.ToArgb32(s.PackedValue);
// Assert:
uint expectedPacked = ReferenceImplementations.MakeArgb32(r, g, b, a).PackedValue;
Assert.Equal(expectedPacked, actualPacked);
}
[Theory]
[MemberData(nameof(RgbaData))]
public void ToRgba32(byte r, byte g, byte b, byte a)
{
Bgra32 s = ReferenceImplementations.MakeBgra32(r, g, b, a);
// Act:
uint actualPacked = PixelConverter.FromBgra32.ToRgba32(s.PackedValue);
// Assert:
uint expectedPacked = ReferenceImplementations.MakeRgba32(r, g, b, a).PackedValue;
Assert.Equal(expectedPacked, actualPacked);
}
}
private static class ReferenceImplementations
{
public static Rgba32 MakeRgba32(byte r, byte g, byte b, byte a)
{
Rgba32 d = default;
d.R = r;
d.G = g;
d.B = b;
d.A = a;
return d;
}
public static Argb32 MakeArgb32(byte r, byte g, byte b, byte a)
{
Argb32 d = default;
d.R = r;
d.G = g;
d.B = b;
d.A = a;
return d;
}
public static Bgra32 MakeBgra32(byte r, byte g, byte b, byte a)
{
Bgra32 d = default;
d.R = r;
d.G = g;
d.B = b;
d.A = a;
return d;
}
}
}
}

25
tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Argb32OperationsTests.cs

@ -0,0 +1,25 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using Xunit;
using Xunit.Abstractions;
namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations
{
public partial class PixelOperationsTests
{
public class Argb32OperationsTests : PixelOperationsTests<Argb32>
{
public Argb32OperationsTests(ITestOutputHelper output)
: base(output)
{
}
[Fact]
public void IsSpecialImplementation() => Assert.IsType<Argb32.PixelOperations>(PixelOperations<Argb32>.Instance);
}
}
}

24
tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgr24OperationsTests.cs

@ -0,0 +1,24 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using Xunit;
using Xunit.Abstractions;
namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations
{
public partial class PixelOperationsTests
{
public class Bgr24OperationsTests : PixelOperationsTests<Bgr24>
{
public Bgr24OperationsTests(ITestOutputHelper output)
: base(output)
{
}
[Fact]
public void IsSpecialImplementation() => Assert.IsType<Bgr24.PixelOperations>(PixelOperations<Bgr24>.Instance);
}
}
}

24
tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Bgra32OperationsTests.cs

@ -0,0 +1,24 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using Xunit;
using Xunit.Abstractions;
namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations
{
public partial class PixelOperationsTests
{
public class Bgra32OperationsTests : PixelOperationsTests<Bgra32>
{
public Bgra32OperationsTests(ITestOutputHelper output)
: base(output)
{
}
[Fact]
public void IsSpecialImplementation() => Assert.IsType<Bgra32.PixelOperations>(PixelOperations<Bgra32>.Instance);
}
}
}

114
tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Gray16OperationsTests.cs

@ -0,0 +1,114 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using Xunit;
using Xunit.Abstractions;
namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations
{
public partial class PixelOperationsTests
{
public class Gray16OperationsTests : PixelOperationsTests<Gray16>
{
public Gray16OperationsTests(ITestOutputHelper output)
: base(output)
{
}
[Fact]
public void IsSpecialImplementation() => Assert.IsType<Gray16.PixelOperations>(PixelOperations<Gray16>.Instance);
[Theory]
[MemberData(nameof(ArraySizesData))]
public void FromGray8Bytes(int count)
{
byte[] source = CreateByteTestData(count);
var expected = new Gray16[count];
for (int i = 0; i < count; i++)
{
expected[i].FromGray8(new Gray8(source[i]));
}
TestOperation(
source,
expected,
(s, d) => Operations.FromGray8Bytes(this.Configuration, s, d.GetSpan(), count)
);
}
[Theory]
[MemberData(nameof(ArraySizesData))]
public void ToGray8Bytes(int count)
{
Gray16[] source = CreatePixelTestData(count);
byte[] expected = new byte[count];
var gray = default(Gray8);
for (int i = 0; i < count; i++)
{
gray.FromScaledVector4(source[i].ToScaledVector4());
expected[i] = gray.PackedValue;
}
TestOperation(
source,
expected,
(s, d) => Operations.ToGray8Bytes(this.Configuration, s, d.GetSpan(), count)
);
}
[Theory]
[MemberData(nameof(ArraySizesData))]
public void FromGray16Bytes(int count)
{
byte[] source = CreateByteTestData(count * 2);
Span<byte> sourceSpan = source.AsSpan();
var expected = new Gray16[count];
for (int i = 0; i < count; i++)
{
int i2 = i * 2;
expected[i].FromGray16(MemoryMarshal.Cast<byte, Gray16>(sourceSpan.Slice(i2, 2))[0]);
}
TestOperation(
source,
expected,
(s, d) => Operations.FromGray16Bytes(this.Configuration, s, d.GetSpan(), count)
);
}
[Theory]
[MemberData(nameof(ArraySizesData))]
public void ToGray16Bytes(int count)
{
Gray16[] source = CreatePixelTestData(count);
byte[] expected = new byte[count * 2];
Gray16 gray = default;
for (int i = 0; i < count; i++)
{
int i2 = i * 2;
gray.FromScaledVector4(source[i].ToScaledVector4());
OctetBytes bytes = Unsafe.As<Gray16, OctetBytes>(ref gray);
expected[i2] = bytes[0];
expected[i2 + 1] = bytes[1];
}
TestOperation(
source,
expected,
(s, d) => Operations.ToGray16Bytes(this.Configuration, s, d.GetSpan(), count)
);
}
}
}
}

114
tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Gray8OperationsTests.cs

@ -0,0 +1,114 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using Xunit;
using Xunit.Abstractions;
namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations
{
public partial class PixelOperationsTests
{
public class Gray8OperationsTests : PixelOperationsTests<Gray8>
{
public Gray8OperationsTests(ITestOutputHelper output)
: base(output)
{
}
[Fact]
public void IsSpecialImplementation() => Assert.IsType<Gray8.PixelOperations>(PixelOperations<Gray8>.Instance);
[Theory]
[MemberData(nameof(ArraySizesData))]
public void FromGray8Bytes(int count)
{
byte[] source = CreateByteTestData(count);
var expected = new Gray8[count];
for (int i = 0; i < count; i++)
{
expected[i].FromGray8(new Gray8(source[i]));
}
TestOperation(
source,
expected,
(s, d) => Operations.FromGray8Bytes(this.Configuration, s, d.GetSpan(), count)
);
}
[Theory]
[MemberData(nameof(ArraySizesData))]
public void ToGray8Bytes(int count)
{
Gray8[] source = CreatePixelTestData(count);
byte[] expected = new byte[count];
var gray = default(Gray8);
for (int i = 0; i < count; i++)
{
gray.FromScaledVector4(source[i].ToScaledVector4());
expected[i] = gray.PackedValue;
}
TestOperation(
source,
expected,
(s, d) => Operations.ToGray8Bytes(this.Configuration, s, d.GetSpan(), count)
);
}
[Theory]
[MemberData(nameof(ArraySizesData))]
public void FromGray16Bytes(int count)
{
byte[] source = CreateByteTestData(count * 2);
Span<byte> sourceSpan = source.AsSpan();
var expected = new Gray8[count];
for (int i = 0; i < count; i++)
{
int i2 = i * 2;
expected[i].FromGray16(MemoryMarshal.Cast<byte, Gray16>(sourceSpan.Slice(i2, 2))[0]);
}
TestOperation(
source,
expected,
(s, d) => Operations.FromGray16Bytes(this.Configuration, s, d.GetSpan(), count)
);
}
[Theory]
[MemberData(nameof(ArraySizesData))]
public void ToGray16Bytes(int count)
{
Gray8[] source = CreatePixelTestData(count);
byte[] expected = new byte[count * 2];
Gray16 gray = default;
for (int i = 0; i < count; i++)
{
int i2 = i * 2;
gray.FromScaledVector4(source[i].ToScaledVector4());
OctetBytes bytes = Unsafe.As<Gray16, OctetBytes>(ref gray);
expected[i2] = bytes[0];
expected[i2 + 1] = bytes[1];
}
TestOperation(
source,
expected,
(s, d) => Operations.ToGray16Bytes(this.Configuration, s, d.GetSpan(), count)
);
}
}
}
}

24
tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgb48OperationsTests.cs

@ -0,0 +1,24 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using Xunit;
using Xunit.Abstractions;
namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations
{
public partial class PixelOperationsTests
{
public class Rgb48OperationsTests : PixelOperationsTests<Rgb48>
{
public Rgb48OperationsTests(ITestOutputHelper output)
: base(output)
{
}
[Fact]
public void IsSpecialImplementation() => Assert.IsType<Rgb48.PixelOperations>(PixelOperations<Rgb48>.Instance);
}
}
}

46
tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgba32OperationsTests.cs

@ -0,0 +1,46 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System.Buffers;
using System.Numerics;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using Xunit;
using Xunit.Abstractions;
namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations
{
public partial class PixelOperationsTests
{
public class Rgba32OperationsTests : PixelOperationsTests<Rgba32>
{
public Rgba32OperationsTests(ITestOutputHelper output)
: base(output)
{
}
[Fact]
public void IsSpecialImplementation() => Assert.IsType<Rgba32.PixelOperations>(PixelOperations<Rgba32>.Instance);
[Fact(Skip = SkipProfilingBenchmarks)]
public void Benchmark_ToVector4()
{
const int times = 200000;
const int count = 1024;
using (IMemoryOwner<Rgba32> source = Configuration.Default.MemoryAllocator.Allocate<Rgba32>(count))
using (IMemoryOwner<Vector4> dest = Configuration.Default.MemoryAllocator.Allocate<Vector4>(count))
{
this.Measure(
times,
() => PixelOperations<Rgba32>.Instance.ToVector4(
this.Configuration,
source.GetSpan(),
dest.GetSpan()));
}
}
}
}
}

24
tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.Rgba64OperationsTests.cs

@ -0,0 +1,24 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using Xunit;
using Xunit.Abstractions;
namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations
{
public partial class PixelOperationsTests
{
public class Rgba64OperationsTests : PixelOperationsTests<Rgba64>
{
public Rgba64OperationsTests(ITestOutputHelper output)
: base(output)
{
}
[Fact]
public void IsSpecialImplementation() => Assert.IsType<Rgba64.PixelOperations>(PixelOperations<Rgba64>.Instance);
}
}
}

24
tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.RgbaVectorOperationsTests.cs

@ -0,0 +1,24 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.PixelFormats;
using Xunit;
using Xunit.Abstractions;
namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations
{
public partial class PixelOperationsTests
{
public class RgbaVectorOperationsTests : PixelOperationsTests<RgbaVector>
{
public RgbaVectorOperationsTests(ITestOutputHelper output)
: base(output)
{
}
[Fact]
public void IsSpecialImplementation() => Assert.IsType<RgbaVector.PixelOperations>(PixelOperations<RgbaVector>.Instance);
}
}
}

429
tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.cs → tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs

@ -6,332 +6,67 @@ using System.Buffers;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
using Xunit;
using Xunit.Abstractions;
namespace SixLabors.ImageSharp.Tests.PixelFormats
namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations
{
public class PixelOperationsTests
public partial class PixelOperationsTests
{
public const string SkipProfilingBenchmarks =
#if true
"Profiling benchmark - enable manually!";
#else
null;
#endif
public class Argb32OperationsTests : PixelOperationsTests<Argb32>
{
public Argb32OperationsTests(ITestOutputHelper output)
: base(output)
{
}
[Fact]
public void IsSpecialImplementation() => Assert.IsType<Argb32.PixelOperations>(PixelOperations<Argb32>.Instance);
}
public class Bgr24OperationsTests : PixelOperationsTests<Bgr24>
{
public Bgr24OperationsTests(ITestOutputHelper output)
: base(output)
{
}
[Fact]
public void IsSpecialImplementation() => Assert.IsType<Bgr24.PixelOperations>(PixelOperations<Bgr24>.Instance);
}
public class Bgra32OperationsTests : PixelOperationsTests<Bgra32>
{
public Bgra32OperationsTests(ITestOutputHelper output)
: base(output)
{
}
[Fact]
public void IsSpecialImplementation() => Assert.IsType<Bgra32.PixelOperations>(PixelOperations<Bgra32>.Instance);
}
public class Gray8OperationsTests : PixelOperationsTests<Gray8>
{
public Gray8OperationsTests(ITestOutputHelper output)
: base(output)
{
}
[Fact]
public void IsSpecialImplementation() => Assert.IsType<Gray8.PixelOperations>(PixelOperations<Gray8>.Instance);
[Theory]
[MemberData(nameof(ArraySizesData))]
public void FromGray8Bytes(int count)
{
byte[] source = CreateByteTestData(count);
var expected = new Gray8[count];
for (int i = 0; i < count; i++)
{
expected[i].FromGray8(new Gray8(source[i]));
}
TestOperation(
source,
expected,
(s, d) => Operations.FromGray8Bytes(s, d.GetSpan(), count)
);
}
[Theory]
[MemberData(nameof(ArraySizesData))]
public void ToGray8Bytes(int count)
{
Gray8[] source = CreatePixelTestData(count);
byte[] expected = new byte[count];
var gray = default(Gray8);
for (int i = 0; i < count; i++)
{
gray.FromScaledVector4(source[i].ToScaledVector4());
expected[i] = gray.PackedValue;
}
TestOperation(
source,
expected,
(s, d) => Operations.ToGray8Bytes(s, d.GetSpan(), count)
);
}
[Theory]
[MemberData(nameof(ArraySizesData))]
public void FromGray16Bytes(int count)
{
byte[] source = CreateByteTestData(count * 2);
Span<byte> sourceSpan = source.AsSpan();
var expected = new Gray8[count];
for (int i = 0; i < count; i++)
{
int i2 = i * 2;
expected[i].FromGray16(MemoryMarshal.Cast<byte, Gray16>(sourceSpan.Slice(i2, 2))[0]);
}
TestOperation(
source,
expected,
(s, d) => Operations.FromGray16Bytes(s, d.GetSpan(), count)
);
}
[Theory]
[MemberData(nameof(ArraySizesData))]
public void ToGray16Bytes(int count)
{
Gray8[] source = CreatePixelTestData(count);
byte[] expected = new byte[count * 2];
Gray16 gray = default;
for (int i = 0; i < count; i++)
{
int i2 = i * 2;
gray.FromScaledVector4(source[i].ToScaledVector4());
OctetBytes bytes = Unsafe.As<Gray16, OctetBytes>(ref gray);
expected[i2] = bytes[0];
expected[i2 + 1] = bytes[1];
}
TestOperation(
source,
expected,
(s, d) => Operations.ToGray16Bytes(s, d.GetSpan(), count)
);
}
}
public class Gray16OperationsTests : PixelOperationsTests<Gray16>
{
public Gray16OperationsTests(ITestOutputHelper output)
: base(output)
{
}
[Fact]
public void IsSpecialImplementation() => Assert.IsType<Gray16.PixelOperations>(PixelOperations<Gray16>.Instance);
[Theory]
[MemberData(nameof(ArraySizesData))]
public void FromGray8Bytes(int count)
{
byte[] source = CreateByteTestData(count);
var expected = new Gray16[count];
for (int i = 0; i < count; i++)
{
expected[i].FromGray8(new Gray8(source[i]));
}
TestOperation(
source,
expected,
(s, d) => Operations.FromGray8Bytes(s, d.GetSpan(), count)
);
}
[Theory]
[MemberData(nameof(ArraySizesData))]
public void ToGray8Bytes(int count)
{
Gray16[] source = CreatePixelTestData(count);
byte[] expected = new byte[count];
var gray = default(Gray8);
for (int i = 0; i < count; i++)
{
gray.FromScaledVector4(source[i].ToScaledVector4());
expected[i] = gray.PackedValue;
}
TestOperation(
source,
expected,
(s, d) => Operations.ToGray8Bytes(s, d.GetSpan(), count)
);
}
[Theory]
[MemberData(nameof(ArraySizesData))]
public void FromGray16Bytes(int count)
{
byte[] source = CreateByteTestData(count * 2);
Span<byte> sourceSpan = source.AsSpan();
var expected = new Gray16[count];
for (int i = 0; i < count; i++)
{
int i2 = i * 2;
expected[i].FromGray16(MemoryMarshal.Cast<byte, Gray16>(sourceSpan.Slice(i2, 2))[0]);
}
TestOperation(
source,
expected,
(s, d) => Operations.FromGray16Bytes(s, d.GetSpan(), count)
);
}
[Theory]
[MemberData(nameof(ArraySizesData))]
public void ToGray16Bytes(int count)
{
Gray16[] source = CreatePixelTestData(count);
byte[] expected = new byte[count * 2];
Gray16 gray = default;
for (int i = 0; i < count; i++)
{
int i2 = i * 2;
gray.FromScaledVector4(source[i].ToScaledVector4());
OctetBytes bytes = Unsafe.As<Gray16, OctetBytes>(ref gray);
expected[i2] = bytes[0];
expected[i2 + 1] = bytes[1];
}
TestOperation(
source,
expected,
(s, d) => Operations.ToGray16Bytes(s, d.GetSpan(), count)
);
}
}
public class Rgba32OperationsTests : PixelOperationsTests<Rgba32>
{
public Rgba32OperationsTests(ITestOutputHelper output)
: base(output)
{
}
[Fact]
public void IsSpecialImplementation() => Assert.IsType<Rgba32.PixelOperations>(PixelOperations<Rgba32>.Instance);
[Fact(Skip = SkipProfilingBenchmarks)]
public void Benchmark_ToVector4()
{
const int times = 200000;
const int count = 1024;
using (IMemoryOwner<Rgba32> source = Configuration.Default.MemoryAllocator.Allocate<Rgba32>(count))
using (IMemoryOwner<Vector4> dest = Configuration.Default.MemoryAllocator.Allocate<Vector4>(count))
{
this.Measure(
times,
() => PixelOperations<Rgba32>.Instance.ToVector4(source.GetSpan(), dest.GetSpan()));
}
}
}
public class Rgb48OperationsTests : PixelOperationsTests<Rgb48>
{
public Rgb48OperationsTests(ITestOutputHelper output)
: base(output)
{
}
[Fact]
public void IsSpecialImplementation() => Assert.IsType<Rgb48.PixelOperations>(PixelOperations<Rgb48>.Instance);
}
public class Rgba64OperationsTests : PixelOperationsTests<Rgba64>
{
public Rgba64OperationsTests(ITestOutputHelper output)
: base(output)
{
}
[Fact]
public void IsSpecialImplementation() => Assert.IsType<Rgba64.PixelOperations>(PixelOperations<Rgba64>.Instance);
}
public class RgbaVectorOperationsTests : PixelOperationsTests<RgbaVector>
{
public RgbaVectorOperationsTests(ITestOutputHelper output)
: base(output)
{
}
[Fact]
public void IsSpecialImplementation() => Assert.IsType<RgbaVector.PixelOperations>(PixelOperations<RgbaVector>.Instance);
}
[Theory]
[WithBlankImages(1, 1, PixelTypes.All)]
public void GetGlobalInstance<TPixel>(TestImageProvider<TPixel> _)
where TPixel : struct, IPixel<TPixel> => Assert.NotNull(PixelOperations<TPixel>.Instance);
[Fact]
public void IsOpaqueColor()
{
Assert.True(new GraphicsOptions(true).IsOpaqueColorWithoutBlending(Rgba32.Red));
Assert.False(new GraphicsOptions(true, 0.5f).IsOpaqueColorWithoutBlending(Rgba32.Red));
Assert.False(new GraphicsOptions(true).IsOpaqueColorWithoutBlending(Rgba32.Transparent));
Assert.False(new GraphicsOptions(true, PixelColorBlendingMode.Lighten, 1).IsOpaqueColorWithoutBlending(Rgba32.Red));
Assert.False(new GraphicsOptions(true, PixelColorBlendingMode.Normal, PixelAlphaCompositionMode.DestOver, 1).IsOpaqueColorWithoutBlending(Rgba32.Red));
}
public void GetGlobalInstance<T>(TestImageProvider<T> _)
where T : struct, IPixel<T> => Assert.NotNull(PixelOperations<T>.Instance);
}
public abstract class PixelOperationsTests<TPixel> : MeasureFixture
where TPixel : struct, IPixel<TPixel>
{
public const string SkipProfilingBenchmarks =
#if true
"Profiling benchmark - enable manually!";
#else
null;
#endif
protected PixelOperationsTests(ITestOutputHelper output)
: base(output)
{
}
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 };
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;
@ -367,7 +102,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,32 +116,10 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats
TestOperation(
source,
expected,
(s, d) => Operations.FromScaledVector4(s, d.GetSpan())
(s, d) => Operations.FromScaledVector4(this.Configuration, s, d.GetSpan())
);
}
internal static Vector4[] CreateExpectedVector4Data(TPixel[] source)
{
var expected = new Vector4[source.Length];
for (int i = 0; i < expected.Length; i++)
{
expected[i] = source[i].ToVector4();
}
return expected;
}
internal static Vector4[] CreateExpectedScaledVector4Data(TPixel[] source)
{
var expected = new Vector4[source.Length];
for (int i = 0; i < expected.Length; i++)
{
expected[i] = source[i].ToScaledVector4();
}
return expected;
}
[Theory]
[MemberData(nameof(ArraySizesData))]
public void ToVector4(int count)
@ -417,7 +130,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 +144,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())
);
}
@ -452,7 +165,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats
TestOperation(
source,
expected,
(s, d) => Operations.FromArgb32Bytes(s, d.GetSpan(), count)
(s, d) => Operations.FromArgb32Bytes(this.Configuration, s, d.GetSpan(), count)
);
}
@ -478,7 +191,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats
TestOperation(
source,
expected,
(s, d) => Operations.ToArgb32Bytes(s, d.GetSpan(), count)
(s, d) => Operations.ToArgb32Bytes(this.Configuration, s, d.GetSpan(), count)
);
}
@ -499,7 +212,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats
TestOperation(
source,
expected,
(s, d) => Operations.FromBgr24Bytes(s, d.GetSpan(), count)
(s, d) => Operations.FromBgr24Bytes(this.Configuration, s, d.GetSpan(), count)
);
}
@ -523,7 +236,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats
TestOperation(
source,
expected,
(s, d) => Operations.ToBgr24Bytes(s, d.GetSpan(), count)
(s, d) => Operations.ToBgr24Bytes(this.Configuration, s, d.GetSpan(), count)
);
}
@ -544,7 +257,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats
TestOperation(
source,
expected,
(s, d) => Operations.FromBgra32Bytes(s, d.GetSpan(), count)
(s, d) => Operations.FromBgra32Bytes(this.Configuration, s, d.GetSpan(), count)
);
}
@ -569,7 +282,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats
TestOperation(
source,
expected,
(s, d) => Operations.ToBgra32Bytes(s, d.GetSpan(), count)
(s, d) => Operations.ToBgra32Bytes(this.Configuration, s, d.GetSpan(), count)
);
}
@ -590,7 +303,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats
TestOperation(
source,
expected,
(s, d) => Operations.FromRgb24Bytes(s, d.GetSpan(), count)
(s, d) => Operations.FromRgb24Bytes(this.Configuration, s, d.GetSpan(), count)
);
}
@ -614,7 +327,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats
TestOperation(
source,
expected,
(s, d) => Operations.ToRgb24Bytes(s, d.GetSpan(), count)
(s, d) => Operations.ToRgb24Bytes(this.Configuration, s, d.GetSpan(), count)
);
}
@ -635,7 +348,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats
TestOperation(
source,
expected,
(s, d) => Operations.FromRgba32Bytes(s, d.GetSpan(), count)
(s, d) => Operations.FromRgba32Bytes(this.Configuration, s, d.GetSpan(), count)
);
}
@ -660,7 +373,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats
TestOperation(
source,
expected,
(s, d) => Operations.ToRgba32Bytes(s, d.GetSpan(), count)
(s, d) => Operations.ToRgba32Bytes(this.Configuration, s, d.GetSpan(), count)
);
}
@ -681,7 +394,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats
TestOperation(
source,
expected,
(s, d) => Operations.FromRgb48Bytes(s, d.GetSpan(), count)
(s, d) => Operations.FromRgb48Bytes(this.Configuration, s, d.GetSpan(), count)
);
}
@ -709,7 +422,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats
TestOperation(
source,
expected,
(s, d) => Operations.ToRgb48Bytes(s, d.GetSpan(), count)
(s, d) => Operations.ToRgb48Bytes(this.Configuration, s, d.GetSpan(), count)
);
}
@ -730,7 +443,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats
TestOperation(
source,
expected,
(s, d) => Operations.FromRgba64Bytes(s, d.GetSpan(), count)
(s, d) => Operations.FromRgba64Bytes(this.Configuration, s, d.GetSpan(), count)
);
}
@ -760,10 +473,32 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats
TestOperation(
source,
expected,
(s, d) => Operations.ToRgba64Bytes(s, d.GetSpan(), count)
(s, d) => Operations.ToRgba64Bytes(this.Configuration, s, d.GetSpan(), count)
);
}
internal static Vector4[] CreateExpectedVector4Data(TPixel[] source)
{
var expected = new Vector4[source.Length];
for (int i = 0; i < expected.Length; i++)
{
expected[i] = source[i].ToVector4();
}
return expected;
}
internal static Vector4[] CreateExpectedScaledVector4Data(TPixel[] source)
{
var expected = new Vector4[source.Length];
for (int i = 0; i < expected.Length; i++)
{
expected[i] = source[i].ToScaledVector4();
}
return expected;
}
internal static void TestOperation<TSource, TDest>(
TSource[] source,
TDest[] expected,

3
tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs

@ -104,7 +104,8 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats
public void ToRgba32()
{
var rgb = new Rgb24(1, 2, 3);
var rgba = rgb.ToRgba32();
Rgba32 rgba = default;
rgb.ToRgba32(ref rgba);
Assert.Equal(new Rgba32(1, 2, 3, 255), rgba);
}

3
tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs

@ -52,7 +52,8 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats
var expected = new Rgba32(20, 38, 76, 255);
// act
var actual = rgba48.ToRgba32();
Rgba32 actual = default;
rgba48.ToRgba32(ref actual);
// assert
Assert.Equal(expected, actual);

3
tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs

@ -79,7 +79,8 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats
var expected = new Rgba32(25, 0, 128, 0);
// act
var actual = rgba.ToRgba32();
Rgba32 actual = default;
rgba.ToRgba32(ref actual);
// assert
Assert.Equal(expected, actual);

1
tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs

@ -5,6 +5,7 @@ using System;
using System.Numerics;
using SixLabors.ImageSharp.PixelFormats;
using Xunit;
using Xunit.Abstractions;
namespace SixLabors.ImageSharp.Tests.PixelFormats
{

2
tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs

@ -86,7 +86,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats
var expected = new Rgba32(20, 38, 76, 115);
// act
actual = rgba64.ToRgba32();
rgba64.ToRgba32(ref actual);
// assert
Assert.Equal(expected, actual);

4
tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs

@ -88,7 +88,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats
var expected = new Rgba32(128, 127, 0, 255);
// act
actual = short2.ToRgba32();
short2.ToRgba32(ref actual);
// assert
Assert.Equal(expected, actual);
@ -104,7 +104,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats
// act
short2.FromRgba32(expected);
actual = short2.ToRgba32();
short2.ToRgba32(ref actual);
// assert
Assert.Equal(expected, actual);

12
tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs

@ -92,7 +92,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats
var expected = new Rgba32(172, 177, 243, 128);
// act
actual = shortValue.ToRgba32();
shortValue.ToRgba32(ref actual);
// assert
Assert.Equal(expected, actual);
@ -108,7 +108,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats
// act
short4.FromRgba32(expected);
actual = short4.ToRgba32();
short4.ToRgba32(ref actual);
// assert
Assert.Equal(expected, actual);
@ -124,7 +124,9 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats
// act
short4.FromBgra32(expected);
actual.FromRgba32(short4.ToRgba32());
Rgba32 temp = default;
short4.ToRgba32(ref temp);
actual.FromRgba32(temp);
// assert
Assert.Equal(expected, actual);
@ -140,7 +142,9 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats
// act
short4.FromArgb32(expected);
actual.FromRgba32(short4.ToRgba32());
Rgba32 temp = default;
short4.ToRgba32(ref temp);
actual.FromRgba32(temp);
// assert
Assert.Equal(expected, actual);

6
tests/ImageSharp.Tests/PixelFormats/UnPackedPixelTests.cs

@ -84,8 +84,10 @@ namespace SixLabors.ImageSharp.Tests.Colors
var color = new Rgba32(24, 48, 96, 192);
var colorVector = new RgbaVector(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F);
var rgba = color.ToRgba32();
var rgbaVector = colorVector.ToRgba32();
Rgba32 rgba = default;
Rgba32 rgbaVector = default;
color.ToRgba32(ref rgba);
colorVector.ToRgba32(ref rgbaVector);
Assert.Equal(rgba, rgbaVector);
}

28
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]);
@ -97,9 +106,10 @@ namespace SixLabors.ImageSharp.Tests
{
// Transparent pixels are much more likely to be found at the end of a palette
int index = -1;
Rgba32 trans = default;
for (int i = quantized.Palette.Length - 1; i >= 0; i--)
{
var trans = quantized.Palette[i].ToRgba32();
quantized.Palette[i].ToRgba32(ref trans);
if (trans.Equals(default))
{

5
tests/ImageSharp.Tests/TestUtilities/ImageComparison/ExactImageComparer.cs

@ -28,14 +28,15 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison
var bBuffer = new Rgba64[width];
var differences = new List<PixelDifference>();
Configuration configuration = expected.Configuration;
for (int y = 0; y < actual.Height; y++)
{
Span<TPixelA> aSpan = expected.GetPixelRowSpan(y);
Span<TPixelB> bSpan = actual.GetPixelRowSpan(y);
PixelOperations<TPixelA>.Instance.ToRgba64(aSpan, aBuffer);
PixelOperations<TPixelB>.Instance.ToRgba64(bSpan, bBuffer);
PixelOperations<TPixelA>.Instance.ToRgba64(configuration, aSpan, aBuffer);
PixelOperations<TPixelB>.Instance.ToRgba64(configuration, bSpan, bBuffer);
for (int x = 0; x < width; x++)
{

5
tests/ImageSharp.Tests/TestUtilities/ImageComparison/TolerantImageComparer.cs

@ -74,14 +74,15 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison
float totalDifference = 0F;
var differences = new List<PixelDifference>();
Configuration configuration = expected.Configuration;
for (int y = 0; y < actual.Height; y++)
{
Span<TPixelA> aSpan = expected.GetPixelRowSpan(y);
Span<TPixelB> bSpan = actual.GetPixelRowSpan(y);
PixelOperations<TPixelA>.Instance.ToRgba64(aSpan, aBuffer);
PixelOperations<TPixelB>.Instance.ToRgba64(bSpan, bBuffer);
PixelOperations<TPixelA>.Instance.ToRgba64(configuration, aSpan, aBuffer);
PixelOperations<TPixelB>.Instance.ToRgba64(configuration, bSpan, bBuffer);
for (int x = 0; x < width; x++)
{

12
tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs

@ -31,14 +31,22 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs
{
byte[] data = pixels.ToByteArray(PixelMapping.RGBA);
PixelOperations<TPixel>.Instance.FromRgba32Bytes(data, resultPixels, resultPixels.Length);
PixelOperations<TPixel>.Instance.FromRgba32Bytes(
configuration,
data,
resultPixels,
resultPixels.Length);
}
else if (magickImage.Depth == 16)
{
ushort[] data = pixels.ToShortArray(PixelMapping.RGBA);
Span<byte> bytes = MemoryMarshal.Cast<ushort, byte>(data.AsSpan());
PixelOperations<TPixel>.Instance.FromRgba64Bytes(bytes, resultPixels, resultPixels.Length);
PixelOperations<TPixel>.Instance.FromRgba64Bytes(
configuration,
bytes,
resultPixels,
resultPixels.Length);
}
else
{

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save