diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs
index 514249a2d..1dc63efa2 100644
--- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs
+++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs
@@ -82,11 +82,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
// we need to offset the pixel grid to account for when we outline a path.
// basically if the line is [1,2] => [3,2] then when outlining at 1 we end up with a region of [0.5,1.5],[1.5, 1.5],[3.5,2.5],[2.5,2.5]
// and this can cause missed fills when not using antialiasing.so we offset the pixel grid by 0.5 in the x & y direction thus causing the#
- // region to alline with the pixel grid.
+ // region to align with the pixel grid.
float offset = 0.5f;
if (this.Options.Antialias)
{
- offset = 0f; // we are antialising skip offsetting as real antalising should take care of offset.
+ offset = 0f; // we are antialiasing skip offsetting as real antialiasing should take care of offset.
subpixelCount = this.Options.AntialiasSubpixelDepth;
if (subpixelCount < 4)
{
@@ -121,7 +121,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
int pointsFound = region.Scan(subPixel + offset, buffer, configuration);
if (pointsFound == 0)
{
- // nothing on this line skip
+ // nothing on this line, skip
continue;
}
diff --git a/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs
index f9a1d8739..487c88064 100644
--- a/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs
+++ b/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs
@@ -32,7 +32,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Text
/// The font we want to render with
/// The brush to source pixel colors from.
/// The pen to outline text with.
- /// The location on the image to start drawign the text from.
+ /// The location on the image to start drawing the text from.
public DrawTextProcessor(TextGraphicsOptions options, string text, Font font, IBrush brush, IPen pen, PointF location)
{
Guard.NotNull(text, nameof(text));
@@ -85,7 +85,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Text
{
base.BeforeImageApply(source, sourceRectangle);
- // do everythign at the image level as we are deligating the processing down to other processors
+ // do everything at the image level as we are delegating the processing down to other processors
var style = new RendererOptions(this.Font, this.Options.DpiX, this.Options.DpiY, this.Location)
{
ApplyKerning = this.Options.ApplyKerning,
diff --git a/src/ImageSharp.Drawing/Processing/SolidBrush{TPixel}.cs b/src/ImageSharp.Drawing/Processing/SolidBrush{TPixel}.cs
index 6a8028770..20a6833c4 100644
--- a/src/ImageSharp.Drawing/Processing/SolidBrush{TPixel}.cs
+++ b/src/ImageSharp.Drawing/Processing/SolidBrush{TPixel}.cs
@@ -91,7 +91,7 @@ namespace SixLabors.ImageSharp.Processing
{
Span destinationRow = this.Target.GetPixelRowSpan(y).Slice(x);
- // constrain the spans to eachother
+ // constrain the spans to each other
if (destinationRow.Length > scanline.Length)
{
destinationRow = destinationRow.Slice(0, scanline.Length);
diff --git a/src/ImageSharp/Advanced/AdvancedImageExtensions.cs b/src/ImageSharp/Advanced/AdvancedImageExtensions.cs
index 328d57596..63ccea4e6 100644
--- a/src/ImageSharp/Advanced/AdvancedImageExtensions.cs
+++ b/src/ImageSharp/Advanced/AdvancedImageExtensions.cs
@@ -160,7 +160,7 @@ namespace SixLabors.ImageSharp.Advanced
///
/// The type of the pixel.
/// The source.
- /// The span retuned from Pixel source
+ /// The span returned from Pixel source
private static Span GetSpan(IPixelSource source)
where TPixel : struct, IPixel
=> source.PixelBuffer.GetSpan();
@@ -172,7 +172,7 @@ namespace SixLabors.ImageSharp.Advanced
/// The source.
/// The row.
///
- /// The span retuned from Pixel source
+ /// The span returned from Pixel source
///
private static Span GetSpan(IPixelSource source, int row)
where TPixel : struct, IPixel
@@ -185,7 +185,7 @@ namespace SixLabors.ImageSharp.Advanced
/// The source.
/// The row.
///
- /// The span retuned from Pixel source
+ /// The span returned from Pixel source
///
private static Span GetSpan(Buffer2D source, int row)
where TPixel : struct, IPixel
diff --git a/src/ImageSharp/Common/Helpers/DebugGuard.cs b/src/ImageSharp/Common/Helpers/DebugGuard.cs
index 2cf18b245..43eebeac8 100644
--- a/src/ImageSharp/Common/Helpers/DebugGuard.cs
+++ b/src/ImageSharp/Common/Helpers/DebugGuard.cs
@@ -163,6 +163,20 @@ namespace SixLabors.ImageSharp
}
}
+ ///
+ /// Verifies whether a specific condition is met, throwing an exception if it's false.
+ ///
+ /// The condition
+ /// The error message
+ [Conditional("DEBUG")]
+ public static void IsTrue(bool target, string message)
+ {
+ if (!target)
+ {
+ throw new InvalidOperationException(message);
+ }
+ }
+
///
/// Verifies, that the method parameter with specified target value is false
/// and throws an exception if it is found to be so.
diff --git a/src/ImageSharp/Common/Helpers/ImageMaths.cs b/src/ImageSharp/Common/Helpers/ImageMaths.cs
index 402aa79b5..f07ccb03b 100644
--- a/src/ImageSharp/Common/Helpers/ImageMaths.cs
+++ b/src/ImageSharp/Common/Helpers/ImageMaths.cs
@@ -76,7 +76,7 @@ namespace SixLabors.ImageSharp
///
/// Scales a value from an 8 bit to it's 16 bit equivalent.
///
- /// The 8 bit compoonent value.
+ /// The 8 bit component value.
/// The
[MethodImpl(InliningOptions.ShortMethod)]
public static ushort UpscaleFrom8BitTo16Bit(byte component) => (ushort)(component * 257);
diff --git a/src/ImageSharp/Common/Helpers/InliningOptions.cs b/src/ImageSharp/Common/Helpers/InliningOptions.cs
index ad85c4fc8..069a426d7 100644
--- a/src/ImageSharp/Common/Helpers/InliningOptions.cs
+++ b/src/ImageSharp/Common/Helpers/InliningOptions.cs
@@ -1,7 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
-// Uncomment this for verbose profiler results:
+// Uncomment this for verbose profiler results. DO NOT PUSH TO MAIN!
// #define PROFILING
using System.Runtime.CompilerServices;
diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs b/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs
index 0f1ce2ab6..85c9f0074 100644
--- a/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs
+++ b/src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs
@@ -90,7 +90,7 @@ namespace SixLabors.ImageSharp
var bVec = new Vector(256.0f / 255.0f);
var magicFloat = new Vector(32768.0f);
- var magicInt = new Vector(1191182336); // reinterpreded value of 32768.0f
+ var magicInt = new Vector(1191182336); // reinterpreted value of 32768.0f
var mask = new Vector(255);
ref Octet.OfByte sourceBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source));
diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs
index 2ac577264..9aeb20931 100644
--- a/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs
+++ b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs
@@ -25,6 +25,20 @@ namespace SixLabors.ImageSharp
false;
#endif
+ ///
+ /// Widen and convert a vector of values into 2 vectors of -s.
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static void ConvertToSingle(
+ Vector source,
+ out Vector dest1,
+ out Vector dest2)
+ {
+ Vector.Widen(source, out Vector i1, out Vector i2);
+ dest1 = Vector.ConvertToSingle(i1);
+ dest2 = Vector.ConvertToSingle(i2);
+ }
+
///
/// as many elements as possible, slicing them down (keeping the remainder).
///
diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.cs b/src/ImageSharp/Common/Helpers/SimdUtils.cs
index a989cc875..867e7b9de 100644
--- a/src/ImageSharp/Common/Helpers/SimdUtils.cs
+++ b/src/ImageSharp/Common/Helpers/SimdUtils.cs
@@ -169,7 +169,7 @@ namespace SixLabors.ImageSharp
DebugGuard.IsTrue(
ImageMaths.ModuloP2(dest.Length, shouldBeDivisibleBy) == 0,
nameof(source),
- $"length should be divisable by {shouldBeDivisibleBy}!");
+ $"length should be divisible by {shouldBeDivisibleBy}!");
}
[Conditional("DEBUG")]
@@ -179,7 +179,7 @@ namespace SixLabors.ImageSharp
DebugGuard.IsTrue(
ImageMaths.ModuloP2(dest.Length, shouldBeDivisibleBy) == 0,
nameof(source),
- $"length should be divisable by {shouldBeDivisibleBy}!");
+ $"length should be divisible by {shouldBeDivisibleBy}!");
}
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
index cea90cb45..eb519f421 100644
--- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
+++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
@@ -207,7 +207,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
///
/// Looks up color values and builds the image from de-compressed RLE8 data.
- /// Compresssed RLE8 stream is uncompressed by
+ /// Compressed RLE8 stream is uncompressed by
///
/// The pixel format.
/// The to assign the palette to.
diff --git a/src/ImageSharp/Formats/Bmp/IBmpDecoderOptions.cs b/src/ImageSharp/Formats/Bmp/IBmpDecoderOptions.cs
index c44ca73f2..219d37ca6 100644
--- a/src/ImageSharp/Formats/Bmp/IBmpDecoderOptions.cs
+++ b/src/ImageSharp/Formats/Bmp/IBmpDecoderOptions.cs
@@ -8,6 +8,6 @@ namespace SixLabors.ImageSharp.Formats.Bmp
///
internal interface IBmpDecoderOptions
{
- // added this for consistancy so we can add stuff as required, no options currently availible
+ // added this for consistency so we can add stuff as required, no options currently available
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs
index db512a078..bfa91416a 100644
--- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs
+++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs
@@ -56,7 +56,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
private GifGraphicControlExtension graphicsControlExtension;
///
- /// The image desciptor.
+ /// The image descriptor.
///
private GifImageDescriptor imageDescriptor;
@@ -142,8 +142,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
this.ReadApplicationExtension();
break;
case GifConstants.PlainTextLabel:
- int plainLength = stream.ReadByte();
- this.Skip(plainLength); // Not supported by any known decoder.
+ this.SkipBlock(); // Not supported by any known decoder.
break;
}
}
@@ -190,9 +189,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
switch (stream.ReadByte())
{
case GifConstants.GraphicControlLabel:
-
- // Skip graphic control extension block
- this.Skip(0);
+ this.SkipBlock(); // Skip graphic control extension block
break;
case GifConstants.CommentLabel:
this.ReadComments();
@@ -201,8 +198,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
this.ReadApplicationExtension();
break;
case GifConstants.PlainTextLabel:
- int plainLength = stream.ReadByte();
- this.Skip(plainLength); // Not supported by any known decoder.
+ this.SkipBlock(); // Not supported by any known decoder.
break;
}
}
@@ -288,24 +284,27 @@ namespace SixLabors.ImageSharp.Formats.Gif
// Could be XMP or something else not supported yet.
// Back up and skip.
this.stream.Position -= appLength + 1;
- this.Skip(appLength);
+ this.SkipBlock(appLength);
return;
}
- this.Skip(appLength); // Not supported by any known decoder.
+ this.SkipBlock(appLength); // Not supported by any known decoder.
}
///
- /// Skips the designated number of bytes in the stream.
+ /// Skips over a block or reads its terminator.
+ /// The length of the block to skip.
///
- /// The number of bytes to skip.
- private void Skip(int length)
+ private void SkipBlock(int blockSize = 0)
{
- this.stream.Skip(length);
+ if (blockSize > 0)
+ {
+ this.stream.Skip(blockSize);
+ }
int flag;
- while ((flag = this.stream.ReadByte()) != 0)
+ while ((flag = this.stream.ReadByte()) > 0)
{
this.stream.Skip(flag);
}
@@ -370,7 +369,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
this.ReadFrameColors(ref image, ref previousFrame, indices.GetSpan(), colorTable, this.imageDescriptor);
// Skip any remaining blocks
- this.Skip(0);
+ this.SkipBlock();
}
finally
{
diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs
index d7e2e40e2..a922f3011 100644
--- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs
+++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs
@@ -23,7 +23,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
internal sealed class GifEncoderCore
{
///
- /// Used for allocating memory during procesing operations.
+ /// Used for allocating memory during processing operations.
///
private readonly MemoryAllocator memoryAllocator;
@@ -142,7 +142,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
private void EncodeGlobal(Image image, QuantizedFrame quantized, int transparencyIndex, Stream stream)
where TPixel : struct, IPixel
{
- var palleteQuantizer = new PaletteQuantizer(this.quantizer.Diffuser);
+ var palleteQuantizer = new PaletteQuantizer(quantized.Palette, this.quantizer.Diffuser);
for (int i = 0; i < image.Frames.Count; i++)
{
@@ -158,8 +158,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
}
else
{
- using (QuantizedFrame paletteQuantized
- = palleteQuantizer.CreateFrameQuantizer(image.GetConfiguration(), () => quantized.Palette).QuantizeFrame(frame))
+ using (QuantizedFrame paletteQuantized = palleteQuantizer.CreateFrameQuantizer(image.GetConfiguration()).QuantizeFrame(frame))
{
this.WriteImageData(paletteQuantized, stream);
}
@@ -422,7 +421,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
private void WriteColorTable(QuantizedFrame image, Stream stream)
where TPixel : struct, IPixel
{
- // The maximium number of colors for the bit depth
+ // The maximum number of colors for the bit depth
int colorTableLength = ImageMaths.GetColorCountForBitDepth(this.bitDepth) * 3;
int pixelCount = image.Palette.Length;
diff --git a/src/ImageSharp/Formats/Gif/LzwEncoder.cs b/src/ImageSharp/Formats/Gif/LzwEncoder.cs
index e390dfd54..34c353ec9 100644
--- a/src/ImageSharp/Formats/Gif/LzwEncoder.cs
+++ b/src/ImageSharp/Formats/Gif/LzwEncoder.cs
@@ -52,7 +52,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
};
///
- /// The maximium number of bits/code.
+ /// The maximum number of bits/code.
///
private const int MaxBits = 12;
@@ -210,7 +210,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// flush the packet to disk.
///
/// The character to add.
- /// The reference to the storage for packat accumulators
+ /// The reference to the storage for packet accumulators
/// The stream to write to.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void AddCharacter(byte c, ref byte accumulatorsRef, Stream stream)
diff --git a/src/ImageSharp/Formats/IImageFormat.cs b/src/ImageSharp/Formats/IImageFormat.cs
index 94191c149..3cd289df7 100644
--- a/src/ImageSharp/Formats/IImageFormat.cs
+++ b/src/ImageSharp/Formats/IImageFormat.cs
@@ -16,12 +16,12 @@ namespace SixLabors.ImageSharp.Formats
string Name { get; }
///
- /// Gets the default mimetype that the image foramt uses
+ /// Gets the default mimetype that the image format uses
///
string DefaultMimeType { get; }
///
- /// Gets all the mimetypes that have been used by this image foramt.
+ /// Gets all the mimetypes that have been used by this image format.
///
IEnumerable MimeTypes { get; }
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8.cs
index 5601a9436..60fec25d2 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8.cs
@@ -10,7 +10,7 @@ using System.Text;
namespace SixLabors.ImageSharp.Formats.Jpeg.Components
{
///
- /// Represents a Jpeg block with coefficiens.
+ /// Represents a Jpeg block with coefficients.
///
// ReSharper disable once InconsistentNaming
internal unsafe struct Block8x8 : IEquatable
@@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
}
///
- /// Gets or sets a value in a row+coulumn of the 8x8 block
+ /// Gets or sets a value in a row+column of the 8x8 block
///
/// The x position index in the row
/// The column index
@@ -283,7 +283,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
}
///
- /// Calculate the total sum of absoulute differences of elements in 'a' and 'b'.
+ /// Calculate the total sum of absolute differences of elements in 'a' and 'b'.
///
public static long TotalDifference(ref Block8x8 a, ref Block8x8 b)
{
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.CopyTo.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.CopyTo.cs
index b7dd125a8..6bf9c8483 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.CopyTo.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.CopyTo.cs
@@ -3,64 +3,41 @@
using System.Numerics;
using System.Runtime.CompilerServices;
-
using SixLabors.ImageSharp.Memory;
+// ReSharper disable UseObjectOrCollectionInitializer
// ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Formats.Jpeg.Components
{
internal partial struct Block8x8F
{
///
- /// Copy block data into the destination color buffer pixel area with the provided horizontal and vertical.
+ /// Copy block data into the destination color buffer pixel area with the provided horizontal and vertical scale factors.
///
+ [MethodImpl(InliningOptions.ShortMethod)]
public void CopyTo(in BufferArea area, int horizontalScale, int verticalScale)
{
if (horizontalScale == 1 && verticalScale == 1)
{
- this.CopyTo(area);
+ this.Copy1x1Scale(area);
return;
}
- else if (horizontalScale == 2 && verticalScale == 2)
+
+ if (horizontalScale == 2 && verticalScale == 2)
{
- this.CopyTo2x2(area);
+ this.Copy2x2Scale(area);
return;
}
- ref float destBase = ref area.GetReferenceToOrigin();
-
- // TODO: Optimize: implement all the cases with loopless special code! (T4?)
- for (int y = 0; y < 8; y++)
- {
- int yy = y * verticalScale;
- int y8 = y * 8;
-
- for (int x = 0; x < 8; x++)
- {
- int xx = x * horizontalScale;
-
- float value = this[y8 + x];
-
- for (int i = 0; i < verticalScale; i++)
- {
- int baseIdx = ((yy + i) * area.Stride) + xx;
-
- for (int j = 0; j < horizontalScale; j++)
- {
- // area[xx + j, yy + i] = value;
- Unsafe.Add(ref destBase, baseIdx + j) = value;
- }
- }
- }
- }
+ // TODO: Optimize: implement all cases with scale-specific, loopless code!
+ this.CopyArbitraryScale(area, horizontalScale, verticalScale);
}
- // [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void CopyTo(in BufferArea area)
+ public void Copy1x1Scale(in BufferArea destination)
{
ref byte selfBase = ref Unsafe.As(ref this);
- ref byte destBase = ref Unsafe.As(ref area.GetReferenceToOrigin());
- int destStride = area.Stride * sizeof(float);
+ ref byte destBase = ref Unsafe.As(ref destination.GetReferenceToOrigin());
+ int destStride = destination.Stride * sizeof(float);
CopyRowImpl(ref selfBase, ref destBase, destStride, 0);
CopyRowImpl(ref selfBase, ref destBase, destStride, 1);
@@ -80,76 +57,86 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
Unsafe.CopyBlock(ref d, ref s, 8 * sizeof(float));
}
- private void CopyTo2x2(in BufferArea area)
+ private void Copy2x2Scale(in BufferArea area)
{
- ref float destBase = ref area.GetReferenceToOrigin();
- int destStride = area.Stride;
-
- this.WidenCopyImpl2x2(ref destBase, 0, destStride);
- this.WidenCopyImpl2x2(ref destBase, 1, destStride);
- this.WidenCopyImpl2x2(ref destBase, 2, destStride);
- this.WidenCopyImpl2x2(ref destBase, 3, destStride);
- this.WidenCopyImpl2x2(ref destBase, 4, destStride);
- this.WidenCopyImpl2x2(ref destBase, 5, destStride);
- this.WidenCopyImpl2x2(ref destBase, 6, destStride);
- this.WidenCopyImpl2x2(ref destBase, 7, destStride);
+ ref Vector2 destBase = ref Unsafe.As(ref area.GetReferenceToOrigin());
+ int destStride = area.Stride / 2;
+
+ this.WidenCopyRowImpl2x2(ref destBase, 0, destStride);
+ this.WidenCopyRowImpl2x2(ref destBase, 1, destStride);
+ this.WidenCopyRowImpl2x2(ref destBase, 2, destStride);
+ this.WidenCopyRowImpl2x2(ref destBase, 3, destStride);
+ this.WidenCopyRowImpl2x2(ref destBase, 4, destStride);
+ this.WidenCopyRowImpl2x2(ref destBase, 5, destStride);
+ this.WidenCopyRowImpl2x2(ref destBase, 6, destStride);
+ this.WidenCopyRowImpl2x2(ref destBase, 7, destStride);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private void WidenCopyImpl2x2(ref float destBase, int row, int destStride)
+ private void WidenCopyRowImpl2x2(ref Vector2 destBase, int row, int destStride)
{
- ref Vector4 selfLeft = ref Unsafe.Add(ref this.V0L, 2 * row);
- ref Vector4 selfRight = ref Unsafe.Add(ref selfLeft, 1);
- ref float destLocalOrigo = ref Unsafe.Add(ref destBase, row * 2 * destStride);
-
- Unsafe.Add(ref destLocalOrigo, 0) = selfLeft.X;
- Unsafe.Add(ref destLocalOrigo, 1) = selfLeft.X;
- Unsafe.Add(ref destLocalOrigo, 2) = selfLeft.Y;
- Unsafe.Add(ref destLocalOrigo, 3) = selfLeft.Y;
- Unsafe.Add(ref destLocalOrigo, 4) = selfLeft.Z;
- Unsafe.Add(ref destLocalOrigo, 5) = selfLeft.Z;
- Unsafe.Add(ref destLocalOrigo, 6) = selfLeft.W;
- Unsafe.Add(ref destLocalOrigo, 7) = selfLeft.W;
-
- Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 0) = selfRight.X;
- Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 1) = selfRight.X;
- Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 2) = selfRight.Y;
- Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 3) = selfRight.Y;
- Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 4) = selfRight.Z;
- Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 5) = selfRight.Z;
- Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 6) = selfRight.W;
- Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 7) = selfRight.W;
-
- Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 0) = selfLeft.X;
- Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 1) = selfLeft.X;
- Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 2) = selfLeft.Y;
- Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 3) = selfLeft.Y;
- Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 4) = selfLeft.Z;
- Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 5) = selfLeft.Z;
- Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 6) = selfLeft.W;
- Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 7) = selfLeft.W;
-
- Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 0) = selfRight.X;
- Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 1) = selfRight.X;
- Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 2) = selfRight.Y;
- Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 3) = selfRight.Y;
- Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 4) = selfRight.Z;
- Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 5) = selfRight.Z;
- Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 6) = selfRight.W;
- Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 7) = selfRight.W;
+ ref Vector4 sLeft = ref Unsafe.Add(ref this.V0L, 2 * row);
+ ref Vector4 sRight = ref Unsafe.Add(ref sLeft, 1);
+
+ int offset = 2 * row * destStride;
+ ref Vector4 dTopLeft = ref Unsafe.As(ref Unsafe.Add(ref destBase, offset));
+ ref Vector4 dBottomLeft = ref Unsafe.As(ref Unsafe.Add(ref destBase, offset + destStride));
+
+ var xyLeft = new Vector4(sLeft.X);
+ xyLeft.Z = sLeft.Y;
+ xyLeft.W = sLeft.Y;
+
+ var zwLeft = new Vector4(sLeft.Z);
+ zwLeft.Z = sLeft.W;
+ zwLeft.W = sLeft.W;
+
+ var xyRight = new Vector4(sRight.X);
+ xyRight.Z = sRight.Y;
+ xyRight.W = sRight.Y;
+
+ var zwRight = new Vector4(sRight.Z);
+ zwRight.Z = sRight.W;
+ zwRight.W = sRight.W;
+
+ dTopLeft = xyLeft;
+ Unsafe.Add(ref dTopLeft, 1) = zwLeft;
+ Unsafe.Add(ref dTopLeft, 2) = xyRight;
+ Unsafe.Add(ref dTopLeft, 3) = zwRight;
+
+ dBottomLeft = xyLeft;
+ Unsafe.Add(ref dBottomLeft, 1) = zwLeft;
+ Unsafe.Add(ref dBottomLeft, 2) = xyRight;
+ Unsafe.Add(ref dBottomLeft, 3) = zwRight;
}
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static void WidenCopyImpl(ref Vector4 s, ref float destBase)
+ [MethodImpl(InliningOptions.ColdPath)]
+ private void CopyArbitraryScale(BufferArea area, int horizontalScale, int verticalScale)
{
- Unsafe.Add(ref destBase, 0) = s.X;
- Unsafe.Add(ref destBase, 1) = s.X;
- Unsafe.Add(ref destBase, 2) = s.Y;
- Unsafe.Add(ref destBase, 3) = s.Y;
- Unsafe.Add(ref destBase, 4) = s.Z;
- Unsafe.Add(ref destBase, 5) = s.Z;
- Unsafe.Add(ref destBase, 6) = s.W;
- Unsafe.Add(ref destBase, 7) = s.W;
+ ref float destBase = ref area.GetReferenceToOrigin();
+
+ for (int y = 0; y < 8; y++)
+ {
+ int yy = y * verticalScale;
+ int y8 = y * 8;
+
+ for (int x = 0; x < 8; x++)
+ {
+ int xx = x * horizontalScale;
+
+ float value = this[y8 + x];
+
+ for (int i = 0; i < verticalScale; i++)
+ {
+ int baseIdx = ((yy + i) * area.Stride) + xx;
+
+ for (int j = 0; j < horizontalScale; j++)
+ {
+ // area[xx + j, yy + i] = value;
+ Unsafe.Add(ref destBase, baseIdx + j) = value;
+ }
+ }
+ }
+ }
}
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs
index e83896f58..09ed6408d 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs
@@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
/// Transpose the block into the destination block.
///
/// The destination block
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [MethodImpl(InliningOptions.ShortMethod)]
public void TransposeInto(ref Block8x8F d)
{
d.V0L.X = V0L.X;
@@ -119,7 +119,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
///
/// AVX2-only variant for executing and in one step.
///
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [MethodImpl(InliningOptions.ShortMethod)]
public void NormalizeColorsAndRoundInplaceAvx2()
{
Vector off = new Vector(128f);
@@ -154,7 +154,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
///
/// Fill the block from 'source' doing short -> float conversion.
///
- public void LoadFrom(ref Block8x8 source)
+ public void LoadFromInt16Scalar(ref Block8x8 source)
{
ref short selfRef = ref Unsafe.As(ref source);
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt
index 82d82ef0c..f93ee6522 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt
+++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt
@@ -30,7 +30,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
/// Transpose the block into the destination block.
///
/// The destination block
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [MethodImpl(InliningOptions.ShortMethod)]
public void TransposeInto(ref Block8x8F d)
{
<#
@@ -82,7 +82,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
///
/// AVX2-only variant for executing and in one step.
///
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [MethodImpl(InliningOptions.ShortMethod)]
public void NormalizeColorsAndRoundInplaceAvx2()
{
Vector off = new Vector(128f);
@@ -104,7 +104,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
///
/// Fill the block from 'source' doing short -> float conversion.
///
- public void LoadFrom(ref Block8x8 source)
+ public void LoadFromInt16Scalar(ref Block8x8 source)
{
ref short selfRef = ref Unsafe.As(ref source);
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs
index 59fc234c4..2be5addc2 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs
@@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
/// The float value at the specified index
public float this[int idx]
{
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [MethodImpl(InliningOptions.ShortMethod)]
get
{
GuardBlockIndex(idx);
@@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
return Unsafe.Add(ref selfRef, idx);
}
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [MethodImpl(InliningOptions.ShortMethod)]
set
{
GuardBlockIndex(idx);
@@ -149,7 +149,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
///
/// Fill the block with defaults (zeroes)
///
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [MethodImpl(InliningOptions.ShortMethod)]
public void Clear()
{
// The cheapest way to do this in C#:
@@ -160,7 +160,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
/// Load raw 32bit floating point data from source
///
/// Source
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [MethodImpl(InliningOptions.ShortMethod)]
public void LoadFrom(Span source)
{
ref byte s = ref Unsafe.As(ref MemoryMarshal.GetReference(source));
@@ -174,7 +174,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
///
/// Block pointer
/// Source
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [MethodImpl(InliningOptions.ShortMethod)]
public static unsafe void LoadFrom(Block8x8F* blockPtr, Span source)
{
blockPtr->LoadFrom(source);
@@ -200,7 +200,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
/// Copy raw 32bit floating point data to dest
///
/// Destination
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [MethodImpl(InliningOptions.ShortMethod)]
public void CopyTo(Span dest)
{
ref byte d = ref Unsafe.As(ref MemoryMarshal.GetReference(dest));
@@ -214,7 +214,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
///
/// Pointer to block
/// Destination
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [MethodImpl(InliningOptions.ShortMethod)]
public static unsafe void CopyTo(Block8x8F* blockPtr, Span dest)
{
float* fPtr = (float*)blockPtr;
@@ -230,7 +230,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
///
/// Block pointer
/// Destination
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [MethodImpl(InliningOptions.ShortMethod)]
public static unsafe void CopyTo(Block8x8F* blockPtr, Span dest)
{
blockPtr->CopyTo(dest);
@@ -240,7 +240,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
/// Copy raw 32bit floating point data to dest
///
/// Destination
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [MethodImpl(InliningOptions.ShortMethod)]
public unsafe void CopyTo(float[] dest)
{
fixed (void* ptr = &this.V0L)
@@ -276,7 +276,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
/// Multiply all elements of the block.
///
/// The value to multiply by
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [MethodImpl(InliningOptions.ShortMethod)]
public void MultiplyInplace(float value)
{
this.V0L *= value;
@@ -300,7 +300,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
///
/// Multiply all elements of the block by the corresponding elements of 'other'
///
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [MethodImpl(InliningOptions.ShortMethod)]
public void MultiplyInplace(ref Block8x8F other)
{
this.V0L *= other.V0L;
@@ -325,7 +325,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
/// Adds a vector to all elements of the block.
///
/// The added vector
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [MethodImpl(InliningOptions.ShortMethod)]
public void AddToAllInplace(Vector4 diff)
{
this.V0L += diff;
@@ -395,7 +395,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
}
///
- /// Scales the 16x16 region represented by the 4 source blocks to the 8x8 DST block.
+ /// Scales the 16x16 region represented by the 4 source blocks to the 8x8 DST block.
///
/// The destination block.
/// The source block.
@@ -420,7 +420,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
}
}
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [MethodImpl(InliningOptions.ShortMethod)]
private static void DivideRoundAll(ref Block8x8F a, ref Block8x8F b)
{
a.V0L = DivideRound(a.V0L, b.V0L);
@@ -493,6 +493,51 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
}
}
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public void LoadFrom(ref Block8x8 source)
+ {
+#if SUPPORTS_EXTENDED_INTRINSICS
+ if (SimdUtils.IsAvx2CompatibleArchitecture)
+ {
+ this.LoadFromInt16ExtendedAvx2(ref source);
+ return;
+ }
+#endif
+ this.LoadFromInt16Scalar(ref source);
+ }
+
+ ///
+ /// Loads values from using extended AVX2 intrinsics.
+ ///
+ /// The source
+ public void LoadFromInt16ExtendedAvx2(ref Block8x8 source)
+ {
+ DebugGuard.IsTrue(
+ SimdUtils.IsAvx2CompatibleArchitecture,
+ "LoadFromUInt16ExtendedAvx2 only works on AVX2 compatible architecture!");
+
+ ref Vector sRef = ref Unsafe.As>(ref source);
+ ref Vector dRef = ref Unsafe.As>(ref this);
+
+ // Vector.Count == 16 on AVX2
+ // We can process 2 block rows in a single step
+ SimdUtils.ExtendedIntrinsics.ConvertToSingle(sRef, out Vector top, out Vector bottom);
+ dRef = top;
+ Unsafe.Add(ref dRef, 1) = bottom;
+
+ SimdUtils.ExtendedIntrinsics.ConvertToSingle(Unsafe.Add(ref sRef, 1), out top, out bottom);
+ Unsafe.Add(ref dRef, 2) = top;
+ Unsafe.Add(ref dRef, 3) = bottom;
+
+ SimdUtils.ExtendedIntrinsics.ConvertToSingle(Unsafe.Add(ref sRef, 2), out top, out bottom);
+ Unsafe.Add(ref dRef, 4) = top;
+ Unsafe.Add(ref dRef, 5) = bottom;
+
+ SimdUtils.ExtendedIntrinsics.ConvertToSingle(Unsafe.Add(ref sRef, 3), out top, out bottom);
+ Unsafe.Add(ref dRef, 6) = top;
+ Unsafe.Add(ref dRef, 7) = bottom;
+ }
+
///
public override string ToString()
{
@@ -511,7 +556,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
return sb.ToString();
}
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [MethodImpl(InliningOptions.ShortMethod)]
private static Vector NormalizeAndRound(Vector row, Vector off, Vector max)
{
row += off;
@@ -520,13 +565,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
return row.FastRound();
}
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [MethodImpl(InliningOptions.ShortMethod)]
private static Vector4 DivideRound(Vector4 dividend, Vector4 divisor)
{
// sign(dividend) = max(min(dividend, 1), -1)
var sign = Vector4.Clamp(dividend, NegativeOne, Vector4.One);
- // AlmostRound(dividend/divisor) = dividend/divisior + 0.5*sign(dividend)
+ // AlmostRound(dividend/divisor) = dividend/divisor + 0.5*sign(dividend)
return (dividend / divisor) + (sign * Offset);
}
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScale.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScale.cs
index 5d7a31a12..7424145c3 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScale.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScale.cs
@@ -3,6 +3,8 @@
using System;
using System.Numerics;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
{
@@ -17,24 +19,17 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
public override void ConvertToRgba(in ComponentValues values, Span result)
{
- // TODO: We can optimize a lot here with Vector and SRCS.Unsafe()!
- ReadOnlySpan yVals = values.Component0;
-
- var v = new Vector4(0, 0, 0, 1);
-
var scale = new Vector4(1 / 255F, 1 / 255F, 1 / 255F, 1F);
+ ref float sBase = ref MemoryMarshal.GetReference(values.Component0);
+ ref Vector4 dBase = ref MemoryMarshal.GetReference(result);
+
for (int i = 0; i < result.Length; i++)
{
- float y = yVals[i];
-
- v.X = y;
- v.Y = y;
- v.Z = y;
-
+ var v = new Vector4(Unsafe.Add(ref sBase, i));
+ v.W = 1f;
v *= scale;
-
- result[i] = v;
+ Unsafe.Add(ref dBase, i) = v;
}
}
}
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs
index 1dc72aaf5..23aa1acbe 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs
@@ -32,11 +32,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
}
///
- /// SIMD convert using buffers of sizes divisable by 8.
+ /// SIMD convert using buffers of sizes divisible by 8.
///
internal static void ConvertCore(in ComponentValues values, Span result)
{
- DebugGuard.IsTrue(result.Length % 8 == 0, nameof(result), "result.Length should be divisable by 8!");
+ DebugGuard.IsTrue(result.Length % 8 == 0, nameof(result), "result.Length should be divisible by 8!");
ref Vector4Pair yBase =
ref Unsafe.As(ref MemoryMarshal.GetReference(values.Component0));
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs
index 46644258b..f0a70a6f3 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs
@@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
}
///
- /// SIMD convert using buffers of sizes divisable by 8.
+ /// SIMD convert using buffers of sizes divisible by 8.
///
internal static void ConvertCore(in ComponentValues values, Span result)
{
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs
index 456636dc3..a44ebf89d 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs
@@ -18,7 +18,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
internal abstract partial class JpegColorConverter
{
///
- /// The avalilable converters
+ /// The available converters
///
private static readonly JpegColorConverter[] Converters =
{
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTable.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTable.cs
index 24d570bf1..9e134746b 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTable.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTable.cs
@@ -91,7 +91,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
}
// Figure F.15: generate decoding tables for bit-sequential decoding.
- // Compute largest code + 1 for this size. preshifted as we needit later.
+ // Compute largest code + 1 for this size. preshifted as we need it later.
Unsafe.Add(ref maxcodeRef, k) = code << (16 - k);
code <<= 1;
}
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/IJpegComponent.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/IJpegComponent.cs
index c03398033..2492a985a 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/IJpegComponent.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/IJpegComponent.cs
@@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Memory;
-using SixLabors.Memory;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
@@ -43,16 +42,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
///
/// Gets the storing the "raw" frequency-domain decoded + unzigged blocks.
- /// We need to apply IDCT and dequantiazition to transform them into color-space blocks.
+ /// We need to apply IDCT and dequantization to transform them into color-space blocks.
///
Buffer2D SpectralBlocks { get; }
-
- ///
- /// Gets a reference to the at the given row and column index from
- ///
- /// The column
- /// The row
- /// The
- ref Block8x8 GetBlockReference(int column, int row);
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/IRawJpegData.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/IRawJpegData.cs
index dace78b33..1454bb5b1 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/IRawJpegData.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/IRawJpegData.cs
@@ -20,7 +20,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
Size ImageSizeInPixels { get; }
///
- /// Gets the number of coponents.
+ /// Gets the number of components.
///
int ComponentCount { get; }
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JFifMarker.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JFifMarker.cs
index f153ce062..4bff49248 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JFifMarker.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JFifMarker.cs
@@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
/// The minor version
/// The units for the density values
/// The horizontal pixel density
- /// The veritcal pixel density
+ /// The vertical pixel density
private JFifMarker(byte majorVersion, byte minorVersion, byte densityUnits, short xDensity, short yDensity)
{
Guard.MustBeGreaterThan(xDensity, 0, nameof(xDensity));
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockPostProcessor.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockPostProcessor.cs
index 0108e3081..da4b2847b 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockPostProcessor.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockPostProcessor.cs
@@ -59,7 +59,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
/// - Dequantize
/// - Applying IDCT
/// - Level shift by +128, clip to [0, 255]
- /// - Copy the resultin color values into 'destArea' scaling up the block by amount defined in
+ /// - Copy the resulting color values into 'destArea' scaling up the block by amount defined in
///
/// The source block.
/// The destination buffer area.
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponent.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponent.cs
index 65a584c4f..ef03582d6 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponent.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponent.cs
@@ -128,21 +128,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
this.SubSamplingDivisors = c0.SamplingFactors.DivideBy(this.SamplingFactors);
}
- this.SpectralBlocks = this.memoryAllocator.Allocate2D(blocksPerColumnForMcu, blocksPerLineForMcu + 1, AllocationOptions.Clean);
- }
+ int totalNumberOfBlocks = blocksPerColumnForMcu * (blocksPerLineForMcu + 1);
+ int width = this.WidthInBlocks + 1;
+ int height = totalNumberOfBlocks / width;
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public ref Block8x8 GetBlockReference(int column, int row)
- {
- int offset = ((this.WidthInBlocks + 1) * row) + column;
- return ref Unsafe.Add(ref MemoryMarshal.GetReference(this.SpectralBlocks.GetSpan()), offset);
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public ref short GetBlockDataReference(int column, int row)
- {
- ref Block8x8 blockRef = ref this.GetBlockReference(column, row);
- return ref Unsafe.As(ref blockRef);
+ this.SpectralBlocks = this.memoryAllocator.Allocate2D(width, height, AllocationOptions.Clean);
}
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs
index 890f40259..94ec600dd 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponentPostProcessor.cs
@@ -2,6 +2,8 @@
// Licensed under the Apache License, Version 2.0.
using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Memory;
using SixLabors.Memory;
@@ -20,7 +22,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
private int currentComponentRowInBlocks;
///
- /// The size of the area in corrsponding to one 8x8 Jpeg block
+ /// The size of the area in corresponding to one 8x8 Jpeg block
///
private readonly Size blockAreaSize;
@@ -88,12 +90,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
int yBuffer = y * this.blockAreaSize.Height;
- for (int x = 0; x < this.SizeInBlocks.Width; x++)
- {
- int xBlock = x;
- int xBuffer = x * this.blockAreaSize.Width;
+ Span blockRow = this.Component.SpectralBlocks.GetRowSpan(yBlock);
+
+ ref Block8x8 blockRowBase = ref MemoryMarshal.GetReference(blockRow);
- ref Block8x8 block = ref this.Component.GetBlockReference(xBlock, yBlock);
+ for (int xBlock = 0; xBlock < this.SizeInBlocks.Width; xBlock++)
+ {
+ ref Block8x8 block = ref Unsafe.Add(ref blockRowBase, xBlock);
+ int xBuffer = xBlock * this.blockAreaSize.Width;
BufferArea destArea = this.ColorBuffer.GetArea(
xBuffer,
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ScanDecoder.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ScanDecoder.cs
index 351e45348..48abca2a4 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ScanDecoder.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ScanDecoder.cs
@@ -1,8 +1,10 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
+using System;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.IO;
+using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
{
@@ -142,7 +144,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
}
}
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [MethodImpl(InliningOptions.ShortMethod)]
private static uint LRot(uint x, int y) => (x << y) | (x >> (32 - y));
private void ParseBaselineData()
@@ -179,10 +181,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
int h = component.HorizontalSamplingFactor;
int v = component.VerticalSamplingFactor;
+ int mcuRow = mcu / mcusPerLine;
+
// Scan out an mcu's worth of this component; that's just determined
// by the basic H and V specified for the component
for (int y = 0; y < v; y++)
{
+ int blockRow = (mcuRow * v) + y;
+ Span blockSpan = component.SpectralBlocks.GetRowSpan(blockRow);
for (int x = 0; x < h; x++)
{
if (this.eof)
@@ -190,15 +196,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
return;
}
- int mcuRow = mcu / mcusPerLine;
int mcuCol = mcu % mcusPerLine;
- int blockRow = (mcuRow * v) + y;
int blockCol = (mcuCol * h) + x;
this.DecodeBlockBaseline(
component,
- blockRow,
- blockCol,
+ ref blockSpan[blockCol],
ref dcHuffmanTable,
ref acHuffmanTable,
ref fastACRef);
@@ -236,6 +239,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
int mcu = 0;
for (int j = 0; j < h; j++)
{
+ // TODO: Isn't blockRow == j actually?
+ int blockRow = mcu / w;
+ Span blockSpan = component.SpectralBlocks.GetRowSpan(blockRow);
+
for (int i = 0; i < w; i++)
{
if (this.eof)
@@ -243,13 +250,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
return;
}
- int blockRow = mcu / w;
+ // TODO: Isn't blockCol == i actually?
int blockCol = mcu % w;
this.DecodeBlockBaseline(
component,
- blockRow,
- blockCol,
+ ref blockSpan[blockCol],
ref dcHuffmanTable,
ref acHuffmanTable,
ref fastACRef);
@@ -299,6 +305,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
// by the basic H and V specified for the component
for (int y = 0; y < v; y++)
{
+ int mcuRow = mcu / mcusPerLine;
+ int blockRow = (mcuRow * v) + y;
+ Span blockSpan = component.SpectralBlocks.GetRowSpan(blockRow);
+
for (int x = 0; x < h; x++)
{
if (this.eof)
@@ -306,15 +316,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
return;
}
- int mcuRow = mcu / mcusPerLine;
int mcuCol = mcu % mcusPerLine;
- int blockRow = (mcuRow * v) + y;
int blockCol = (mcuCol * h) + x;
this.DecodeBlockProgressiveDC(
component,
- blockRow,
- blockCol,
+ ref blockSpan[blockCol],
ref dcHuffmanTable);
}
}
@@ -351,6 +358,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
int mcu = 0;
for (int j = 0; j < h; j++)
{
+ // TODO: isn't blockRow == j actually?
+ int blockRow = mcu / w;
+ Span blockSpan = component.SpectralBlocks.GetRowSpan(blockRow);
+
for (int i = 0; i < w; i++)
{
if (this.eof)
@@ -358,23 +369,22 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
return;
}
- int blockRow = mcu / w;
+ // TODO: isn't blockCol == i actually?
int blockCol = mcu % w;
+ ref Block8x8 block = ref blockSpan[blockCol];
+
if (this.spectralStart == 0)
{
this.DecodeBlockProgressiveDC(
component,
- blockRow,
- blockCol,
+ ref block,
ref dcHuffmanTable);
}
else
{
this.DecodeBlockProgressiveAC(
- component,
- blockRow,
- blockCol,
+ ref block,
ref acHuffmanTable,
ref fastACRef);
}
@@ -391,8 +401,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
private void DecodeBlockBaseline(
JpegComponent component,
- int row,
- int col,
+ ref Block8x8 block,
ref HuffmanTable dcTable,
ref HuffmanTable acTable,
ref short fastACRef)
@@ -405,7 +414,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
JpegThrowHelper.ThrowBadHuffmanCode();
}
- ref short blockDataRef = ref component.GetBlockDataReference(col, row);
+ ref short blockDataRef = ref Unsafe.As(ref block);
int diff = t != 0 ? this.ExtendReceive(t) : 0;
int dc = component.DcPredictor + diff;
@@ -470,8 +479,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
private void DecodeBlockProgressiveDC(
JpegComponent component,
- int row,
- int col,
+ ref Block8x8 block,
ref HuffmanTable dcTable)
{
if (this.spectralEnd != 0)
@@ -481,7 +489,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
this.CheckBits();
- ref short blockDataRef = ref component.GetBlockDataReference(col, row);
+ ref short blockDataRef = ref Unsafe.As(ref block);
if (this.successiveHigh == 0)
{
@@ -505,9 +513,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
}
private void DecodeBlockProgressiveAC(
- JpegComponent component,
- int row,
- int col,
+ ref Block8x8 block,
ref HuffmanTable acTable,
ref short fastACRef)
{
@@ -516,7 +522,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
JpegThrowHelper.ThrowImageFormatException("Can't merge DC and AC.");
}
- ref short blockDataRef = ref component.GetBlockDataReference(col, row);
+ ref short blockDataRef = ref Unsafe.As(ref block);
if (this.successiveHigh == 0)
{
@@ -749,7 +755,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
[MethodImpl(InliningOptions.ColdPath)]
private void FillBuffer()
{
- // Attempt to load at least the minimum nbumber of required bits into the buffer.
+ // Attempt to load at least the minimum number of required bits into the buffer.
// We fail to do so only if we hit a marker or reach the end of the input stream.
do
{
@@ -906,7 +912,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
}
// If it's NOT a restart, then just bail, so we get corrupt data rather than no data.
- // Reset the stream to before any bad markers to ensure we can read sucessive segments.
+ // Reset the stream to before any bad markers to ensure we can read successive segments.
if (this.badMarker)
{
this.stream.Position = this.markerPosition;
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Encoder/RgbToYCbCrTables.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/RgbToYCbCrTables.cs
index a0cc9ee8e..cb0810985 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Encoder/RgbToYCbCrTables.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Encoder/RgbToYCbCrTables.cs
@@ -63,7 +63,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder
///
/// Initializes the YCbCr tables
///
- /// The intialized
+ /// The initialized
public static RgbToYCbCrTables Create()
{
RgbToYCbCrTables tables = default;
diff --git a/src/ImageSharp/Formats/Jpeg/Components/GenericBlock8x8.cs b/src/ImageSharp/Formats/Jpeg/Components/GenericBlock8x8.cs
index 2e20da266..c795ccc8b 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/GenericBlock8x8.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/GenericBlock8x8.cs
@@ -44,7 +44,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
///
/// FOR TESTING ONLY!
- /// Gets or sets a value in a row+coulumn of the 8x8 block
+ /// Gets or sets a value in a row+column of the 8x8 block
///
/// The x position index in the row
/// The column index
diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
index 36246c682..67f665576 100644
--- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
+++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
@@ -51,12 +51,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
private readonly byte[] markerBuffer = new byte[2];
///
- /// The DC HUffman tables
+ /// The DC Huffman tables
///
private HuffmanTables dcHuffmanTables;
///
- /// The AC HUffman tables
+ /// The AC Huffman tables
///
private HuffmanTables acHuffmanTables;
@@ -913,7 +913,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
/// The table index
/// The codelengths
/// The values
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [MethodImpl(InliningOptions.ShortMethod)]
private void BuildHuffmanTable(HuffmanTables tables, int index, ReadOnlySpan codeLengths, ReadOnlySpan values)
=> tables[index] = new HuffmanTable(this.configuration.MemoryAllocator, codeLengths, values);
@@ -921,7 +921,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
/// Reads a from the stream advancing it by two bytes
///
/// The
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [MethodImpl(InliningOptions.ShortMethod)]
private ushort ReadUint16()
{
this.InputStream.Read(this.markerBuffer, 0, 2);
@@ -936,12 +936,18 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
private Image PostProcessIntoImage()
where TPixel : struct, IPixel
{
+ var image = Image.CreateUninitialized(
+ this.configuration,
+ this.ImageWidth,
+ this.ImageHeight,
+ this.MetaData);
+
using (var postProcessor = new JpegImagePostProcessor(this.configuration, this))
{
- var image = new Image(this.configuration, this.ImageWidth, this.ImageHeight, this.MetaData);
postProcessor.PostProcess(image.Frames.RootFrame);
- return image;
}
+
+ return image;
}
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Formats/Png/Chunks/PhysicalChunkData.cs b/src/ImageSharp/Formats/Png/Chunks/PhysicalChunkData.cs
index 07fc688d5..6ab0dd657 100644
--- a/src/ImageSharp/Formats/Png/Chunks/PhysicalChunkData.cs
+++ b/src/ImageSharp/Formats/Png/Chunks/PhysicalChunkData.cs
@@ -53,7 +53,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Chunks
///
/// Constructs the PngPhysicalChunkData from the provided metadata.
- /// If the resolution units are not in meters, they are automatically convereted.
+ /// If the resolution units are not in meters, they are automatically converted.
///
/// The metadata.
/// The constructed PngPhysicalChunkData instance.
diff --git a/src/ImageSharp/Formats/Png/Filters/PaethFilter.cs b/src/ImageSharp/Formats/Png/Filters/PaethFilter.cs
index 4ffc39bdb..4cd61e043 100644
--- a/src/ImageSharp/Formats/Png/Filters/PaethFilter.cs
+++ b/src/ImageSharp/Formats/Png/Filters/PaethFilter.cs
@@ -30,7 +30,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Filters
ref byte prevBaseRef = ref MemoryMarshal.GetReference(previousScanline);
// Paeth(x) + PaethPredictor(Raw(x-bpp), Prior(x), Prior(x-bpp))
- int offset = bytesPerPixel + 1; // Add one bcause x starts at one.
+ int offset = bytesPerPixel + 1; // Add one because x starts at one.
int x = 1;
for (; x < offset; x++)
{
diff --git a/src/ImageSharp/Formats/Png/IPngDecoderOptions.cs b/src/ImageSharp/Formats/Png/IPngDecoderOptions.cs
index bd0b93205..5b650ac2a 100644
--- a/src/ImageSharp/Formats/Png/IPngDecoderOptions.cs
+++ b/src/ImageSharp/Formats/Png/IPngDecoderOptions.cs
@@ -6,7 +6,7 @@ using System.Text;
namespace SixLabors.ImageSharp.Formats.Png
{
///
- /// The optioas for decoding png images
+ /// The options for decoding png images
///
internal interface IPngDecoderOptions
{
diff --git a/src/ImageSharp/IImageInfo.cs b/src/ImageSharp/IImageInfo.cs
index 25d5ec7ca..6e64aa679 100644
--- a/src/ImageSharp/IImageInfo.cs
+++ b/src/ImageSharp/IImageInfo.cs
@@ -7,7 +7,7 @@ using SixLabors.ImageSharp.MetaData;
namespace SixLabors.ImageSharp
{
///
- /// Encapsulates properties that descibe basic image information including dimensions, pixel type information
+ /// Encapsulates properties that describe basic image information including dimensions, pixel type information
/// and additional metadata
///
public interface IImageInfo
diff --git a/src/ImageSharp/Image.Decode.cs b/src/ImageSharp/Image.Decode.cs
index 8b9f3fdb5..ffdab25e2 100644
--- a/src/ImageSharp/Image.Decode.cs
+++ b/src/ImageSharp/Image.Decode.cs
@@ -5,6 +5,7 @@ using System.IO;
using System.Linq;
using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Memory;
+using SixLabors.ImageSharp.MetaData;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
@@ -15,6 +16,29 @@ namespace SixLabors.ImageSharp
///
public static partial class Image
{
+ ///
+ /// Creates an instance backed by an uninitialized memory buffer.
+ /// This is an optimized creation method intended to be used by decoders.
+ /// The image might be filled with memory garbage.
+ ///
+ /// The pixel type
+ /// The
+ /// The width of the image
+ /// The height of the image
+ /// The
+ /// The result
+ internal static Image CreateUninitialized(
+ Configuration configuration,
+ int width,
+ int height,
+ ImageMetaData metadata)
+ where TPixel : struct, IPixel
+ {
+ Buffer2D uninitializedMemoryBuffer =
+ configuration.MemoryAllocator.Allocate2D(width, height);
+ return new Image(configuration, uninitializedMemoryBuffer.MemorySource, width, height, metadata);
+ }
+
///
/// By reading the header on the provided stream this calculates the images format.
///
diff --git a/src/ImageSharp/Image.WrapMemory.cs b/src/ImageSharp/Image.WrapMemory.cs
index e8d9ab754..c2935bed9 100644
--- a/src/ImageSharp/Image.WrapMemory.cs
+++ b/src/ImageSharp/Image.WrapMemory.cs
@@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp
public static partial class Image
{
///
- /// Wraps an existing contigous memory area of 'width'x'height' pixels,
+ /// Wraps an existing contiguous memory area of 'width' x 'height' pixels,
/// allowing to view/manipulate it as an ImageSharp instance.
///
/// The pixel type
@@ -40,7 +40,7 @@ namespace SixLabors.ImageSharp
}
///
- /// Wraps an existing contigous memory area of 'width'x'height' pixels,
+ /// Wraps an existing contiguous memory area of 'width' x 'height' pixels,
/// allowing to view/manipulate it as an ImageSharp instance.
///
/// The pixel type
@@ -60,7 +60,7 @@ namespace SixLabors.ImageSharp
}
///
- /// Wraps an existing contigous memory area of 'width'x'height' pixels,
+ /// Wraps an existing contiguous memory area of 'width' x 'height' pixels,
/// allowing to view/manipulate it as an ImageSharp instance.
/// The memory is being observed, the caller remains responsible for managing it's lifecycle.
///
@@ -79,15 +79,15 @@ namespace SixLabors.ImageSharp
}
///
- /// Wraps an existing contigous memory area of 'width'x'height' pixels,
+ /// Wraps an existing contiguous memory area of 'width' x 'height' pixels,
/// allowing to view/manipulate it as an ImageSharp instance.
- /// The ownership of the is being transfered to the new instance,
+ /// The ownership of the is being transferred to the new instance,
/// meaning that the caller is not allowed to dispose .
/// It will be disposed together with the result image.
///
/// The pixel type
/// The
- /// The that is being transfered to the image
+ /// The that is being transferred to the image
/// The width of the memory image
/// The height of the memory image
/// The
@@ -105,15 +105,15 @@ namespace SixLabors.ImageSharp
}
///
- /// Wraps an existing contigous memory area of 'width'x'height' pixels,
+ /// Wraps an existing contiguous memory area of 'width' x 'height' pixels,
/// allowing to view/manipulate it as an ImageSharp instance.
- /// The ownership of the is being transfered to the new instance,
+ /// The ownership of the is being transferred to the new instance,
/// meaning that the caller is not allowed to dispose .
/// It will be disposed together with the result image.
///
/// The pixel type
/// The
- /// The that is being transfered to the image
+ /// The that is being transferred to the image
/// The width of the memory image
/// The height of the memory image
/// An instance
@@ -128,14 +128,14 @@ namespace SixLabors.ImageSharp
}
///
- /// Wraps an existing contigous memory area of 'width'x'height' pixels,
+ /// Wraps an existing contiguous memory area of 'width' x 'height' pixels,
/// allowing to view/manipulate it as an ImageSharp instance.
- /// The ownership of the is being transfered to the new instance,
+ /// The ownership of the is being transferred to the new instance,
/// meaning that the caller is not allowed to dispose .
/// It will be disposed together with the result image.
///
/// The pixel type
- /// The that is being transfered to the image
+ /// The that is being transferred to the image
/// The width of the memory image
/// The height of the memory image
/// An instance
diff --git a/src/ImageSharp/ImageExtensions.cs b/src/ImageSharp/ImageExtensions.cs
index e579bec1a..cbf93275c 100644
--- a/src/ImageSharp/ImageExtensions.cs
+++ b/src/ImageSharp/ImageExtensions.cs
@@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp
if (format is null)
{
var sb = new StringBuilder();
- sb.AppendLine($"Can't find a format that is associated with the file extention '{ext}'. Registered formats with there extensions include:");
+ sb.AppendLine($"Can't find a format that is associated with the file extension '{ext}'. Registered formats with there extensions include:");
foreach (IImageFormat fmt in source.GetConfiguration().ImageFormats)
{
sb.AppendLine($" - {fmt.Name} : {string.Join(", ", fmt.FileExtensions)}");
@@ -47,7 +47,7 @@ namespace SixLabors.ImageSharp
if (encoder is null)
{
var sb = new StringBuilder();
- sb.AppendLine($"Can't find encoder for file extention '{ext}' using image format '{format.Name}'. Registered encoders include:");
+ sb.AppendLine($"Can't find encoder for file extension '{ext}' using image format '{format.Name}'. Registered encoders include:");
foreach (KeyValuePair enc in source.GetConfiguration().ImageFormatsManager.ImageEncoders)
{
sb.AppendLine($" - {enc.Key} : {enc.Value.GetType().Name}");
diff --git a/src/ImageSharp/Image{TPixel}.cs b/src/ImageSharp/Image{TPixel}.cs
index 9d4c1ef0b..178194b21 100644
--- a/src/ImageSharp/Image{TPixel}.cs
+++ b/src/ImageSharp/Image{TPixel}.cs
@@ -186,7 +186,7 @@ namespace SixLabors.ImageSharp
public Image Clone() => this.Clone(this.configuration);
///
- /// Clones the current image with the given configueation.
+ /// Clones the current image with the given configuration.
///
/// The configuration providing initialization code which allows extending the library.
/// Returns a new with all the same pixel data as the original.
diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs
index 3326c3217..100649c0f 100644
--- a/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs
+++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs
@@ -124,7 +124,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif
private byte ConvertToByte(ReadOnlySpan buffer) => buffer[0];
- private unsafe string ConvertToString(ReadOnlySpan buffer)
+ private string ConvertToString(ReadOnlySpan buffer)
{
int nullCharIndex = buffer.IndexOf((byte)0);
@@ -382,13 +382,13 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif
this.invalidTags.Add(tag);
}
+ [MethodImpl(InliningOptions.ShortMethod)]
private TEnum ToEnum(int value, TEnum defaultValue)
where TEnum : struct
{
- var enumValue = (TEnum)(object)value;
- if (Enum.GetValues(typeof(TEnum)).Cast().Any(v => v.Equals(enumValue)))
+ if (EnumHelper.IsDefined(value))
{
- return enumValue;
+ return Unsafe.As(ref value);
}
return defaultValue;
@@ -557,5 +557,18 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif
? BinaryPrimitives.ReadInt16BigEndian(buffer)
: BinaryPrimitives.ReadInt16LittleEndian(buffer);
}
+
+ private class EnumHelper
+ where TEnum : struct
+ {
+ private static readonly int[] Values = Enum.GetValues(typeof(TEnum)).Cast()
+ .Select(e => Convert.ToInt32(e)).OrderBy(e => e).ToArray();
+
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public static bool IsDefined(int value)
+ {
+ return Array.BinarySearch(Values, value) >= 0;
+ }
+ }
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.Curves.cs b/src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.Curves.cs
index ee91ad7a1..b27083dc4 100644
--- a/src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.Curves.cs
+++ b/src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.Curves.cs
@@ -41,10 +41,10 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
public IccResponseCurve ReadResponseCurve(int channelCount)
{
var type = (IccCurveMeasurementEncodings)this.ReadUInt32();
- uint[] measurment = new uint[channelCount];
+ uint[] measurement = new uint[channelCount];
for (int i = 0; i < channelCount; i++)
{
- measurment[i] = this.ReadUInt32();
+ measurement[i] = this.ReadUInt32();
}
Vector3[] xyzValues = new Vector3[channelCount];
@@ -56,8 +56,8 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
IccResponseNumber[][] response = new IccResponseNumber[channelCount][];
for (int i = 0; i < channelCount; i++)
{
- response[i] = new IccResponseNumber[measurment[i]];
- for (uint j = 0; j < measurment[i]; j++)
+ response[i] = new IccResponseNumber[measurement[i]];
+ for (uint j = 0; j < measurement[i]; j++)
{
response[i][j] = this.ReadResponseNumber();
}
diff --git a/src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.TagDataEntry.cs b/src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.TagDataEntry.cs
index e41d9b3b8..c572b7f21 100644
--- a/src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.TagDataEntry.cs
+++ b/src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.TagDataEntry.cs
@@ -628,16 +628,16 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
{
int start = this.currentIndex - 8; // 8 is the tag header size
ushort channelCount = this.ReadUInt16();
- ushort measurmentCount = this.ReadUInt16();
+ ushort measurementCount = this.ReadUInt16();
- uint[] offset = new uint[measurmentCount];
- for (int i = 0; i < measurmentCount; i++)
+ uint[] offset = new uint[measurementCount];
+ for (int i = 0; i < measurementCount; i++)
{
offset[i] = this.ReadUInt32();
}
- var curves = new IccResponseCurve[measurmentCount];
- for (int i = 0; i < measurmentCount; i++)
+ var curves = new IccResponseCurve[measurementCount];
+ for (int i = 0; i < measurementCount; i++)
{
this.currentIndex = (int)(start + offset[i]);
curves[i] = this.ReadResponseCurve(channelCount);
diff --git a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileClass.cs b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileClass.cs
index 71c27ca61..8f0427db2 100644
--- a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileClass.cs
+++ b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileClass.cs
@@ -39,15 +39,15 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
///
/// This profile provides the relevant information to perform a transformation
- /// between colour encodings and the PCS. This type of profile is based on
- /// modelling rather than device measurement or characterization data.
+ /// between color encodings and the PCS. This type of profile is based on
+ /// modeling rather than device measurement or characterization data.
/// ColorSpace profiles may be embedded in images.
///
ColorSpace = 0x73706163, // spac
///
/// This profile represents abstract transforms and does not represent any
- /// device model. Colour transformations using Abstract profiles are performed
+ /// device model. Color transformations using Abstract profiles are performed
/// from PCS to PCS. Abstract profiles cannot be embedded in images.
///
Abstract = 0x61627374, // abst
@@ -55,8 +55,8 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
///
/// NamedColor profiles can be thought of as sibling profiles to device profiles.
/// For a given device there would be one or more device profiles to handle
- /// process colour conversions and one or more named colour profiles to handle
- /// named colours.
+ /// process color conversions and one or more named color profiles to handle
+ /// named colors.
///
NamedColor = 0x6E6D636C, // nmcl
}
diff --git a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileFlag.cs b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileFlag.cs
index 3758be34b..1e9ec18e8 100644
--- a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileFlag.cs
+++ b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileFlag.cs
@@ -29,12 +29,12 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
NotEmbedded = 0,
///
- /// Profile cannot be used independently of the embedded colour data
+ /// Profile cannot be used independently of the embedded color data
///
NotIndependent = 1 << 1,
///
- /// Profile can be used independently of the embedded colour data
+ /// Profile can be used independently of the embedded color data
///
Independent = 0,
}
diff --git a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileTag.cs b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileTag.cs
index 82b296900..61d34dca1 100644
--- a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileTag.cs
+++ b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccProfileTag.cs
@@ -19,18 +19,18 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
Unknown,
///
- /// A2B0 - This tag defines a colour transform from Device, Colour Encoding or PCS, to PCS, or a colour transform
+ /// A2B0 - This tag defines a color transform from Device, Color Encoding or PCS, to PCS, or a color transform
/// from Device 1 to Device 2, using lookup table tag element structures
///
AToB0 = 0x41324230,
///
- /// A2B2 - This tag describes the colour transform from Device or Colour Encoding to PCS using lookup table tag element structures
+ /// A2B2 - This tag describes the color transform from Device or Color Encoding to PCS using lookup table tag element structures
///
AToB1 = 0x41324231,
///
- /// A2B2 - This tag describes the colour transform from Device or Colour Encoding to PCS using lookup table tag element structures
+ /// A2B2 - This tag describes the color transform from Device or Color Encoding to PCS using lookup table tag element structures
///
AToB2 = 0x41324232,
@@ -46,40 +46,40 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
BlueTrc = 0x62545243,
///
- /// B2A0 - This tag defines a colour transform from PCS to Device or Colour Encoding using the lookup table tag element structures
+ /// B2A0 - This tag defines a color transform from PCS to Device or Color Encoding using the lookup table tag element structures
///
BToA0 = 0x42324130,
///
- /// B2A1 - This tag defines a colour transform from PCS to Device or Colour Encoding using the lookup table tag element structures.
+ /// B2A1 - This tag defines a color transform from PCS to Device or Color Encoding using the lookup table tag element structures.
///
BToA1 = 0x42324131,
///
- /// B2A2 - This tag defines a colour transform from PCS to Device or Colour Encoding using the lookup table tag element structures.
+ /// B2A2 - This tag defines a color transform from PCS to Device or Color Encoding using the lookup table tag element structures.
///
BToA2 = 0x42324132,
///
- /// B2D0 - This tag defines a colour transform from PCS to Device. It supports float32Number-encoded input range, output range and transform, and
+ /// B2D0 - This tag defines a color transform from PCS to Device. It supports float32Number-encoded input range, output range and transform, and
/// provides a means to override the BToA0 tag.
///
BToD0 = 0x42324430,
///
- /// B2D1 - This tag defines a colour transform from PCS to Device. It supports float32Number-encoded input range, output range and transform, and
+ /// B2D1 - This tag defines a color transform from PCS to Device. It supports float32Number-encoded input range, output range and transform, and
/// provides a means to override the BToA1 tag.
///
BToD1 = 0x42324431,
///
- /// B2D2 - This tag defines a colour transform from PCS to Device. It supports float32Number-encoded input range, output range and transform, and
+ /// B2D2 - This tag defines a color transform from PCS to Device. It supports float32Number-encoded input range, output range and transform, and
/// provides a means to override the BToA2 tag.
///
BToD2 = 0x42324432,
///
- /// B2D3 - This tag defines a colour transform from PCS to Device. It supports float32Number-encoded input range, output range and transform, and
+ /// B2D3 - This tag defines a color transform from PCS to Device. It supports float32Number-encoded input range, output range and transform, and
/// provides a means to override the BToA1 tag.
///
BToD3 = 0x42324433,
@@ -97,8 +97,8 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
CharTarget = 0x74617267,
///
- /// chad - This tag contains a matrix, which shall be invertible, and which converts an nCIEXYZ colour, measured using the actual illumination
- /// conditions and relative to the actual adopted white, to an nCIEXYZ colour relative to the PCS adopted white
+ /// chad - This tag contains a matrix, which shall be invertible, and which converts an nCIEXYZ color, measured using the actual illumination
+ /// conditions and relative to the actual adopted white, to an nCIEXYZ color relative to the PCS adopted white
///
ChromaticAdaptation = 0x63686164,
@@ -166,33 +166,33 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
DeviceSettings = 0x64657673,
///
- /// D2B0 - This tag defines a colour transform from Device to PCS. It supports float32Number-encoded
+ /// D2B0 - This tag defines a color transform from Device to PCS. It supports float32Number-encoded
/// input range, output range and transform, and provides a means to override the AToB0 tag
///
DToB0 = 0x44324230,
///
- /// D2B1 - This tag defines a colour transform from Device to PCS. It supports float32Number-encoded
+ /// D2B1 - This tag defines a color transform from Device to PCS. It supports float32Number-encoded
/// input range, output range and transform, and provides a means to override the AToB1 tag
///
DToB1 = 0x44324230,
///
- /// D2B2 - This tag defines a colour transform from Device to PCS. It supports float32Number-encoded
+ /// D2B2 - This tag defines a color transform from Device to PCS. It supports float32Number-encoded
/// input range, output range and transform, and provides a means to override the AToB1 tag
///
DToB2 = 0x44324230,
///
- /// D2B3 - This tag defines a colour transform from Device to PCS. It supports float32Number-encoded
+ /// D2B3 - This tag defines a color transform from Device to PCS. It supports float32Number-encoded
/// input range, output range and transform, and provides a means to override the AToB1 tag
///
DToB3 = 0x44324230,
///
/// gamt - This tag provides a table in which PCS values are the input and a single
- /// output value for each input value is the output. If the output value is 0, the PCS colour is in-gamut.
- /// If the output is non-zero, the PCS colour is out-of-gamut
+ /// output value for each input value is the output. If the output value is 0, the PCS color is in-gamut.
+ /// If the output is non-zero, the PCS color is out-of-gamut
///
Gamut = 0x67616D74,
@@ -214,7 +214,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
GreenTrc = 0x67545243,
///
- /// lumi - This tag contains the absolute luminance of emissive devices in candelas per square metre as described by the Y channel.
+ /// lumi - This tag contains the absolute luminance of emissive devices in candelas per square meter as described by the Y channel.
///
Luminance = 0x6C756d69,
@@ -240,8 +240,8 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
NamedColor = 0x6E636f6C,
///
- /// ncl2 - This tag contains the named colour information providing a PCS and optional device representation
- /// for a list of named colours.
+ /// ncl2 - This tag contains the named color information providing a PCS and optional device representation
+ /// for a list of named colors.
///
NamedColor2 = 0x6E636C32,
diff --git a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccRenderingIntent.cs b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccRenderingIntent.cs
index e0504b24c..7cb9c00f3 100644
--- a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccRenderingIntent.cs
+++ b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccRenderingIntent.cs
@@ -10,11 +10,11 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
{
///
/// In perceptual transforms the PCS values represent hypothetical
- /// measurements of a colour reproduction on the reference reflective
+ /// measurements of a color reproduction on the reference reflective
/// medium. By extension, for the perceptual intent, the PCS represents
/// the appearance of that reproduction as viewed in the reference viewing
/// environment by a human observer adapted to that environment. The exact
- /// colour rendering of the perceptual intent is vendor specific.
+ /// color rendering of the perceptual intent is vendor specific.
///
Perceptual = 0,
@@ -27,15 +27,15 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
MediaRelativeColorimetric = 1,
///
- /// The exact colour rendering of the saturation intent is vendor
+ /// The exact color rendering of the saturation intent is vendor
/// specific and involves compromises such as trading off
- /// preservation of hue in order to preserve the vividness of pure colours.
+ /// preservation of hue in order to preserve the vividness of pure colors.
///
Saturation = 2,
///
/// Transformations for this intent shall leave the chromatically
- /// adapted nCIEXYZ tristimulus values of the in-gamut colours unchanged.
+ /// adapted nCIEXYZ tristimulus values of the in-gamut colors unchanged.
///
AbsoluteColorimetric = 3,
}
diff --git a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccTypeSignature.cs b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccTypeSignature.cs
index 1493ecc6b..ad0db4df9 100644
--- a/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccTypeSignature.cs
+++ b/src/ImageSharp/MetaData/Profiles/ICC/Enums/IccTypeSignature.cs
@@ -23,7 +23,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
/// This is an optional tag which specifies the laydown order in which colorants
/// will be printed on an n-colorant device. The laydown order may be the same
/// as the channel generation order listed in the colorantTableTag or the channel
- /// order of a colour encoding type such as CMYK, in which case this tag is not
+ /// order of a color encoding type such as CMYK, in which case this tag is not
/// needed. When this is not the case (for example, ink-towers sometimes use
/// the order KCMY), this tag may be used to specify the laydown order of the
/// colorants
@@ -59,25 +59,25 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
DateTime = 0x6474696D,
///
- /// This structure represents a colour transform using tables with 16-bit
+ /// This structure represents a color transform using tables with 16-bit
/// precision. This type contains four processing elements: a 3 × 3 matrix
- /// (which shall be the identity matrix unless the input colour space is
+ /// (which shall be the identity matrix unless the input color space is
/// PCSXYZ), a set of one-dimensional input tables, a multi-dimensional
/// lookup table, and a set of one-dimensional output tables
///
Lut16 = 0x6D667432,
///
- /// This structure represents a colour transform using tables of 8-bit
+ /// This structure represents a color transform using tables of 8-bit
/// precision. This type contains four processing elements: a 3 × 3 matrix
- /// (which shall be the identity matrix unless the input colour space is
+ /// (which shall be the identity matrix unless the input color space is
/// PCSXYZ), a set of one-dimensional input tables, a multi-dimensional
/// lookup table, and a set of one-dimensional output tables.
///
Lut8 = 0x6D667431,
///
- /// This structure represents a colour transform. The type contains up
+ /// This structure represents a color transform. The type contains up
/// to five processing elements which are stored in the AToBTag tag
/// in the following order: a set of one-dimensional curves, a 3 × 3
/// matrix with offset terms, a set of one-dimensional curves, a
@@ -87,7 +87,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
LutAToB = 0x6D414220,
///
- /// This structure represents a colour transform. The type contains
+ /// This structure represents a color transform. The type contains
/// up to five processing elements which are stored in the BToATag
/// in the following order: a set of one-dimensional curves, a 3 × 3
/// matrix with offset terms, a set of one-dimensional curves, a
@@ -111,7 +111,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
MultiLocalizedUnicode = 0x6D6C7563,
///
- /// This structure represents a colour transform, containing a sequence
+ /// This structure represents a color transform, containing a sequence
/// of processing elements. The processing elements contained in the
/// structure are defined in the structure itself, allowing for a flexible
/// structure. Currently supported processing elements are: a set of one
@@ -123,15 +123,15 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
MultiProcessElements = 0x6D706574,
///
- /// This type is a count value and array of structures that provide colour
- /// coordinates for colour names. For each named colour, a PCS and optional
- /// device representation of the colour are given. Both representations are
+ /// This type is a count value and array of structures that provide color
+ /// coordinates for color names. For each named color, a PCS and optional
+ /// device representation of the color are given. Both representations are
/// 16-bit values and PCS values shall be relative colorimetric. The device
- /// representation corresponds to the header’s "data colour space" field.
+ /// representation corresponds to the header’s "data color space" field.
/// This representation should be consistent with the "number of device
/// coordinates" field in the namedColor2Type. If this field is 0, device
/// coordinates are not provided. The PCS representation corresponds to the
- /// header's PCS field. The PCS representation is always provided. Colour
+ /// header's PCS field. The PCS representation is always provided. Color
/// names are fixed-length, 32-byte fields including null termination. In
/// order to maintain maximum portability, it is strongly recommended that
/// special characters of the 7-bit ASCII set not be used.
@@ -168,7 +168,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
/// so that corrections can be made for variation in the device without
/// having to produce a new profile. The mechanism can be used by applications
/// to allow users with relatively inexpensive and readily available
- /// instrumentation to apply corrections to individual output colour
+ /// instrumentation to apply corrections to individual output color
/// channels in order to achieve consistent results.
///
ResponseCurveSet16 = 0x72637332,
diff --git a/src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs b/src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs
index 2ed316409..2572b3293 100644
--- a/src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs
+++ b/src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs
@@ -21,7 +21,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// The hexadecimal representation of the combined color components arranged
/// in rgb, rgba, rrggbb, or rrggbbaa format to match web syntax.
///
- /// Returns a that represents the color defined by the provided RGBA heax string.
+ /// Returns a that represents the color defined by the provided RGBA hex string.
public static TPixel FromHex(string hex)
{
Guard.NotNullOrWhiteSpace(hex, nameof(hex));
diff --git a/src/ImageSharp/PixelFormats/ColorConstants.cs b/src/ImageSharp/PixelFormats/ColorConstants.cs
index bac05c53d..14df38569 100644
--- a/src/ImageSharp/PixelFormats/ColorConstants.cs
+++ b/src/ImageSharp/PixelFormats/ColorConstants.cs
@@ -11,157 +11,268 @@ namespace SixLabors.ImageSharp.PixelFormats
///
/// Gets a collection of named, web safe, colors as defined in the CSS Color Module Level 4.
///
- public static readonly Rgba32[] WebSafeColors = GetWebSafeColors();
+ public static readonly Rgba32[] WebSafeColors =
+ {
+ Rgba32.AliceBlue,
+ Rgba32.AntiqueWhite,
+ Rgba32.Aqua,
+ Rgba32.Aquamarine,
+ Rgba32.Azure,
+ Rgba32.Beige,
+ Rgba32.Bisque,
+ Rgba32.Black,
+ Rgba32.BlanchedAlmond,
+ Rgba32.Blue,
+ Rgba32.BlueViolet,
+ Rgba32.Brown,
+ Rgba32.BurlyWood,
+ Rgba32.CadetBlue,
+ Rgba32.Chartreuse,
+ Rgba32.Chocolate,
+ Rgba32.Coral,
+ Rgba32.CornflowerBlue,
+ Rgba32.Cornsilk,
+ Rgba32.Crimson,
+ Rgba32.Cyan,
+ Rgba32.DarkBlue,
+ Rgba32.DarkCyan,
+ Rgba32.DarkGoldenrod,
+ Rgba32.DarkGray,
+ Rgba32.DarkGreen,
+ Rgba32.DarkKhaki,
+ Rgba32.DarkMagenta,
+ Rgba32.DarkOliveGreen,
+ Rgba32.DarkOrange,
+ Rgba32.DarkOrchid,
+ Rgba32.DarkRed,
+ Rgba32.DarkSalmon,
+ Rgba32.DarkSeaGreen,
+ Rgba32.DarkSlateBlue,
+ Rgba32.DarkSlateGray,
+ Rgba32.DarkTurquoise,
+ Rgba32.DarkViolet,
+ Rgba32.DeepPink,
+ Rgba32.DeepSkyBlue,
+ Rgba32.DimGray,
+ Rgba32.DodgerBlue,
+ Rgba32.Firebrick,
+ Rgba32.FloralWhite,
+ Rgba32.ForestGreen,
+ Rgba32.Fuchsia,
+ Rgba32.Gainsboro,
+ Rgba32.GhostWhite,
+ Rgba32.Gold,
+ Rgba32.Goldenrod,
+ Rgba32.Gray,
+ Rgba32.Green,
+ Rgba32.GreenYellow,
+ Rgba32.Honeydew,
+ Rgba32.HotPink,
+ Rgba32.IndianRed,
+ Rgba32.Indigo,
+ Rgba32.Ivory,
+ Rgba32.Khaki,
+ Rgba32.Lavender,
+ Rgba32.LavenderBlush,
+ Rgba32.LawnGreen,
+ Rgba32.LemonChiffon,
+ Rgba32.LightBlue,
+ Rgba32.LightCoral,
+ Rgba32.LightCyan,
+ Rgba32.LightGoldenrodYellow,
+ Rgba32.LightGray,
+ Rgba32.LightGreen,
+ Rgba32.LightPink,
+ Rgba32.LightSalmon,
+ Rgba32.LightSeaGreen,
+ Rgba32.LightSkyBlue,
+ Rgba32.LightSlateGray,
+ Rgba32.LightSteelBlue,
+ Rgba32.LightYellow,
+ Rgba32.Lime,
+ Rgba32.LimeGreen,
+ Rgba32.Linen,
+ Rgba32.Magenta,
+ Rgba32.Maroon,
+ Rgba32.MediumAquamarine,
+ Rgba32.MediumBlue,
+ Rgba32.MediumOrchid,
+ Rgba32.MediumPurple,
+ Rgba32.MediumSeaGreen,
+ Rgba32.MediumSlateBlue,
+ Rgba32.MediumSpringGreen,
+ Rgba32.MediumTurquoise,
+ Rgba32.MediumVioletRed,
+ Rgba32.MidnightBlue,
+ Rgba32.MintCream,
+ Rgba32.MistyRose,
+ Rgba32.Moccasin,
+ Rgba32.NavajoWhite,
+ Rgba32.Navy,
+ Rgba32.OldLace,
+ Rgba32.Olive,
+ Rgba32.OliveDrab,
+ Rgba32.Orange,
+ Rgba32.OrangeRed,
+ Rgba32.Orchid,
+ Rgba32.PaleGoldenrod,
+ Rgba32.PaleGreen,
+ Rgba32.PaleTurquoise,
+ Rgba32.PaleVioletRed,
+ Rgba32.PapayaWhip,
+ Rgba32.PeachPuff,
+ Rgba32.Peru,
+ Rgba32.Pink,
+ Rgba32.Plum,
+ Rgba32.PowderBlue,
+ Rgba32.Purple,
+ Rgba32.RebeccaPurple,
+ Rgba32.Red,
+ Rgba32.RosyBrown,
+ Rgba32.RoyalBlue,
+ Rgba32.SaddleBrown,
+ Rgba32.Salmon,
+ Rgba32.SandyBrown,
+ Rgba32.SeaGreen,
+ Rgba32.SeaShell,
+ Rgba32.Sienna,
+ Rgba32.Silver,
+ Rgba32.SkyBlue,
+ Rgba32.SlateBlue,
+ Rgba32.SlateGray,
+ Rgba32.Snow,
+ Rgba32.SpringGreen,
+ Rgba32.SteelBlue,
+ Rgba32.Tan,
+ Rgba32.Teal,
+ Rgba32.Thistle,
+ Rgba32.Tomato,
+ Rgba32.Transparent,
+ Rgba32.Turquoise,
+ Rgba32.Violet,
+ Rgba32.Wheat,
+ Rgba32.White,
+ Rgba32.WhiteSmoke,
+ Rgba32.Yellow,
+ Rgba32.YellowGreen
+ };
///
- /// Returns an array of web safe colors.
+ /// Gets a collection of colors as defined in the original second edition of Werner’s Nomenclature of Colours 1821.
+ /// The hex codes were collected and defined by Nicholas Rougeux
///
- /// The
- private static Rgba32[] GetWebSafeColors()
- => new Rgba32[]
- {
- Rgba32.AliceBlue,
- Rgba32.AntiqueWhite,
- Rgba32.Aqua,
- Rgba32.Aquamarine,
- Rgba32.Azure,
- Rgba32.Beige,
- Rgba32.Bisque,
- Rgba32.Black,
- Rgba32.BlanchedAlmond,
- Rgba32.Blue,
- Rgba32.BlueViolet,
- Rgba32.Brown,
- Rgba32.BurlyWood,
- Rgba32.CadetBlue,
- Rgba32.Chartreuse,
- Rgba32.Chocolate,
- Rgba32.Coral,
- Rgba32.CornflowerBlue,
- Rgba32.Cornsilk,
- Rgba32.Crimson,
- Rgba32.Cyan,
- Rgba32.DarkBlue,
- Rgba32.DarkCyan,
- Rgba32.DarkGoldenrod,
- Rgba32.DarkGray,
- Rgba32.DarkGreen,
- Rgba32.DarkKhaki,
- Rgba32.DarkMagenta,
- Rgba32.DarkOliveGreen,
- Rgba32.DarkOrange,
- Rgba32.DarkOrchid,
- Rgba32.DarkRed,
- Rgba32.DarkSalmon,
- Rgba32.DarkSeaGreen,
- Rgba32.DarkSlateBlue,
- Rgba32.DarkSlateGray,
- Rgba32.DarkTurquoise,
- Rgba32.DarkViolet,
- Rgba32.DeepPink,
- Rgba32.DeepSkyBlue,
- Rgba32.DimGray,
- Rgba32.DodgerBlue,
- Rgba32.Firebrick,
- Rgba32.FloralWhite,
- Rgba32.ForestGreen,
- Rgba32.Fuchsia,
- Rgba32.Gainsboro,
- Rgba32.GhostWhite,
- Rgba32.Gold,
- Rgba32.Goldenrod,
- Rgba32.Gray,
- Rgba32.Green,
- Rgba32.GreenYellow,
- Rgba32.Honeydew,
- Rgba32.HotPink,
- Rgba32.IndianRed,
- Rgba32.Indigo,
- Rgba32.Ivory,
- Rgba32.Khaki,
- Rgba32.Lavender,
- Rgba32.LavenderBlush,
- Rgba32.LawnGreen,
- Rgba32.LemonChiffon,
- Rgba32.LightBlue,
- Rgba32.LightCoral,
- Rgba32.LightCyan,
- Rgba32.LightGoldenrodYellow,
- Rgba32.LightGray,
- Rgba32.LightGreen,
- Rgba32.LightPink,
- Rgba32.LightSalmon,
- Rgba32.LightSeaGreen,
- Rgba32.LightSkyBlue,
- Rgba32.LightSlateGray,
- Rgba32.LightSteelBlue,
- Rgba32.LightYellow,
- Rgba32.Lime,
- Rgba32.LimeGreen,
- Rgba32.Linen,
- Rgba32.Magenta,
- Rgba32.Maroon,
- Rgba32.MediumAquamarine,
- Rgba32.MediumBlue,
- Rgba32.MediumOrchid,
- Rgba32.MediumPurple,
- Rgba32.MediumSeaGreen,
- Rgba32.MediumSlateBlue,
- Rgba32.MediumSpringGreen,
- Rgba32.MediumTurquoise,
- Rgba32.MediumVioletRed,
- Rgba32.MidnightBlue,
- Rgba32.MintCream,
- Rgba32.MistyRose,
- Rgba32.Moccasin,
- Rgba32.NavajoWhite,
- Rgba32.Navy,
- Rgba32.OldLace,
- Rgba32.Olive,
- Rgba32.OliveDrab,
- Rgba32.Orange,
- Rgba32.OrangeRed,
- Rgba32.Orchid,
- Rgba32.PaleGoldenrod,
- Rgba32.PaleGreen,
- Rgba32.PaleTurquoise,
- Rgba32.PaleVioletRed,
- Rgba32.PapayaWhip,
- Rgba32.PeachPuff,
- Rgba32.Peru,
- Rgba32.Pink,
- Rgba32.Plum,
- Rgba32.PowderBlue,
- Rgba32.Purple,
- Rgba32.RebeccaPurple,
- Rgba32.Red,
- Rgba32.RosyBrown,
- Rgba32.RoyalBlue,
- Rgba32.SaddleBrown,
- Rgba32.Salmon,
- Rgba32.SandyBrown,
- Rgba32.SeaGreen,
- Rgba32.SeaShell,
- Rgba32.Sienna,
- Rgba32.Silver,
- Rgba32.SkyBlue,
- Rgba32.SlateBlue,
- Rgba32.SlateGray,
- Rgba32.Snow,
- Rgba32.SpringGreen,
- Rgba32.SteelBlue,
- Rgba32.Tan,
- Rgba32.Teal,
- Rgba32.Thistle,
- Rgba32.Tomato,
- Rgba32.Transparent,
- Rgba32.Turquoise,
- Rgba32.Violet,
- Rgba32.Wheat,
- Rgba32.White,
- Rgba32.WhiteSmoke,
- Rgba32.Yellow,
- Rgba32.YellowGreen
- };
+ public static readonly Rgba32[] WernerColors =
+ {
+ Rgba32.FromHex("#f1e9cd"),
+ Rgba32.FromHex("#f2e7cf"),
+ Rgba32.FromHex("#ece6d0"),
+ Rgba32.FromHex("#f2eacc"),
+ Rgba32.FromHex("#f3e9ca"),
+ Rgba32.FromHex("#f2ebcd"),
+ Rgba32.FromHex("#e6e1c9"),
+ Rgba32.FromHex("#e2ddc6"),
+ Rgba32.FromHex("#cbc8b7"),
+ Rgba32.FromHex("#bfbbb0"),
+ Rgba32.FromHex("#bebeb3"),
+ Rgba32.FromHex("#b7b5ac"),
+ Rgba32.FromHex("#bab191"),
+ Rgba32.FromHex("#9c9d9a"),
+ Rgba32.FromHex("#8a8d84"),
+ Rgba32.FromHex("#5b5c61"),
+ Rgba32.FromHex("#555152"),
+ Rgba32.FromHex("#413f44"),
+ Rgba32.FromHex("#454445"),
+ Rgba32.FromHex("#423937"),
+ Rgba32.FromHex("#433635"),
+ Rgba32.FromHex("#252024"),
+ Rgba32.FromHex("#241f20"),
+ Rgba32.FromHex("#281f3f"),
+ Rgba32.FromHex("#1c1949"),
+ Rgba32.FromHex("#4f638d"),
+ Rgba32.FromHex("#383867"),
+ Rgba32.FromHex("#5c6b8f"),
+ Rgba32.FromHex("#657abb"),
+ Rgba32.FromHex("#6f88af"),
+ Rgba32.FromHex("#7994b5"),
+ Rgba32.FromHex("#6fb5a8"),
+ Rgba32.FromHex("#719ba2"),
+ Rgba32.FromHex("#8aa1a6"),
+ Rgba32.FromHex("#d0d5d3"),
+ Rgba32.FromHex("#8590ae"),
+ Rgba32.FromHex("#3a2f52"),
+ Rgba32.FromHex("#39334a"),
+ Rgba32.FromHex("#6c6d94"),
+ Rgba32.FromHex("#584c77"),
+ Rgba32.FromHex("#533552"),
+ Rgba32.FromHex("#463759"),
+ Rgba32.FromHex("#bfbac0"),
+ Rgba32.FromHex("#77747f"),
+ Rgba32.FromHex("#4a475c"),
+ Rgba32.FromHex("#b8bfaf"),
+ Rgba32.FromHex("#b2b599"),
+ Rgba32.FromHex("#979c84"),
+ Rgba32.FromHex("#5d6161"),
+ Rgba32.FromHex("#61ac86"),
+ Rgba32.FromHex("#a4b6a7"),
+ Rgba32.FromHex("#adba98"),
+ Rgba32.FromHex("#93b778"),
+ Rgba32.FromHex("#7d8c55"),
+ Rgba32.FromHex("#33431e"),
+ Rgba32.FromHex("#7c8635"),
+ Rgba32.FromHex("#8e9849"),
+ Rgba32.FromHex("#c2c190"),
+ Rgba32.FromHex("#67765b"),
+ Rgba32.FromHex("#ab924b"),
+ Rgba32.FromHex("#c8c76f"),
+ Rgba32.FromHex("#ccc050"),
+ Rgba32.FromHex("#ebdd99"),
+ Rgba32.FromHex("#ab9649"),
+ Rgba32.FromHex("#dbc364"),
+ Rgba32.FromHex("#e6d058"),
+ Rgba32.FromHex("#ead665"),
+ Rgba32.FromHex("#d09b2c"),
+ Rgba32.FromHex("#a36629"),
+ Rgba32.FromHex("#a77d35"),
+ Rgba32.FromHex("#f0d696"),
+ Rgba32.FromHex("#d7c485"),
+ Rgba32.FromHex("#f1d28c"),
+ Rgba32.FromHex("#efcc83"),
+ Rgba32.FromHex("#f3daa7"),
+ Rgba32.FromHex("#dfa837"),
+ Rgba32.FromHex("#ebbc71"),
+ Rgba32.FromHex("#d17c3f"),
+ Rgba32.FromHex("#92462f"),
+ Rgba32.FromHex("#be7249"),
+ Rgba32.FromHex("#bb603c"),
+ Rgba32.FromHex("#c76b4a"),
+ Rgba32.FromHex("#a75536"),
+ Rgba32.FromHex("#b63e36"),
+ Rgba32.FromHex("#b5493a"),
+ Rgba32.FromHex("#cd6d57"),
+ Rgba32.FromHex("#711518"),
+ Rgba32.FromHex("#e9c49d"),
+ Rgba32.FromHex("#eedac3"),
+ Rgba32.FromHex("#eecfbf"),
+ Rgba32.FromHex("#ce536b"),
+ Rgba32.FromHex("#b74a70"),
+ Rgba32.FromHex("#b7757c"),
+ Rgba32.FromHex("#612741"),
+ Rgba32.FromHex("#7a4848"),
+ Rgba32.FromHex("#3f3033"),
+ Rgba32.FromHex("#8d746f"),
+ Rgba32.FromHex("#4d3635"),
+ Rgba32.FromHex("#6e3b31"),
+ Rgba32.FromHex("#864735"),
+ Rgba32.FromHex("#553d3a"),
+ Rgba32.FromHex("#613936"),
+ Rgba32.FromHex("#7a4b3a"),
+ Rgba32.FromHex("#946943"),
+ Rgba32.FromHex("#c39e6d"),
+ Rgba32.FromHex("#513e32"),
+ Rgba32.FromHex("#8b7859"),
+ Rgba32.FromHex("#9b856b"),
+ Rgba32.FromHex("#766051"),
+ Rgba32.FromHex("#453b32")
+ };
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/PixelFormats/NamedColors{TPixel}.cs b/src/ImageSharp/PixelFormats/NamedColors{TPixel}.cs
index 08530c2bb..7e093de04 100644
--- a/src/ImageSharp/PixelFormats/NamedColors{TPixel}.cs
+++ b/src/ImageSharp/PixelFormats/NamedColors{TPixel}.cs
@@ -14,9 +14,10 @@ namespace SixLabors.ImageSharp.PixelFormats
where TPixel : struct, IPixel
{
///
- /// Thread-safe backing field for .
+ /// Thread-safe backing field for the constant palettes.
///
private static readonly Lazy WebSafePaletteLazy = new Lazy(GetWebSafePalette, true);
+ private static readonly Lazy WernerPaletteLazy = new Lazy(GetWernerPalette, true);
///
/// Represents a matching the W3C definition that has an hex value of #F0F8FF.
@@ -729,22 +730,32 @@ namespace SixLabors.ImageSharp.PixelFormats
public static readonly TPixel YellowGreen = ColorBuilder.FromRGBA(154, 205, 50, 255);
///
- /// Gets a matching the W3C definition of web safe colors.
+ /// Gets a collection of web safe, colors as defined in the CSS Color Module Level 4.
///
public static TPixel[] WebSafePalette => WebSafePaletteLazy.Value;
- private static TPixel[] GetWebSafePalette()
+ ///
+ /// Gets a collection of colors as defined in the original second edition of Werner’s Nomenclature of Colours 1821.
+ /// The hex codes were collected and defined by Nicholas Rougeux
+ ///
+ public static TPixel[] WernerPalette => WernerPaletteLazy.Value;
+
+ private static TPixel[] GetWebSafePalette() => GetPalette(ColorConstants.WebSafeColors);
+
+ private static TPixel[] GetWernerPalette() => GetPalette(ColorConstants.WernerColors);
+
+ private static TPixel[] GetPalette(Rgba32[] palette)
{
- Rgba32[] constants = ColorConstants.WebSafeColors;
- var safe = new TPixel[constants.Length + 1];
+ var converted = new TPixel[palette.Length];
- Span constantsBytes = MemoryMarshal.Cast(constants.AsSpan());
+ Span constantsBytes = MemoryMarshal.Cast(palette.AsSpan());
PixelOperations.Instance.FromRgba32Bytes(
Configuration.Default,
constantsBytes,
- safe,
- constants.Length);
- return safe;
+ converted,
+ palette.Length);
+
+ return converted;
}
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs
index f4eb19be3..115dd7a43 100644
--- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs
+++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs
@@ -110,7 +110,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourceColors);
// Gray8 and Gray16 are special implementations of IPixel in that they do not conform to the
- // standard RGBA colorspace format and must be converted from RGBA using the special ITU BT709 alogrithm.
+ // standard RGBA colorspace format and must be converted from RGBA using the special ITU BT709 algorithm.
// One of the requirements of FromScaledVector4/ToScaledVector4 is that it unaware of this and
// packs/unpacks the pixel without and conversion so we employ custom methods do do this.
if (typeof(TDestinationPixel) == typeof(Gray16))
diff --git a/src/ImageSharp/PixelFormats/Utils/PixelConverter.cs b/src/ImageSharp/PixelFormats/Utils/PixelConverter.cs
index 55a94fc81..12ec389b0 100644
--- a/src/ImageSharp/PixelFormats/Utils/PixelConverter.cs
+++ b/src/ImageSharp/PixelFormats/Utils/PixelConverter.cs
@@ -40,7 +40,7 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils
// packedRgba = [aa bb gg rr]
// tmp1 = [aa 00 gg 00]
// tmp2 = [00 bb 00 rr]
- // tmp3=ROTL(16, tmp2) = [00 rr 00 bb]
+ // tmp3=ROTL(16, tmp2) = [00 rr 00 bb]
// tmp1 + tmp3 = [aa rr gg bb]
uint tmp1 = packedRgba & 0xFF00FF00;
uint tmp2 = packedRgba & 0x00FF00FF;
diff --git a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs
index 7c57fe4fb..5609e606d 100644
--- a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs
+++ b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs
@@ -60,7 +60,7 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils
Span lastQuarterOfDestBuffer = MemoryMarshal.Cast(destVectors).Slice((3 * count) + 1, countWithoutLastItem);
pixelOperations.ToRgba32(configuration, reducedSource, lastQuarterOfDestBuffer);
- // 'destVectors' and 'lastQuarterOfDestBuffer' are ovelapping buffers,
+ // 'destVectors' and 'lastQuarterOfDestBuffer' are overlapping buffers,
// but we are always reading/writing at different positions:
SimdUtils.BulkConvertByteToNormalizedFloat(
MemoryMarshal.Cast(lastQuarterOfDestBuffer),
diff --git a/src/ImageSharp/Processing/KnownQuantizers.cs b/src/ImageSharp/Processing/KnownQuantizers.cs
index fe9806310..e4a7a75d5 100644
--- a/src/ImageSharp/Processing/KnownQuantizers.cs
+++ b/src/ImageSharp/Processing/KnownQuantizers.cs
@@ -12,20 +12,23 @@ namespace SixLabors.ImageSharp.Processing
{
///
/// Gets the adaptive Octree quantizer. Fast with good quality.
- /// The quantizer only supports a single alpha value.
///
public static IQuantizer Octree { get; } = new OctreeQuantizer();
///
/// Gets the Xiaolin Wu's Color Quantizer which generates high quality output.
- /// The quantizer supports multiple alpha values.
///
public static IQuantizer Wu { get; } = new WuQuantizer();
///
- /// Gets the palette based, Using the collection of web-safe colors.
- /// The quantizer supports multiple alpha values.
+ /// Gets the palette based quantizer consisting of web safe colors as defined in the CSS Color Module Level 4.
///
- public static IQuantizer Palette { get; } = new PaletteQuantizer();
+ public static IQuantizer WebSafe { get; } = new WebSafePaletteQuantizer();
+
+ ///
+ /// Gets the palette based quantizer consisting of colors as defined in the original second edition of Werner’s Nomenclature of Colours 1821.
+ /// The hex codes were collected and defined by Nicholas Rougeux
+ ///
+ public static IQuantizer Werner { get; } = new WernerPaletteQuantizer();
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs
index 0ec62ac3d..38dc638b9 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs
@@ -66,36 +66,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
? new DenseMatrix(size, 1)
: new DenseMatrix(1, size);
- float sum = 0F;
- for (int i = 0; i < size; i++)
- {
- float x = 1;
- sum += x;
- if (horizontal)
- {
- kernel[0, i] = x;
- }
- else
- {
- kernel[i, 0] = x;
- }
- }
-
- // Normalize kernel so that the sum of all weights equals 1
- if (horizontal)
- {
- for (int i = 0; i < size; i++)
- {
- kernel[0, i] = kernel[0, i] / sum;
- }
- }
- else
- {
- for (int i = 0; i < size; i++)
- {
- kernel[i, 0] = kernel[i, 0] / sum;
- }
- }
+ kernel.Fill(1.0F / size);
return kernel;
}
diff --git a/src/ImageSharp/Processing/Processors/Convolution/KirshKernels.cs b/src/ImageSharp/Processing/Processors/Convolution/KirschKernels.cs
similarity index 96%
rename from src/ImageSharp/Processing/Processors/Convolution/KirshKernels.cs
rename to src/ImageSharp/Processing/Processors/Convolution/KirschKernels.cs
index d31587508..86232e306 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/KirshKernels.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/KirschKernels.cs
@@ -6,9 +6,9 @@ using SixLabors.ImageSharp.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Convolution
{
///
- /// Contains the eight matrices used for Kirsh edge detection
+ /// Contains the eight matrices used for Kirsch edge detection
///
- internal static class KirshKernels
+ internal static class KirschKernels
{
///
/// Gets the North gradient operator
diff --git a/src/ImageSharp/Processing/Processors/Convolution/KirschProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/KirschProcessor.cs
index 46cf00c22..c3188676f 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/KirschProcessor.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/KirschProcessor.cs
@@ -23,27 +23,27 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
}
///
- public override DenseMatrix North => KirshKernels.KirschNorth;
+ public override DenseMatrix North => KirschKernels.KirschNorth;
///
- public override DenseMatrix NorthWest => KirshKernels.KirschNorthWest;
+ public override DenseMatrix NorthWest => KirschKernels.KirschNorthWest;
///
- public override DenseMatrix West => KirshKernels.KirschWest;
+ public override DenseMatrix West => KirschKernels.KirschWest;
///
- public override DenseMatrix SouthWest => KirshKernels.KirschSouthWest;
+ public override DenseMatrix SouthWest => KirschKernels.KirschSouthWest;
///
- public override DenseMatrix South => KirshKernels.KirschSouth;
+ public override DenseMatrix South => KirschKernels.KirschSouth;
///
- public override DenseMatrix SouthEast => KirshKernels.KirschSouthEast;
+ public override DenseMatrix SouthEast => KirschKernels.KirschSouthEast;
///
- public override DenseMatrix East => KirshKernels.KirschEast;
+ public override DenseMatrix East => KirschKernels.KirschEast;
///
- public override DenseMatrix NorthEast => KirshKernels.KirschNorthEast;
+ public override DenseMatrix NorthEast => KirschKernels.KirschNorthEast;
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs
index 38962c768..d49023886 100644
--- a/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs
+++ b/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs
@@ -15,11 +15,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
///
public class OctreeQuantizer : IQuantizer
{
- ///
- /// The default maximum number of colors to use when quantizing the image.
- ///
- public const int DefaultMaxColors = 256;
-
///
/// Initializes a new instance of the class.
///
@@ -42,7 +37,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
///
/// Whether to apply dithering to the output image
public OctreeQuantizer(bool dither)
- : this(GetDiffuser(dither), DefaultMaxColors)
+ : this(GetDiffuser(dither), QuantizerConstants.MaxColors)
{
}
@@ -51,7 +46,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
///
/// The error diffusion algorithm, if any, to apply to the output image
public OctreeQuantizer(IErrorDiffuser diffuser)
- : this(diffuser, DefaultMaxColors)
+ : this(diffuser, QuantizerConstants.MaxColors)
{
}
@@ -63,7 +58,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
public OctreeQuantizer(IErrorDiffuser diffuser, int maxColors)
{
this.Diffuser = diffuser;
- this.MaxColors = maxColors.Clamp(1, DefaultMaxColors);
+ this.MaxColors = maxColors.Clamp(QuantizerConstants.MinColors, QuantizerConstants.MaxColors);
}
///
@@ -84,7 +79,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
public IFrameQuantizer CreateFrameQuantizer(Configuration configuration, int maxColors)
where TPixel : struct, IPixel
{
- maxColors = maxColors.Clamp(1, DefaultMaxColors);
+ maxColors = maxColors.Clamp(QuantizerConstants.MinColors, QuantizerConstants.MaxColors);
return new OctreeFrameQuantizer(this, maxColors);
}
diff --git a/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs
index cab3af6de..f8a19f8c4 100644
--- a/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs
@@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0.
using System;
-using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Advanced;
@@ -23,27 +22,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
///
private readonly TPixel[] palette;
- ///
- /// The vector representation of the image palette.
- ///
- private readonly Vector4[] paletteVector;
-
///
/// Initializes a new instance of the class.
///
- /// The to configure internal operations.
/// The palette quantizer.
/// An array of all colors in the palette.
- public PaletteFrameQuantizer(Configuration configuration, PaletteQuantizer quantizer, TPixel[] colors)
- : base(quantizer, true)
- {
- // TODO: Why is this value constrained? Gif has limitations but theoretically
- // we might want to reduce the palette of an image to greater than that limitation.
- Guard.MustBeBetweenOrEqualTo(colors.Length, 1, 256, nameof(colors));
- this.palette = colors;
- this.paletteVector = new Vector4[this.palette.Length];
- PixelOperations.Instance.ToScaledVector4(configuration, this.palette, this.paletteVector);
- }
+ public PaletteFrameQuantizer(IQuantizer quantizer, TPixel[] colors)
+ : base(quantizer, true) => this.palette = colors;
///
protected override void SecondPass(
diff --git a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs
index 361791253..6b2be3d03 100644
--- a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs
+++ b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs
@@ -8,18 +8,18 @@ using SixLabors.ImageSharp.Processing.Processors.Dithering;
namespace SixLabors.ImageSharp.Processing.Processors.Quantization
{
///
- /// Allows the quantization of images pixels using web safe colors defined in the CSS Color Module Level 4.
- /// Override this class to provide your own palette.
+ /// Allows the quantization of images pixels using color palettes.
+ /// Override this class to provide your own palette.
///
- /// By default the quantizer uses dithering and the
+ /// By default the quantizer uses dithering.
///
///
- public class PaletteQuantizer : IQuantizer
+ public abstract class PaletteQuantizer : IQuantizer
{
///
/// Initializes a new instance of the class.
///
- public PaletteQuantizer()
+ protected PaletteQuantizer()
: this(true)
{
}
@@ -28,7 +28,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
/// Initializes a new instance of the class.
///
/// Whether to apply dithering to the output image
- public PaletteQuantizer(bool dither)
+ protected PaletteQuantizer(bool dither)
: this(GetDiffuser(dither))
{
}
@@ -37,42 +37,40 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
/// Initializes a new instance of the class.
///
/// The error diffusion algorithm, if any, to apply to the output image
- public PaletteQuantizer(IErrorDiffuser diffuser) => this.Diffuser = diffuser;
+ protected PaletteQuantizer(IErrorDiffuser diffuser) => this.Diffuser = diffuser;
///
public IErrorDiffuser Diffuser { get; }
///
- public virtual IFrameQuantizer CreateFrameQuantizer(Configuration configuration)
- where TPixel : struct, IPixel
- => this.CreateFrameQuantizer(configuration, () => NamedColors.WebSafePalette);
+ public abstract IFrameQuantizer CreateFrameQuantizer(Configuration configuration)
+ where TPixel : struct, IPixel;
///
- public IFrameQuantizer CreateFrameQuantizer(Configuration configuration, int maxColors)
+ public abstract IFrameQuantizer CreateFrameQuantizer(Configuration configuration, int maxColors)
+ where TPixel : struct, IPixel;
+
+ ///
+ /// Creates the generic frame quantizer.
+ ///
+ /// The pixel format.
+ /// The to configure internal operations.
+ /// The color palette.
+ /// The maximum number of colors to hold in the color palette.
+ /// The
+ protected IFrameQuantizer CreateFrameQuantizer(Configuration configuration, TPixel[] palette, int maxColors)
where TPixel : struct, IPixel
{
- TPixel[] websafe = NamedColors.WebSafePalette;
- int max = Math.Min(maxColors, websafe.Length);
+ int max = Math.Min(QuantizerConstants.MaxColors, Math.Min(maxColors, palette.Length));
- if (max != websafe.Length)
+ if (max != palette.Length)
{
- return this.CreateFrameQuantizer(configuration, () => NamedColors.WebSafePalette.AsSpan(0, max).ToArray());
+ return new PaletteFrameQuantizer(this, palette.AsSpan(0, max).ToArray());
}
- return this.CreateFrameQuantizer(configuration, () => websafe);
+ return new PaletteFrameQuantizer(this, palette);
}
- ///
- /// Gets the palette to use to quantize the image.
- ///
- /// The pixel format.
- /// The to configure internal operations
- /// The method to return the palette.
- /// The
- public IFrameQuantizer CreateFrameQuantizer(Configuration configuration, Func paletteFunction)
- where TPixel : struct, IPixel
- => new PaletteFrameQuantizer(configuration, this, paletteFunction.Invoke());
-
private static IErrorDiffuser GetDiffuser(bool dither) => dither ? KnownDiffusers.FloydSteinberg : null;
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs
new file mode 100644
index 000000000..a350adfc0
--- /dev/null
+++ b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs
@@ -0,0 +1,110 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+using System.Runtime.CompilerServices;
+using SixLabors.ImageSharp.PixelFormats;
+using SixLabors.ImageSharp.Processing.Processors.Dithering;
+
+namespace SixLabors.ImageSharp.Processing.Processors.Quantization
+{
+ ///
+ /// A generic palette quantizer.
+ ///
+ /// The pixel format.
+ public class PaletteQuantizer : IQuantizer
+ where TPixel : struct, IPixel
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The color palette to use.
+ public PaletteQuantizer(TPixel[] palette)
+ : this(palette, true)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The color palette to use.
+ /// Whether to apply dithering to the output image
+ public PaletteQuantizer(TPixel[] palette, bool dither)
+ : this(palette, GetDiffuser(dither))
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The color palette to use.
+ /// The error diffusion algorithm, if any, to apply to the output image
+ public PaletteQuantizer(TPixel[] palette, IErrorDiffuser diffuser)
+ {
+ Guard.MustBeBetweenOrEqualTo(palette.Length, QuantizerConstants.MinColors, QuantizerConstants.MaxColors, nameof(palette));
+ this.Palette = palette;
+ this.Diffuser = diffuser;
+ }
+
+ ///
+ public IErrorDiffuser Diffuser { get; }
+
+ ///
+ /// Gets the palette.
+ ///
+ public TPixel[] Palette { get; }
+
+ ///
+ /// Creates the generic frame quantizer.
+ ///
+ /// The to configure internal operations.
+ /// The .
+ public IFrameQuantizer CreateFrameQuantizer(Configuration configuration)
+ => ((IQuantizer)this).CreateFrameQuantizer(configuration);
+
+ ///
+ /// Creates the generic frame quantizer.
+ ///
+ /// The to configure internal operations.
+ /// The maximum number of colors to hold in the color palette.
+ /// The .
+ public IFrameQuantizer CreateFrameQuantizer(Configuration configuration, int maxColors)
+ => ((IQuantizer)this).CreateFrameQuantizer(configuration, maxColors);
+
+ ///
+ IFrameQuantizer IQuantizer.CreateFrameQuantizer(Configuration configuration)
+ {
+ if (!typeof(TPixel).Equals(typeof(TPixel1)))
+ {
+ throw new InvalidOperationException("Generic method type must be the same as class type.");
+ }
+
+ TPixel[] paletteRef = this.Palette;
+ return new PaletteFrameQuantizer(this, Unsafe.As(ref paletteRef));
+ }
+
+ ///
+ IFrameQuantizer IQuantizer.CreateFrameQuantizer(Configuration configuration, int maxColors)
+ {
+ if (!typeof(TPixel).Equals(typeof(TPixel1)))
+ {
+ throw new InvalidOperationException("Generic method type must be the same as class type.");
+ }
+
+ TPixel[] paletteRef = this.Palette;
+ TPixel1[] castPalette = Unsafe.As(ref paletteRef);
+
+ maxColors = maxColors.Clamp(QuantizerConstants.MinColors, QuantizerConstants.MaxColors);
+ int max = Math.Min(maxColors, castPalette.Length);
+
+ if (max != castPalette.Length)
+ {
+ return new PaletteFrameQuantizer(this, castPalette.AsSpan(0, max).ToArray());
+ }
+
+ return new PaletteFrameQuantizer(this, castPalette);
+ }
+
+ private static IErrorDiffuser GetDiffuser(bool dither) => dither ? KnownDiffusers.FloydSteinberg : null;
+ }
+}
\ No newline at end of file
diff --git a/src/ImageSharp/Processing/Processors/Quantization/QuantizerConstants.cs b/src/ImageSharp/Processing/Processors/Quantization/QuantizerConstants.cs
new file mode 100644
index 000000000..d79a91c30
--- /dev/null
+++ b/src/ImageSharp/Processing/Processors/Quantization/QuantizerConstants.cs
@@ -0,0 +1,21 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+namespace SixLabors.ImageSharp.Processing.Processors.Quantization
+{
+ ///
+ /// Contains color quantization specific constants.
+ ///
+ internal static class QuantizerConstants
+ {
+ ///
+ /// The minimum number of colors to use when quantizing an image.
+ ///
+ public const int MinColors = 1;
+
+ ///
+ /// The maximum number of colors to use when quantizing an image.
+ ///
+ public const int MaxColors = 256;
+ }
+}
\ No newline at end of file
diff --git a/src/ImageSharp/Processing/Processors/Quantization/WebSafePaletteQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/WebSafePaletteQuantizer.cs
new file mode 100644
index 000000000..93630a916
--- /dev/null
+++ b/src/ImageSharp/Processing/Processors/Quantization/WebSafePaletteQuantizer.cs
@@ -0,0 +1,47 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+using SixLabors.ImageSharp.PixelFormats;
+using SixLabors.ImageSharp.Processing.Processors.Dithering;
+
+namespace SixLabors.ImageSharp.Processing.Processors.Quantization
+{
+ ///
+ /// A palette quantizer consisting of web safe colors as defined in the CSS Color Module Level 4.
+ ///
+ public class WebSafePaletteQuantizer : PaletteQuantizer
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public WebSafePaletteQuantizer()
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Whether to apply dithering to the output image
+ public WebSafePaletteQuantizer(bool dither)
+ : base(dither)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The error diffusion algorithm, if any, to apply to the output image
+ public WebSafePaletteQuantizer(IErrorDiffuser diffuser)
+ : base(diffuser)
+ {
+ }
+
+ ///
+ public override IFrameQuantizer CreateFrameQuantizer(Configuration configuration)
+ => this.CreateFrameQuantizer(configuration, NamedColors.WebSafePalette.Length);
+
+ ///
+ public override IFrameQuantizer CreateFrameQuantizer(Configuration configuration, int maxColors)
+ => this.CreateFrameQuantizer(configuration, NamedColors.WebSafePalette, maxColors);
+ }
+}
\ No newline at end of file
diff --git a/src/ImageSharp/Processing/Processors/Quantization/WernerPaletteQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/WernerPaletteQuantizer.cs
new file mode 100644
index 000000000..2ff9f5090
--- /dev/null
+++ b/src/ImageSharp/Processing/Processors/Quantization/WernerPaletteQuantizer.cs
@@ -0,0 +1,48 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+using SixLabors.ImageSharp.PixelFormats;
+using SixLabors.ImageSharp.Processing.Processors.Dithering;
+
+namespace SixLabors.ImageSharp.Processing.Processors.Quantization
+{
+ ///
+ /// A palette quantizer consisting of colors as defined in the original second edition of Werner’s Nomenclature of Colours 1821.
+ /// The hex codes were collected and defined by Nicholas Rougeux
+ ///
+ public class WernerPaletteQuantizer : PaletteQuantizer
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public WernerPaletteQuantizer()
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Whether to apply dithering to the output image
+ public WernerPaletteQuantizer(bool dither)
+ : base(dither)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The error diffusion algorithm, if any, to apply to the output image
+ public WernerPaletteQuantizer(IErrorDiffuser diffuser)
+ : base(diffuser)
+ {
+ }
+
+ ///
+ public override IFrameQuantizer CreateFrameQuantizer(Configuration configuration)
+ => this.CreateFrameQuantizer(configuration, NamedColors.WernerPalette.Length);
+
+ ///
+ public override IFrameQuantizer CreateFrameQuantizer(Configuration configuration, int maxColors)
+ => this.CreateFrameQuantizer(configuration, NamedColors.WernerPalette, maxColors);
+ }
+}
\ No newline at end of file
diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs
index 4cd09a14f..eb8b0fec9 100644
--- a/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs
+++ b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs
@@ -14,11 +14,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
///
public class WuQuantizer : IQuantizer
{
- ///
- /// The default maximum number of colors to use when quantizing the image.
- ///
- public const int DefaultMaxColors = 256;
-
///
/// Initializes a new instance of the class.
///
@@ -41,7 +36,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
///
/// Whether to apply dithering to the output image
public WuQuantizer(bool dither)
- : this(GetDiffuser(dither), DefaultMaxColors)
+ : this(GetDiffuser(dither), QuantizerConstants.MaxColors)
{
}
@@ -50,7 +45,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
///
/// The error diffusion algorithm, if any, to apply to the output image
public WuQuantizer(IErrorDiffuser diffuser)
- : this(diffuser, DefaultMaxColors)
+ : this(diffuser, QuantizerConstants.MaxColors)
{
}
@@ -62,7 +57,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
public WuQuantizer(IErrorDiffuser diffuser, int maxColors)
{
this.Diffuser = diffuser;
- this.MaxColors = maxColors.Clamp(1, DefaultMaxColors);
+ this.MaxColors = maxColors.Clamp(QuantizerConstants.MinColors, QuantizerConstants.MaxColors);
}
///
@@ -83,7 +78,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
public IFrameQuantizer CreateFrameQuantizer(Configuration configuration, int maxColors)
where TPixel : struct, IPixel
{
- maxColors = maxColors.Clamp(1, DefaultMaxColors);
+ maxColors = maxColors.Clamp(QuantizerConstants.MinColors, QuantizerConstants.MaxColors);
return new WuFrameQuantizer(this, maxColors);
}
diff --git a/tests/ImageSharp.Benchmarks/Codecs/EncodeGif.cs b/tests/ImageSharp.Benchmarks/Codecs/EncodeGif.cs
index 12e74ccdb..89eb63d62 100644
--- a/tests/ImageSharp.Benchmarks/Codecs/EncodeGif.cs
+++ b/tests/ImageSharp.Benchmarks/Codecs/EncodeGif.cs
@@ -53,7 +53,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
public void GifCore()
{
// Try to get as close to System.Drawing's output as possible
- var options = new GifEncoder { Quantizer = new PaletteQuantizer(false) };
+ var options = new GifEncoder { Quantizer = new WebSafePaletteQuantizer(false) };
using (var memoryStream = new MemoryStream())
{
this.bmpCore.SaveAsGif(memoryStream, options);
diff --git a/tests/ImageSharp.Benchmarks/Codecs/EncodeGifMultiple.cs b/tests/ImageSharp.Benchmarks/Codecs/EncodeGifMultiple.cs
index 9b94347f3..bf9627f4c 100644
--- a/tests/ImageSharp.Benchmarks/Codecs/EncodeGifMultiple.cs
+++ b/tests/ImageSharp.Benchmarks/Codecs/EncodeGifMultiple.cs
@@ -23,7 +23,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
this.ForEachImageSharpImage((img, ms) =>
{
// Try to get as close to System.Drawing's output as possible
- var options = new GifEncoder { Quantizer = new PaletteQuantizer(false) };
+ var options = new GifEncoder { Quantizer = new WebSafePaletteQuantizer(false) };
img.Save(ms, options); return null;
});
}
diff --git a/tests/ImageSharp.Benchmarks/Codecs/EncodeIndexedPng.cs b/tests/ImageSharp.Benchmarks/Codecs/EncodeIndexedPng.cs
index 962b34eb7..639d1594e 100644
--- a/tests/ImageSharp.Benchmarks/Codecs/EncodeIndexedPng.cs
+++ b/tests/ImageSharp.Benchmarks/Codecs/EncodeIndexedPng.cs
@@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
{
using (var memoryStream = new MemoryStream())
{
- var options = new PngEncoder { Quantizer = KnownQuantizers.Palette };
+ var options = new PngEncoder { Quantizer = KnownQuantizers.WebSafe };
this.bmpCore.SaveAsPng(memoryStream, options);
}
}
@@ -75,7 +75,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
{
using (var memoryStream = new MemoryStream())
{
- var options = new PngEncoder { Quantizer = new PaletteQuantizer(false) };
+ var options = new PngEncoder { Quantizer = new WebSafePaletteQuantizer(false) };
this.bmpCore.SaveAsPng(memoryStream, options);
}
}
diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo1x1.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo1x1.cs
new file mode 100644
index 000000000..bf9b1af33
--- /dev/null
+++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo1x1.cs
@@ -0,0 +1,133 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+using System.Numerics;
+using System.Runtime.CompilerServices;
+
+using BenchmarkDotNet.Attributes;
+
+using SixLabors.ImageSharp.Formats.Jpeg.Components;
+using SixLabors.ImageSharp.Memory;
+// ReSharper disable InconsistentNaming
+
+namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations
+{
+ public class Block8x8F_CopyTo1x1
+ {
+ private Block8x8F block;
+
+ private Buffer2D buffer;
+
+ private BufferArea destArea;
+
+ [GlobalSetup]
+ public void Setup()
+ {
+ if (!SimdUtils.IsAvx2CompatibleArchitecture)
+ {
+ throw new InvalidOperationException("Benchmark Block8x8F_CopyTo1x1 is invalid on platforms without AVX2 support.");
+ }
+
+ this.buffer = Configuration.Default.MemoryAllocator.Allocate2D(1000, 500);
+ this.destArea = this.buffer.GetArea(200, 100, 64, 64);
+ }
+
+ [Benchmark(Baseline = true)]
+ public void Original()
+ {
+ ref byte selfBase = ref Unsafe.As(ref this.block);
+ ref byte destBase = ref Unsafe.As(ref this.destArea.GetReferenceToOrigin());
+ int destStride = this.destArea.Stride * sizeof(float);
+
+ CopyRowImpl(ref selfBase, ref destBase, destStride, 0);
+ CopyRowImpl(ref selfBase, ref destBase, destStride, 1);
+ CopyRowImpl(ref selfBase, ref destBase, destStride, 2);
+ CopyRowImpl(ref selfBase, ref destBase, destStride, 3);
+ CopyRowImpl(ref selfBase, ref destBase, destStride, 4);
+ CopyRowImpl(ref selfBase, ref destBase, destStride, 5);
+ CopyRowImpl(ref selfBase, ref destBase, destStride, 6);
+ CopyRowImpl(ref selfBase, ref destBase, destStride, 7);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static void CopyRowImpl(ref byte selfBase, ref byte destBase, int destStride, int row)
+ {
+ ref byte s = ref Unsafe.Add(ref selfBase, row * 8 * sizeof(float));
+ ref byte d = ref Unsafe.Add(ref destBase, row * destStride);
+ Unsafe.CopyBlock(ref d, ref s, 8 * sizeof(float));
+ }
+
+ [Benchmark]
+ public void UseVector8()
+ {
+ ref Block8x8F s = ref this.block;
+ ref float origin = ref this.destArea.GetReferenceToOrigin();
+ int stride = this.destArea.Stride;
+
+ ref Vector d0 = ref Unsafe.As>(ref origin);
+ ref Vector d1 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride));
+ ref Vector d2 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride * 2));
+ ref Vector d3 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride * 3));
+ ref Vector d4 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride * 4));
+ ref Vector d5 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride * 5));
+ ref Vector d6 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride * 6));
+ ref Vector d7 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride * 7));
+
+ Vector row0 = Unsafe.As>(ref s.V0L);
+ Vector row1 = Unsafe.As>(ref s.V1L);
+ Vector row2 = Unsafe.As>(ref s.V2L);
+ Vector row3 = Unsafe.As>(ref s.V3L);
+ Vector row4 = Unsafe.As>(ref s.V4L);
+ Vector row5 = Unsafe.As>(ref s.V5L);
+ Vector row6 = Unsafe.As>(ref s.V6L);
+ Vector row7 = Unsafe.As>(ref s.V7L);
+
+ d0 = row0;
+ d1 = row1;
+ d2 = row2;
+ d3 = row3;
+ d4 = row4;
+ d5 = row5;
+ d6 = row6;
+ d7 = row7;
+ }
+
+ [Benchmark]
+ public void UseVector8_V2()
+ {
+ ref Block8x8F s = ref this.block;
+ ref float origin = ref this.destArea.GetReferenceToOrigin();
+ int stride = this.destArea.Stride;
+
+ ref Vector d0 = ref Unsafe.As>(ref origin);
+ ref Vector d1 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride));
+ ref Vector d2 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride * 2));
+ ref Vector d3 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride * 3));
+ ref Vector d4 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride * 4));
+ ref Vector d5 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride * 5));
+ ref Vector d6 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride * 6));
+ ref Vector d7 = ref Unsafe.As>(ref Unsafe.Add(ref origin, stride * 7));
+
+ d0 = Unsafe.As>(ref s.V0L);
+ d1 = Unsafe.As>(ref s.V1L);
+ d2 = Unsafe.As>(ref s.V2L);
+ d3 = Unsafe.As>(ref s.V3L);
+ d4 = Unsafe.As>(ref s.V4L);
+ d5 = Unsafe.As>(ref s.V5L);
+ d6 = Unsafe.As>(ref s.V6L);
+ d7 = Unsafe.As>(ref s.V7L);
+ }
+
+ // RESULTS:
+ //
+ // Method | Mean | Error | StdDev | Scaled |
+ // -------------- |---------:|----------:|----------:|-------:|
+ // Original | 22.53 ns | 0.1660 ns | 0.1553 ns | 1.00 |
+ // UseVector8 | 21.59 ns | 0.3079 ns | 0.2571 ns | 0.96 |
+ // UseVector8_V2 | 22.57 ns | 0.1699 ns | 0.1506 ns | 1.00 |
+ //
+ // Conclusion:
+ // Doesn't worth to bother with this
+ }
+}
\ No newline at end of file
diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo2x2.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo2x2.cs
new file mode 100644
index 000000000..65176af5b
--- /dev/null
+++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_CopyTo2x2.cs
@@ -0,0 +1,404 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+using System.Numerics;
+using System.Runtime.CompilerServices;
+
+using BenchmarkDotNet.Attributes;
+
+using SixLabors.ImageSharp.Formats.Jpeg.Components;
+using SixLabors.ImageSharp.Memory;
+// ReSharper disable InconsistentNaming
+
+namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations
+{
+ public class Block8x8F_CopyTo2x2
+ {
+ private Block8x8F block;
+
+ private Buffer2D buffer;
+
+ private BufferArea destArea;
+
+ [GlobalSetup]
+ public void Setup()
+ {
+ this.buffer = Configuration.Default.MemoryAllocator.Allocate2D(1000, 500);
+ this.destArea = this.buffer.GetArea(200, 100, 128, 128);
+ }
+
+ [Benchmark(Baseline = true)]
+ public void Original()
+ {
+ ref float destBase = ref this.destArea.GetReferenceToOrigin();
+ int destStride = this.destArea.Stride;
+
+ ref Block8x8F src = ref this.block;
+
+ WidenCopyImpl2x2(ref src, ref destBase, 0, destStride);
+ WidenCopyImpl2x2(ref src, ref destBase, 1, destStride);
+ WidenCopyImpl2x2(ref src, ref destBase, 2, destStride);
+ WidenCopyImpl2x2(ref src, ref destBase, 3, destStride);
+ WidenCopyImpl2x2(ref src, ref destBase, 4, destStride);
+ WidenCopyImpl2x2(ref src, ref destBase, 5, destStride);
+ WidenCopyImpl2x2(ref src, ref destBase, 6, destStride);
+ WidenCopyImpl2x2(ref src, ref destBase, 7, destStride);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static void WidenCopyImpl2x2(ref Block8x8F src, ref float destBase, int row, int destStride)
+ {
+ ref Vector4 selfLeft = ref Unsafe.Add(ref src.V0L, 2 * row);
+ ref Vector4 selfRight = ref Unsafe.Add(ref selfLeft, 1);
+ ref float destLocalOrigo = ref Unsafe.Add(ref destBase, row * 2 * destStride);
+
+ Unsafe.Add(ref destLocalOrigo, 0) = selfLeft.X;
+ Unsafe.Add(ref destLocalOrigo, 1) = selfLeft.X;
+ Unsafe.Add(ref destLocalOrigo, 2) = selfLeft.Y;
+ Unsafe.Add(ref destLocalOrigo, 3) = selfLeft.Y;
+ Unsafe.Add(ref destLocalOrigo, 4) = selfLeft.Z;
+ Unsafe.Add(ref destLocalOrigo, 5) = selfLeft.Z;
+ Unsafe.Add(ref destLocalOrigo, 6) = selfLeft.W;
+ Unsafe.Add(ref destLocalOrigo, 7) = selfLeft.W;
+
+ Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 0) = selfRight.X;
+ Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 1) = selfRight.X;
+ Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 2) = selfRight.Y;
+ Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 3) = selfRight.Y;
+ Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 4) = selfRight.Z;
+ Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 5) = selfRight.Z;
+ Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 6) = selfRight.W;
+ Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, 8), 7) = selfRight.W;
+
+ Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 0) = selfLeft.X;
+ Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 1) = selfLeft.X;
+ Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 2) = selfLeft.Y;
+ Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 3) = selfLeft.Y;
+ Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 4) = selfLeft.Z;
+ Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 5) = selfLeft.Z;
+ Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 6) = selfLeft.W;
+ Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride), 7) = selfLeft.W;
+
+ Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 0) = selfRight.X;
+ Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 1) = selfRight.X;
+ Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 2) = selfRight.Y;
+ Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 3) = selfRight.Y;
+ Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 4) = selfRight.Z;
+ Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 5) = selfRight.Z;
+ Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 6) = selfRight.W;
+ Unsafe.Add(ref Unsafe.Add(ref destLocalOrigo, destStride + 8), 7) = selfRight.W;
+ }
+
+ [Benchmark]
+ public void Original_V2()
+ {
+ ref float destBase = ref this.destArea.GetReferenceToOrigin();
+ int destStride = this.destArea.Stride;
+
+ ref Block8x8F src = ref this.block;
+
+ WidenCopyImpl2x2_V2(ref src, ref destBase, 0, destStride);
+ WidenCopyImpl2x2_V2(ref src, ref destBase, 1, destStride);
+ WidenCopyImpl2x2_V2(ref src, ref destBase, 2, destStride);
+ WidenCopyImpl2x2_V2(ref src, ref destBase, 3, destStride);
+ WidenCopyImpl2x2_V2(ref src, ref destBase, 4, destStride);
+ WidenCopyImpl2x2_V2(ref src, ref destBase, 5, destStride);
+ WidenCopyImpl2x2_V2(ref src, ref destBase, 6, destStride);
+ WidenCopyImpl2x2_V2(ref src, ref destBase, 7, destStride);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static void WidenCopyImpl2x2_V2(ref Block8x8F src, ref float destBase, int row, int destStride)
+ {
+ ref Vector4 selfLeft = ref Unsafe.Add(ref src.V0L, 2 * row);
+ ref Vector4 selfRight = ref Unsafe.Add(ref selfLeft, 1);
+ ref float dest0 = ref Unsafe.Add(ref destBase, row * 2 * destStride);
+
+ Unsafe.Add(ref dest0, 0) = selfLeft.X;
+ Unsafe.Add(ref dest0, 1) = selfLeft.X;
+ Unsafe.Add(ref dest0, 2) = selfLeft.Y;
+ Unsafe.Add(ref dest0, 3) = selfLeft.Y;
+ Unsafe.Add(ref dest0, 4) = selfLeft.Z;
+ Unsafe.Add(ref dest0, 5) = selfLeft.Z;
+ Unsafe.Add(ref dest0, 6) = selfLeft.W;
+ Unsafe.Add(ref dest0, 7) = selfLeft.W;
+
+ ref float dest1 = ref Unsafe.Add(ref dest0, 8);
+
+ Unsafe.Add(ref dest1, 0) = selfRight.X;
+ Unsafe.Add(ref dest1, 1) = selfRight.X;
+ Unsafe.Add(ref dest1, 2) = selfRight.Y;
+ Unsafe.Add(ref dest1, 3) = selfRight.Y;
+ Unsafe.Add(ref dest1, 4) = selfRight.Z;
+ Unsafe.Add(ref dest1, 5) = selfRight.Z;
+ Unsafe.Add(ref dest1, 6) = selfRight.W;
+ Unsafe.Add(ref dest1, 7) = selfRight.W;
+
+ ref float dest2 = ref Unsafe.Add(ref dest0, destStride);
+
+ Unsafe.Add(ref dest2, 0) = selfLeft.X;
+ Unsafe.Add(ref dest2, 1) = selfLeft.X;
+ Unsafe.Add(ref dest2, 2) = selfLeft.Y;
+ Unsafe.Add(ref dest2, 3) = selfLeft.Y;
+ Unsafe.Add(ref dest2, 4) = selfLeft.Z;
+ Unsafe.Add(ref dest2, 5) = selfLeft.Z;
+ Unsafe.Add(ref dest2, 6) = selfLeft.W;
+ Unsafe.Add(ref dest2, 7) = selfLeft.W;
+
+ ref float dest3 = ref Unsafe.Add(ref dest2, 8);
+
+ Unsafe.Add(ref dest3, 0) = selfRight.X;
+ Unsafe.Add(ref dest3, 1) = selfRight.X;
+ Unsafe.Add(ref dest3, 2) = selfRight.Y;
+ Unsafe.Add(ref dest3, 3) = selfRight.Y;
+ Unsafe.Add(ref dest3, 4) = selfRight.Z;
+ Unsafe.Add(ref dest3, 5) = selfRight.Z;
+ Unsafe.Add(ref dest3, 6) = selfRight.W;
+ Unsafe.Add(ref dest3, 7) = selfRight.W;
+ }
+
+ [Benchmark]
+ public void UseVector2()
+ {
+ ref Vector2 destBase = ref Unsafe.As(ref this.destArea.GetReferenceToOrigin());
+ int destStride = this.destArea.Stride / 2;
+
+ ref Block8x8F src = ref this.block;
+
+ WidenCopyImpl2x2_Vector2(ref src, ref destBase, 0, destStride);
+ WidenCopyImpl2x2_Vector2(ref src, ref destBase, 1, destStride);
+ WidenCopyImpl2x2_Vector2(ref src, ref destBase, 2, destStride);
+ WidenCopyImpl2x2_Vector2(ref src, ref destBase, 3, destStride);
+ WidenCopyImpl2x2_Vector2(ref src, ref destBase, 4, destStride);
+ WidenCopyImpl2x2_Vector2(ref src, ref destBase, 5, destStride);
+ WidenCopyImpl2x2_Vector2(ref src, ref destBase, 6, destStride);
+ WidenCopyImpl2x2_Vector2(ref src, ref destBase, 7, destStride);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static void WidenCopyImpl2x2_Vector2(ref Block8x8F src, ref Vector2 destBase, int row, int destStride)
+ {
+ ref Vector4 sLeft = ref Unsafe.Add(ref src.V0L, 2 * row);
+ ref Vector4 sRight = ref Unsafe.Add(ref sLeft, 1);
+
+ ref Vector2 dTopLeft = ref Unsafe.Add(ref destBase, 2 * row * destStride);
+ ref Vector2 dTopRight = ref Unsafe.Add(ref dTopLeft, 4);
+ ref Vector2 dBottomLeft = ref Unsafe.Add(ref dTopLeft, destStride);
+ ref Vector2 dBottomRight = ref Unsafe.Add(ref dBottomLeft, 4);
+
+ var xLeft = new Vector2(sLeft.X);
+ var yLeft = new Vector2(sLeft.Y);
+ var zLeft = new Vector2(sLeft.Z);
+ var wLeft = new Vector2(sLeft.W);
+
+ var xRight = new Vector2(sRight.X);
+ var yRight = new Vector2(sRight.Y);
+ var zRight = new Vector2(sRight.Z);
+ var wRight = new Vector2(sRight.W);
+
+ dTopLeft = xLeft;
+ Unsafe.Add(ref dTopLeft, 1) = yLeft;
+ Unsafe.Add(ref dTopLeft, 2) = zLeft;
+ Unsafe.Add(ref dTopLeft, 3) = wLeft;
+
+ dTopRight = xRight;
+ Unsafe.Add(ref dTopRight, 1) = yRight;
+ Unsafe.Add(ref dTopRight, 2) = zRight;
+ Unsafe.Add(ref dTopRight, 3) = wRight;
+
+ dBottomLeft = xLeft;
+ Unsafe.Add(ref dBottomLeft, 1) = yLeft;
+ Unsafe.Add(ref dBottomLeft, 2) = zLeft;
+ Unsafe.Add(ref dBottomLeft, 3) = wLeft;
+
+ dBottomRight = xRight;
+ Unsafe.Add(ref dBottomRight, 1) = yRight;
+ Unsafe.Add(ref dBottomRight, 2) = zRight;
+ Unsafe.Add(ref dBottomRight, 3) = wRight;
+ }
+
+ [Benchmark]
+ public void UseVector4()
+ {
+ ref Vector2 destBase = ref Unsafe.As(ref this.destArea.GetReferenceToOrigin());
+ int destStride = this.destArea.Stride / 2;
+
+ ref Block8x8F src = ref this.block;
+
+ WidenCopyImpl2x2_Vector4(ref src, ref destBase, 0, destStride);
+ WidenCopyImpl2x2_Vector4(ref src, ref destBase, 1, destStride);
+ WidenCopyImpl2x2_Vector4(ref src, ref destBase, 2, destStride);
+ WidenCopyImpl2x2_Vector4(ref src, ref destBase, 3, destStride);
+ WidenCopyImpl2x2_Vector4(ref src, ref destBase, 4, destStride);
+ WidenCopyImpl2x2_Vector4(ref src, ref destBase, 5, destStride);
+ WidenCopyImpl2x2_Vector4(ref src, ref destBase, 6, destStride);
+ WidenCopyImpl2x2_Vector4(ref src, ref destBase, 7, destStride);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static void WidenCopyImpl2x2_Vector4(ref Block8x8F src, ref Vector2 destBase, int row, int destStride)
+ {
+ ref Vector4 sLeft = ref Unsafe.Add(ref src.V0L, 2 * row);
+ ref Vector4 sRight = ref Unsafe.Add(ref sLeft, 1);
+
+ ref Vector2 dTopLeft = ref Unsafe.Add(ref destBase, 2 * row * destStride);
+ ref Vector2 dTopRight = ref Unsafe.Add(ref dTopLeft, 4);
+ ref Vector2 dBottomLeft = ref Unsafe.Add(ref dTopLeft, destStride);
+ ref Vector2 dBottomRight = ref Unsafe.Add(ref dBottomLeft, 4);
+
+ var xLeft = new Vector4(sLeft.X);
+ var yLeft = new Vector4(sLeft.Y);
+ var zLeft = new Vector4(sLeft.Z);
+ var wLeft = new Vector4(sLeft.W);
+
+ var xRight = new Vector4(sRight.X);
+ var yRight = new Vector4(sRight.Y);
+ var zRight = new Vector4(sRight.Z);
+ var wRight = new Vector4(sRight.W);
+
+ Unsafe.As(ref dTopLeft) = xLeft;
+ Unsafe.As(ref Unsafe.Add(ref dTopLeft, 1)) = yLeft;
+ Unsafe.As(ref Unsafe.Add(ref dTopLeft, 2)) = zLeft;
+ Unsafe.As(ref Unsafe.Add(ref dTopLeft, 3)) = wLeft;
+
+ Unsafe.As(ref dTopRight) = xRight;
+ Unsafe.As(ref Unsafe.Add(ref dTopRight, 1)) = yRight;
+ Unsafe.As(ref Unsafe.Add(ref dTopRight, 2)) = zRight;
+ Unsafe.As(ref Unsafe.Add(ref dTopRight, 3)) = wRight;
+
+ Unsafe.As(ref dBottomLeft) = xLeft;
+ Unsafe.As(ref Unsafe.Add(ref dBottomLeft, 1)) = yLeft;
+ Unsafe.As(ref Unsafe.Add(ref dBottomLeft, 2)) = zLeft;
+ Unsafe.As(ref Unsafe.Add(ref dBottomLeft, 3)) = wLeft;
+
+ Unsafe.As(ref dBottomRight) = xRight;
+ Unsafe.As(ref Unsafe.Add(ref dBottomRight, 1)) = yRight;
+ Unsafe.As(ref Unsafe.Add(ref dBottomRight, 2)) = zRight;
+ Unsafe.As(ref Unsafe.Add(ref dBottomRight, 3)) = wRight;
+ }
+
+ [Benchmark]
+ public void UseVector4_SafeRightCorner()
+ {
+ ref Vector2 destBase = ref Unsafe.As(ref this.destArea.GetReferenceToOrigin());
+ int destStride = this.destArea.Stride / 2;
+
+ ref Block8x8F src = ref this.block;
+
+ WidenCopyImpl2x2_Vector4_SafeRightCorner(ref src, ref destBase, 0, destStride);
+ WidenCopyImpl2x2_Vector4_SafeRightCorner(ref src, ref destBase, 1, destStride);
+ WidenCopyImpl2x2_Vector4_SafeRightCorner(ref src, ref destBase, 2, destStride);
+ WidenCopyImpl2x2_Vector4_SafeRightCorner(ref src, ref destBase, 3, destStride);
+ WidenCopyImpl2x2_Vector4_SafeRightCorner(ref src, ref destBase, 4, destStride);
+ WidenCopyImpl2x2_Vector4_SafeRightCorner(ref src, ref destBase, 5, destStride);
+ WidenCopyImpl2x2_Vector4_SafeRightCorner(ref src, ref destBase, 6, destStride);
+ WidenCopyImpl2x2_Vector4_SafeRightCorner(ref src, ref destBase, 7, destStride);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static void WidenCopyImpl2x2_Vector4_SafeRightCorner(ref Block8x8F src, ref Vector2 destBase, int row, int destStride)
+ {
+ ref Vector4 sLeft = ref Unsafe.Add(ref src.V0L, 2 * row);
+ ref Vector4 sRight = ref Unsafe.Add(ref sLeft, 1);
+
+ ref Vector2 dTopLeft = ref Unsafe.Add(ref destBase, 2 * row * destStride);
+ ref Vector2 dBottomLeft = ref Unsafe.Add(ref dTopLeft, destStride);
+
+ var xLeft = new Vector4(sLeft.X);
+ var yLeft = new Vector4(sLeft.Y);
+ var zLeft = new Vector4(sLeft.Z);
+ var wLeft = new Vector4(sLeft.W);
+
+ var xRight = new Vector4(sRight.X);
+ var yRight = new Vector4(sRight.Y);
+ var zRight = new Vector4(sRight.Z);
+ var wRight = new Vector2(sRight.W);
+
+ Unsafe.As(ref dTopLeft) = xLeft;
+ Unsafe.As(ref Unsafe.Add(ref dTopLeft, 1)) = yLeft;
+ Unsafe.As(ref Unsafe.Add(ref dTopLeft, 2)) = zLeft;
+ Unsafe.As(ref Unsafe.Add(ref dTopLeft, 3)) = wLeft;
+
+ Unsafe.As(ref Unsafe.Add(ref dTopLeft, 4)) = xRight;
+ Unsafe.As(ref Unsafe.Add(ref dTopLeft, 5)) = yRight;
+ Unsafe.As(ref Unsafe.Add(ref dTopLeft, 6)) = zRight;
+ Unsafe.Add(ref dTopLeft, 7) = wRight;
+
+ Unsafe.As(ref dBottomLeft) = xLeft;
+ Unsafe.As