diff --git a/.gitattributes b/.gitattributes
index 70ced6903..355b64dce 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -87,7 +87,6 @@
*.eot binary
*.exe binary
*.otf binary
-*.pbm binary
*.pdf binary
*.ppt binary
*.pptx binary
@@ -95,7 +94,6 @@
*.snk binary
*.ttc binary
*.ttf binary
-*.wbmp binary
*.woff binary
*.woff2 binary
*.xls binary
@@ -126,3 +124,9 @@
*.dds filter=lfs diff=lfs merge=lfs -text
*.ktx filter=lfs diff=lfs merge=lfs -text
*.ktx2 filter=lfs diff=lfs merge=lfs -text
+*.pam filter=lfs diff=lfs merge=lfs -text
+*.pbm filter=lfs diff=lfs merge=lfs -text
+*.pgm filter=lfs diff=lfs merge=lfs -text
+*.ppm filter=lfs diff=lfs merge=lfs -text
+*.pnm filter=lfs diff=lfs merge=lfs -text
+*.wbmp filter=lfs diff=lfs merge=lfs -text
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
index 1326c72e8..62a8bf2b4 100644
--- a/.github/ISSUE_TEMPLATE/config.yml
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -1,8 +1,5 @@
blank_issues_enabled: false
contact_links:
- - name: Ask a Question
- url: https://github.com/SixLabors/ImageSharp/discussions?discussions_q=category%3AQ%26A
- about: Ask a question about this project.
- name: Feature Request
url: https://github.com/SixLabors/ImageSharp/discussions?discussions_q=category%3AIdeas
about: Share ideas for new features for this project.
diff --git a/.github/ISSUE_TEMPLATE/oss-bug-report.md b/.github/ISSUE_TEMPLATE/oss-bug-report.md
index e0d37de53..9e9567a99 100644
--- a/.github/ISSUE_TEMPLATE/oss-bug-report.md
+++ b/.github/ISSUE_TEMPLATE/oss-bug-report.md
@@ -1,6 +1,6 @@
---
name: "OSS : Bug Report"
-about: Create a report to help us improve the project.
+about: Create a report to help us improve the project. OSS Issues are not guaranteed to be triaged.
labels: needs triage
---
diff --git a/Directory.Build.props b/Directory.Build.props
index 3899ce939..26b3cc5af 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -13,6 +13,9 @@
$(MSBuildThisFileDirectory)
+
+
+ $(DefineConstants);DEBUG
@@ -30,5 +33,4 @@
true
-
diff --git a/README.md b/README.md
index ab16bbb76..fdf14b496 100644
--- a/README.md
+++ b/README.md
@@ -20,7 +20,7 @@ ImageSharp is a new, fully featured, fully managed, cross-platform, 2D graphics
ImageSharp is designed from the ground up to be flexible and extensible. The library provides API endpoints for common image processing operations and the building blocks to allow for the development of additional operations.
-Built against [.NET Standard 1.3](https://docs.microsoft.com/en-us/dotnet/standard/net-standard), ImageSharp can be used in device, cloud, and embedded/IoT scenarios.
+Built against [.NET Standard 2.0](https://docs.microsoft.com/en-us/dotnet/standard/net-standard), ImageSharp can be used in device, cloud, and embedded/IoT scenarios.
## License
diff --git a/shared-infrastructure b/shared-infrastructure
index a042aba17..59ce17f5a 160000
--- a/shared-infrastructure
+++ b/shared-infrastructure
@@ -1 +1 @@
-Subproject commit a042aba176cdb840d800c6ed4cfe41a54fb7b1e3
+Subproject commit 59ce17f5a4e1f956811133f41add7638e74c2836
diff --git a/src/ImageSharp/Advanced/AdvancedImageExtensions.cs b/src/ImageSharp/Advanced/AdvancedImageExtensions.cs
index 54a773be0..829c6155d 100644
--- a/src/ImageSharp/Advanced/AdvancedImageExtensions.cs
+++ b/src/ImageSharp/Advanced/AdvancedImageExtensions.cs
@@ -143,7 +143,7 @@ namespace SixLabors.ImageSharp.Advanced
/// The source.
/// The row.
/// The
- public static Memory GetPixelRowMemory(this ImageFrame source, int rowIndex)
+ public static Memory DangerousGetPixelRowMemory(this ImageFrame source, int rowIndex)
where TPixel : unmanaged, IPixel
{
Guard.NotNull(source, nameof(source));
@@ -161,7 +161,7 @@ namespace SixLabors.ImageSharp.Advanced
/// The source.
/// The row.
/// The
- public static Memory GetPixelRowMemory(this Image source, int rowIndex)
+ public static Memory DangerousGetPixelRowMemory(this Image source, int rowIndex)
where TPixel : unmanaged, IPixel
{
Guard.NotNull(source, nameof(source));
diff --git a/src/ImageSharp/Advanced/AotCompilerTools.cs b/src/ImageSharp/Advanced/AotCompilerTools.cs
index 3961cc6c5..82a146dc7 100644
--- a/src/ImageSharp/Advanced/AotCompilerTools.cs
+++ b/src/ImageSharp/Advanced/AotCompilerTools.cs
@@ -10,6 +10,7 @@ using SixLabors.ImageSharp.Formats.Bmp;
using SixLabors.ImageSharp.Formats.Gif;
using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Formats.Jpeg.Components;
+using SixLabors.ImageSharp.Formats.Pbm;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.Formats.Tga;
using SixLabors.ImageSharp.Formats.Tiff;
@@ -74,6 +75,7 @@ namespace SixLabors.ImageSharp.Advanced
Seed();
Seed();
+ Seed();
Seed();
Seed();
Seed();
@@ -148,6 +150,7 @@ namespace SixLabors.ImageSharp.Advanced
Image img = default;
img.CloneAs(default);
img.CloneAs(default);
+ img.CloneAs(default);
img.CloneAs(default);
img.CloneAs(default);
img.CloneAs(default);
@@ -200,6 +203,7 @@ namespace SixLabors.ImageSharp.Advanced
default(BmpEncoderCore).Encode(default, default, default);
default(GifEncoderCore).Encode(default, default, default);
default(JpegEncoderCore).Encode(default, default, default);
+ default(PbmEncoderCore).Encode(default, default, default);
default(PngEncoderCore).Encode(default, default, default);
default(TgaEncoderCore).Encode(default, default, default);
default(TiffEncoderCore).Encode(default, default, default);
@@ -217,6 +221,7 @@ namespace SixLabors.ImageSharp.Advanced
default(BmpDecoderCore).Decode(default, default, default);
default(GifDecoderCore).Decode(default, default, default);
default(JpegDecoderCore).Decode(default, default, default);
+ default(PbmDecoderCore).Decode(default, default, default);
default(PngDecoderCore).Decode(default, default, default);
default(TgaDecoderCore).Decode(default, default, default);
default(TiffDecoderCore).Decode(default, default, default);
@@ -234,6 +239,7 @@ namespace SixLabors.ImageSharp.Advanced
AotCompileImageEncoder();
AotCompileImageEncoder();
AotCompileImageEncoder();
+ AotCompileImageEncoder();
AotCompileImageEncoder();
AotCompileImageEncoder();
AotCompileImageEncoder();
@@ -251,6 +257,7 @@ namespace SixLabors.ImageSharp.Advanced
AotCompileImageDecoder();
AotCompileImageDecoder();
AotCompileImageDecoder();
+ AotCompileImageDecoder();
AotCompileImageDecoder();
AotCompileImageDecoder();
AotCompileImageDecoder();
@@ -529,7 +536,7 @@ namespace SixLabors.ImageSharp.Advanced
private static void AotCompileMemoryManagers()
where TPixel : unmanaged, IPixel
{
- AotCompileMemoryManager();
+ AotCompileMemoryManager();
AotCompileMemoryManager();
}
diff --git a/src/ImageSharp/Color/Color.Conversions.cs b/src/ImageSharp/Color/Color.Conversions.cs
index bf7869e53..5c10bfaa0 100644
--- a/src/ImageSharp/Color/Color.Conversions.cs
+++ b/src/ImageSharp/Color/Color.Conversions.cs
@@ -89,6 +89,17 @@ namespace SixLabors.ImageSharp
this.boxedHighPrecisionPixel = null;
}
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The containing the color information.
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public Color(Abgr32 pixel)
+ {
+ this.data = new Rgba64(pixel);
+ this.boxedHighPrecisionPixel = null;
+ }
+
///
/// Initializes a new instance of the struct.
///
@@ -177,6 +188,19 @@ namespace SixLabors.ImageSharp
return value;
}
+ [MethodImpl(InliningOptions.ShortMethod)]
+ internal Abgr32 ToAbgr32()
+ {
+ if (this.boxedHighPrecisionPixel is null)
+ {
+ return this.data.ToAbgr32();
+ }
+
+ Abgr32 value = default;
+ value.FromScaledVector4(this.boxedHighPrecisionPixel.ToScaledVector4());
+ return value;
+ }
+
[MethodImpl(InliningOptions.ShortMethod)]
internal Rgb24 ToRgb24()
{
diff --git a/src/ImageSharp/Color/Color.cs b/src/ImageSharp/Color/Color.cs
index 7c21d62dd..cd0583361 100644
--- a/src/ImageSharp/Color/Color.cs
+++ b/src/ImageSharp/Color/Color.cs
@@ -270,8 +270,15 @@ namespace SixLabors.ImageSharp
return pixel;
}
+ if (this.boxedHighPrecisionPixel is null)
+ {
+ pixel = default;
+ pixel.FromRgba64(this.data);
+ return pixel;
+ }
+
pixel = default;
- pixel.FromRgba64(this.data);
+ pixel.FromScaledVector4(this.boxedHighPrecisionPixel.ToScaledVector4());
return pixel;
}
diff --git a/src/ImageSharp/Common/Helpers/DebugGuard.cs b/src/ImageSharp/Common/Helpers/DebugGuard.cs
index f56cb37a8..f438ca9e2 100644
--- a/src/ImageSharp/Common/Helpers/DebugGuard.cs
+++ b/src/ImageSharp/Common/Helpers/DebugGuard.cs
@@ -26,6 +26,20 @@ namespace SixLabors
}
}
+ ///
+ /// Verifies whether a condition (indicating disposed state) is met, throwing an ObjectDisposedException if it's true.
+ ///
+ /// Whether the object is disposed.
+ /// The name of the object.
+ [Conditional("DEBUG")]
+ public static void NotDisposed(bool isDisposed, string objectName)
+ {
+ if (isDisposed)
+ {
+ throw new ObjectDisposedException(objectName);
+ }
+ }
+
///
/// Verifies, that the target span is of same size than the 'other' span.
///
diff --git a/src/ImageSharp/Common/Helpers/Guard.cs b/src/ImageSharp/Common/Helpers/Guard.cs
index 0b5cc21cb..0f6efcb3c 100644
--- a/src/ImageSharp/Common/Helpers/Guard.cs
+++ b/src/ImageSharp/Common/Helpers/Guard.cs
@@ -2,9 +2,6 @@
// Licensed under the Apache License, Version 2.0.
using System;
-#if NETSTANDARD1_3
-using System.Reflection;
-#endif
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp;
@@ -22,11 +19,7 @@ namespace SixLabors
[MethodImpl(InliningOptions.ShortMethod)]
public static void MustBeValueType(TValue value, string parameterName)
{
- if (value.GetType()
-#if NETSTANDARD1_3
- .GetTypeInfo()
-#endif
- .IsValueType)
+ if (value.GetType().IsValueType)
{
return;
}
diff --git a/src/ImageSharp/Common/Helpers/Numerics.cs b/src/ImageSharp/Common/Helpers/Numerics.cs
index fa0af823d..513db0c44 100644
--- a/src/ImageSharp/Common/Helpers/Numerics.cs
+++ b/src/ImageSharp/Common/Helpers/Numerics.cs
@@ -907,5 +907,61 @@ namespace SixLabors.ImageSharp
/// Divisor value.
/// Ceiled division result.
public static uint DivideCeil(uint value, uint divisor) => (value + divisor - 1) / divisor;
+
+ ///
+ /// Rotates the specified value left by the specified number of bits.
+ ///
+ /// The value to rotate.
+ /// The number of bits to rotate with.
+ /// The rotated value.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static uint RotateLeft(uint value, int offset)
+ {
+#if SUPPORTS_BITOPERATIONS
+ return BitOperations.RotateLeft(value, offset);
+#else
+ return RotateLeftSoftwareFallback(value, offset);
+#endif
+ }
+
+#if !SUPPORTS_BITOPERATIONS
+ ///
+ /// Rotates the specified value left by the specified number of bits.
+ ///
+ /// The value to rotate.
+ /// The number of bits to rotate with.
+ /// The rotated value.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static uint RotateLeftSoftwareFallback(uint value, int offset)
+ => (value << offset) | (value >> (32 - offset));
+#endif
+
+ ///
+ /// Rotates the specified value right by the specified number of bits.
+ ///
+ /// The value to rotate.
+ /// The number of bits to rotate with.
+ /// The rotated value.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static uint RotateRight(uint value, int offset)
+ {
+#if SUPPORTS_BITOPERATIONS
+ return BitOperations.RotateRight(value, offset);
+#else
+ return RotateRightSoftwareFallback(value, offset);
+#endif
+ }
+
+#if !SUPPORTS_BITOPERATIONS
+ ///
+ /// Rotates the specified value right by the specified number of bits.
+ ///
+ /// The value to rotate.
+ /// The number of bits to rotate with.
+ /// The rotated value.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static uint RotateRightSoftwareFallback(uint value, int offset)
+ => (value >> offset) | (value << (32 - offset));
+#endif
}
}
diff --git a/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs b/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs
index 7687a5b95..049c61185 100644
--- a/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs
+++ b/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs
@@ -28,6 +28,10 @@ namespace SixLabors.ImageSharp
///
/// The source span of bytes.
/// The destination span of bytes.
+ ///
+ /// Implementation can assume that source.Length is less or equal than dest.Length.
+ /// Loops should iterate using source.Length.
+ ///
void RunFallbackShuffle(ReadOnlySpan source, Span dest);
}
@@ -153,7 +157,7 @@ namespace SixLabors.ImageSharp
// packed = [W Z Y X]
// ROTR(8, packedArgb) = [Y Z W X]
- Unsafe.Add(ref dBase, i) = (packed >> 8) | (packed << 24);
+ Unsafe.Add(ref dBase, i) = Numerics.RotateRight(packed, 8);
}
}
}
@@ -184,7 +188,40 @@ namespace SixLabors.ImageSharp
// tmp1 + tmp3 = [W X Y Z]
uint tmp1 = packed & 0xFF00FF00;
uint tmp2 = packed & 0x00FF00FF;
- uint tmp3 = (tmp2 << 16) | (tmp2 >> 16);
+ uint tmp3 = Numerics.RotateLeft(tmp2, 16);
+
+ Unsafe.Add(ref dBase, i) = tmp1 + tmp3;
+ }
+ }
+ }
+
+ internal readonly struct XWZYShuffle4 : IShuffle4
+ {
+ public byte Control
+ {
+ [MethodImpl(InliningOptions.ShortMethod)]
+ get => SimdUtils.Shuffle.MmShuffle(1, 2, 3, 0);
+ }
+
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public void RunFallbackShuffle(ReadOnlySpan source, Span dest)
+ {
+ ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source));
+ ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest));
+ int n = source.Length / 4;
+
+ for (int i = 0; i < n; i++)
+ {
+ uint packed = Unsafe.Add(ref sBase, i);
+
+ // packed = [W Z Y X]
+ // tmp1 = [0 Z 0 X]
+ // tmp2 = [W 0 Y 0]
+ // tmp3=ROTL(16, tmp2) = [Y 0 W 0]
+ // tmp1 + tmp3 = [Y Z W X]
+ uint tmp1 = packed & 0x00FF00FF;
+ uint tmp2 = packed & 0xFF00FF00;
+ uint tmp3 = Numerics.RotateLeft(tmp2, 16);
Unsafe.Add(ref dBase, i) = tmp1 + tmp3;
}
diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.Shuffle.cs b/src/ImageSharp/Common/Helpers/SimdUtils.Shuffle.cs
index 07744566a..abf9e9fed 100644
--- a/src/ImageSharp/Common/Helpers/SimdUtils.Shuffle.cs
+++ b/src/ImageSharp/Common/Helpers/SimdUtils.Shuffle.cs
@@ -77,6 +77,7 @@ namespace SixLabors.ImageSharp
TShuffle shuffle)
where TShuffle : struct, IShuffle3
{
+ // Source length should be smaller than dest length, and divisible by 3.
VerifyShuffle3SpanInput(source, dest);
#if SUPPORTS_RUNTIME_INTRINSICS
@@ -182,9 +183,9 @@ namespace SixLabors.ImageSharp
where T : struct
{
DebugGuard.IsTrue(
- source.Length == dest.Length,
+ source.Length <= dest.Length,
nameof(source),
- "Input spans must be of same length!");
+ "Source should fit into dest!");
DebugGuard.IsTrue(
source.Length % 3 == 0,
diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.cs b/src/ImageSharp/Common/Helpers/SimdUtils.cs
index 6d82cfad0..29068a82c 100644
--- a/src/ImageSharp/Common/Helpers/SimdUtils.cs
+++ b/src/ImageSharp/Common/Helpers/SimdUtils.cs
@@ -33,18 +33,6 @@ namespace SixLabors.ImageSharp
public static bool HasVector4 { get; } =
Vector.IsHardwareAccelerated && Vector.Count == 4;
- public static bool HasAvx2
- {
- get
- {
-#if SUPPORTS_RUNTIME_INTRINSICS
- return Avx2.IsSupported;
-#else
- return false;
-#endif
- }
- }
-
///
/// Transform all scalars in 'v' in a way that converting them to would have rounding semantics.
///
diff --git a/src/ImageSharp/Common/Tuples/Vector4Pair.cs b/src/ImageSharp/Common/Tuples/Vector4Pair.cs
deleted file mode 100644
index 6294a6177..000000000
--- a/src/ImageSharp/Common/Tuples/Vector4Pair.cs
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright (c) Six Labors.
-// Licensed under the Apache License, Version 2.0.
-
-using System.Numerics;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-namespace SixLabors.ImageSharp.Tuples
-{
- ///
- /// Its faster to process multiple Vector4-s together, so let's pair them!
- /// On AVX2 this pair should be convertible to of !
- /// TODO: Investigate defining this as union with an Octet.OfSingle type.
- ///
- [StructLayout(LayoutKind.Sequential)]
- internal struct Vector4Pair
- {
- public Vector4 A;
-
- public Vector4 B;
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void MultiplyInplace(float value)
- {
- this.A *= value;
- this.B *= value;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void AddInplace(Vector4 value)
- {
- this.A += value;
- this.B += value;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void AddInplace(ref Vector4Pair other)
- {
- this.A += other.A;
- this.B += other.B;
- }
-
- /// .
- /// Downscale method, specific to Jpeg color conversion. Works only if Vector{float}.Count == 4! /// TODO: Move it somewhere else.
- ///
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal void RoundAndDownscalePreVector8(float downscaleFactor)
- {
- ref Vector a = ref Unsafe.As>(ref this.A);
- a = a.FastRound();
-
- ref Vector b = ref Unsafe.As>(ref this.B);
- b = b.FastRound();
-
- // Downscale by 1/factor
- var scale = new Vector4(1 / downscaleFactor);
- this.A *= scale;
- this.B *= scale;
- }
-
- ///
- /// AVX2-only Downscale method, specific to Jpeg color conversion.
- /// TODO: Move it somewhere else.
- ///
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal void RoundAndDownscaleVector8(float downscaleFactor)
- {
- ref Vector self = ref Unsafe.As>(ref this);
- Vector v = self;
- v = v.FastRound();
-
- // Downscale by 1/factor
- v *= new Vector(1 / downscaleFactor);
- self = v;
- }
-
- public override string ToString()
- {
- return $"{nameof(Vector4Pair)}({this.A}, {this.B})";
- }
- }
-}
diff --git a/src/ImageSharp/Configuration.cs b/src/ImageSharp/Configuration.cs
index ea9524827..ca83b0764 100644
--- a/src/ImageSharp/Configuration.cs
+++ b/src/ImageSharp/Configuration.cs
@@ -8,6 +8,7 @@ using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Formats.Bmp;
using SixLabors.ImageSharp.Formats.Gif;
using SixLabors.ImageSharp.Formats.Jpeg;
+using SixLabors.ImageSharp.Formats.Pbm;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.Formats.Tga;
using SixLabors.ImageSharp.Formats.Tiff;
@@ -26,10 +27,11 @@ namespace SixLabors.ImageSharp
///
/// A lazily initialized configuration default instance.
///
- private static readonly Lazy Lazy = new Lazy(CreateDefaultInstance);
+ private static readonly Lazy Lazy = new(CreateDefaultInstance);
private const int DefaultStreamProcessingBufferSize = 8096;
private int streamProcessingBufferSize = DefaultStreamProcessingBufferSize;
private int maxDegreeOfParallelism = Environment.ProcessorCount;
+ private MemoryAllocator memoryAllocator = MemoryAllocator.Default;
///
/// Initializes a new instance of the class.
@@ -95,6 +97,14 @@ namespace SixLabors.ImageSharp
}
}
+ ///
+ /// Gets or sets a value indicating whether to force image buffers to be contiguous whenever possible.
+ ///
+ ///
+ /// Contiguous allocations are not possible, if the image needs a buffer larger than .
+ ///
+ public bool PreferContiguousImageBuffers { get; set; }
+
///
/// Gets a set of properties for the Configuration.
///
@@ -117,9 +127,31 @@ namespace SixLabors.ImageSharp
public ImageFormatManager ImageFormatsManager { get; set; } = new ImageFormatManager();
///
- /// Gets or sets the that is currently in use.
+ /// Gets or sets the that is currently in use.
+ /// Defaults to .
+ ///
+ /// Allocators are expensive, so it is strongly recommended to use only one busy instance per process.
+ /// In case you need to customize it, you can ensure this by changing
///
- public MemoryAllocator MemoryAllocator { get; set; } = ArrayPoolMemoryAllocator.CreateDefault();
+ ///
+ /// It's possible to reduce allocator footprint by assigning a custom instance created with
+ /// , but note that since the default pooling
+ /// allocators are expensive, it is strictly recommended to use a single process-wide allocator.
+ /// You can ensure this by altering the allocator of , or by implementing custom application logic that
+ /// manages allocator lifetime.
+ ///
+ /// If an allocator has to be dropped for some reason,
+ /// shall be invoked after disposing all associated instances.
+ ///
+ public MemoryAllocator MemoryAllocator
+ {
+ get => this.memoryAllocator;
+ set
+ {
+ Guard.NotNull(value, nameof(this.MemoryAllocator));
+ this.memoryAllocator = value;
+ }
+ }
///
/// Gets the maximum header size of all the formats.
@@ -165,7 +197,7 @@ namespace SixLabors.ImageSharp
MaxDegreeOfParallelism = this.MaxDegreeOfParallelism,
StreamProcessingBufferSize = this.StreamProcessingBufferSize,
ImageFormatsManager = this.ImageFormatsManager,
- MemoryAllocator = this.MemoryAllocator,
+ memoryAllocator = this.memoryAllocator,
ImageOperationsProvider = this.ImageOperationsProvider,
ReadOrigin = this.ReadOrigin,
FileSystem = this.FileSystem,
@@ -178,6 +210,7 @@ namespace SixLabors.ImageSharp
///
///
/// .
+ /// .
/// .
/// .
/// .
@@ -188,6 +221,7 @@ namespace SixLabors.ImageSharp
new JpegConfigurationModule(),
new GifConfigurationModule(),
new BmpConfigurationModule(),
+ new PbmConfigurationModule(),
new TgaConfigurationModule(),
new TiffConfigurationModule(),
new WebpConfigurationModule());
diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
index 8919befcb..41adc1cff 100644
--- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
+++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
@@ -306,7 +306,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
int newY = Invert(y, height, inverted);
int rowStartIdx = y * width;
Span bufferRow = bufferSpan.Slice(rowStartIdx, width);
- Span pixelRow = pixels.GetRowSpan(newY);
+ Span pixelRow = pixels.DangerousGetRowSpan(newY);
bool rowHasUndefinedPixels = rowsWithUndefinedPixelsSpan[y];
if (rowHasUndefinedPixels)
@@ -377,7 +377,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
for (int y = 0; y < height; y++)
{
int newY = Invert(y, height, inverted);
- Span pixelRow = pixels.GetRowSpan(newY);
+ Span pixelRow = pixels.DangerousGetRowSpan(newY);
bool rowHasUndefinedPixels = rowsWithUndefinedPixelsSpan[y];
if (rowHasUndefinedPixels)
{
@@ -826,7 +826,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
int newY = Invert(y, height, inverted);
this.stream.Read(rowSpan);
int offset = 0;
- Span pixelRow = pixels.GetRowSpan(newY);
+ Span pixelRow = pixels.DangerousGetRowSpan(newY);
for (int x = 0; x < arrayWidth; x++)
{
@@ -878,7 +878,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
{
this.stream.Read(bufferSpan);
int newY = Invert(y, height, inverted);
- Span pixelRow = pixels.GetRowSpan(newY);
+ Span pixelRow = pixels.DangerousGetRowSpan(newY);
int offset = 0;
for (int x = 0; x < width; x++)
@@ -933,7 +933,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
{
this.stream.Read(rowSpan);
int newY = Invert(y, height, inverted);
- Span pixelSpan = pixels.GetRowSpan(newY);
+ Span pixelSpan = pixels.DangerousGetRowSpan(newY);
PixelOperations.Instance.FromBgr24Bytes(
this.Configuration,
rowSpan,
@@ -961,7 +961,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
{
this.stream.Read(rowSpan);
int newY = Invert(y, height, inverted);
- Span pixelSpan = pixels.GetRowSpan(newY);
+ Span pixelSpan = pixels.DangerousGetRowSpan(newY);
PixelOperations.Instance.FromBgra32Bytes(
this.Configuration,
rowSpan,
@@ -1031,7 +1031,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
this.stream.Read(rowSpan);
int newY = Invert(y, height, inverted);
- Span pixelSpan = pixels.GetRowSpan(newY);
+ Span pixelSpan = pixels.DangerousGetRowSpan(newY);
PixelOperations.Instance.FromBgra32Bytes(
this.Configuration,
@@ -1054,7 +1054,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
width);
int newY = Invert(y, height, inverted);
- Span pixelSpan = pixels.GetRowSpan(newY);
+ Span pixelSpan = pixels.DangerousGetRowSpan(newY);
for (int x = 0; x < width; x++)
{
@@ -1109,7 +1109,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
{
this.stream.Read(bufferSpan);
int newY = Invert(y, height, inverted);
- Span pixelRow = pixels.GetRowSpan(newY);
+ Span pixelRow = pixels.DangerousGetRowSpan(newY);
int offset = 0;
for (int x = 0; x < width; x++)
diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
index c6ca5b09d..6384074df 100644
--- a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
+++ b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
@@ -274,7 +274,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
for (int y = pixels.Height - 1; y >= 0; y--)
{
- Span pixelSpan = pixels.GetRowSpan(y);
+ Span pixelSpan = pixels.DangerousGetRowSpan(y);
PixelOperations.Instance.ToBgra32Bytes(
this.configuration,
pixelSpan,
@@ -300,7 +300,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
for (int y = pixels.Height - 1; y >= 0; y--)
{
- Span pixelSpan = pixels.GetRowSpan(y);
+ Span pixelSpan = pixels.DangerousGetRowSpan(y);
PixelOperations.Instance.ToBgr24Bytes(
this.configuration,
pixelSpan,
@@ -326,7 +326,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
for (int y = pixels.Height - 1; y >= 0; y--)
{
- Span pixelSpan = pixels.GetRowSpan(y);
+ Span pixelSpan = pixels.DangerousGetRowSpan(y);
PixelOperations.Instance.ToBgra5551Bytes(
this.configuration,
@@ -379,7 +379,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
for (int y = image.Height - 1; y >= 0; y--)
{
- ReadOnlySpan pixelSpan = quantized.GetPixelRowSpan(y);
+ ReadOnlySpan pixelSpan = quantized.DangerousGetRowSpan(y);
stream.Write(pixelSpan);
for (int i = 0; i < this.padding; i++)
@@ -413,10 +413,10 @@ namespace SixLabors.ImageSharp.Formats.Bmp
}
stream.Write(colorPalette);
-
+ Buffer2D imageBuffer = image.PixelBuffer;
for (int y = image.Height - 1; y >= 0; y--)
{
- ReadOnlySpan inputPixelRow = image.GetPixelRowSpan(y);
+ ReadOnlySpan inputPixelRow = imageBuffer.DangerousGetRowSpan(y);
ReadOnlySpan outputPixelRow = MemoryMarshal.AsBytes(inputPixelRow);
stream.Write(outputPixelRow);
@@ -447,11 +447,11 @@ namespace SixLabors.ImageSharp.Formats.Bmp
ReadOnlySpan quantizedColorPalette = quantized.Palette.Span;
this.WriteColorPalette(stream, quantizedColorPalette, colorPalette);
- ReadOnlySpan pixelRowSpan = quantized.GetPixelRowSpan(0);
+ ReadOnlySpan pixelRowSpan = quantized.DangerousGetRowSpan(0);
int rowPadding = pixelRowSpan.Length % 2 != 0 ? this.padding - 1 : this.padding;
for (int y = image.Height - 1; y >= 0; y--)
{
- pixelRowSpan = quantized.GetPixelRowSpan(y);
+ pixelRowSpan = quantized.DangerousGetRowSpan(y);
int endIdx = pixelRowSpan.Length % 2 == 0 ? pixelRowSpan.Length : pixelRowSpan.Length - 1;
for (int i = 0; i < endIdx; i += 2)
@@ -491,11 +491,11 @@ namespace SixLabors.ImageSharp.Formats.Bmp
ReadOnlySpan quantizedColorPalette = quantized.Palette.Span;
this.WriteColorPalette(stream, quantizedColorPalette, colorPalette);
- ReadOnlySpan quantizedPixelRow = quantized.GetPixelRowSpan(0);
+ ReadOnlySpan quantizedPixelRow = quantized.DangerousGetRowSpan(0);
int rowPadding = quantizedPixelRow.Length % 8 != 0 ? this.padding - 1 : this.padding;
for (int y = image.Height - 1; y >= 0; y--)
{
- quantizedPixelRow = quantized.GetPixelRowSpan(y);
+ quantizedPixelRow = quantized.DangerousGetRowSpan(y);
int endIdx = quantizedPixelRow.Length % 8 == 0 ? quantizedPixelRow.Length : quantizedPixelRow.Length - 8;
for (int i = 0; i < endIdx; i += 8)
diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs
index 482a76153..3e33a6e37 100644
--- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs
+++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs
@@ -445,7 +445,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
for (int y = descriptorTop; y < descriptorBottom && y < imageHeight; y++)
{
- ref byte indicesRowRef = ref MemoryMarshal.GetReference(indices.GetRowSpan(y - descriptorTop));
+ ref byte indicesRowRef = ref MemoryMarshal.GetReference(indices.DangerousGetRowSpan(y - descriptorTop));
// Check if this image is interlaced.
int writeY; // the target y offset to write to
@@ -481,7 +481,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
writeY = y;
}
- ref TPixel rowRef = ref MemoryMarshal.GetReference(imageFrame.GetPixelRowSpan(writeY));
+ ref TPixel rowRef = ref MemoryMarshal.GetReference(imageFrame.PixelBuffer.DangerousGetRowSpan(writeY));
if (!transFlag)
{
diff --git a/src/ImageSharp/Formats/Gif/LzwDecoder.cs b/src/ImageSharp/Formats/Gif/LzwDecoder.cs
index 9eaa55566..68227db53 100644
--- a/src/ImageSharp/Formats/Gif/LzwDecoder.cs
+++ b/src/ImageSharp/Formats/Gif/LzwDecoder.cs
@@ -115,14 +115,14 @@ namespace SixLabors.ImageSharp.Formats.Gif
int y = 0;
int x = 0;
int rowMax = width;
- ref byte pixelsRowRef = ref MemoryMarshal.GetReference(pixels.GetRowSpan(y));
+ ref byte pixelsRowRef = ref MemoryMarshal.GetReference(pixels.DangerousGetRowSpan(y));
while (xyz < length)
{
// Reset row reference.
if (xyz == rowMax)
{
x = 0;
- pixelsRowRef = ref MemoryMarshal.GetReference(pixels.GetRowSpan(++y));
+ pixelsRowRef = ref MemoryMarshal.GetReference(pixels.DangerousGetRowSpan(++y));
rowMax = (y * width) + width;
}
diff --git a/src/ImageSharp/Formats/Gif/LzwEncoder.cs b/src/ImageSharp/Formats/Gif/LzwEncoder.cs
index e9fb7ab00..c52e34f96 100644
--- a/src/ImageSharp/Formats/Gif/LzwEncoder.cs
+++ b/src/ImageSharp/Formats/Gif/LzwEncoder.cs
@@ -275,7 +275,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
for (int y = 0; y < indexedPixels.Height; y++)
{
- ref byte rowSpanRef = ref MemoryMarshal.GetReference(indexedPixels.GetRowSpan(y));
+ ref byte rowSpanRef = ref MemoryMarshal.GetReference(indexedPixels.DangerousGetRowSpan(y));
int offsetX = y == 0 ? 1 : 0;
for (int x = offsetX; x < indexedPixels.Width; x++)
diff --git a/src/ImageSharp/Formats/ImageExtensions.Save.cs b/src/ImageSharp/Formats/ImageExtensions.Save.cs
index c5237f2bc..a6a65aef6 100644
--- a/src/ImageSharp/Formats/ImageExtensions.Save.cs
+++ b/src/ImageSharp/Formats/ImageExtensions.Save.cs
@@ -10,6 +10,7 @@ using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Formats.Bmp;
using SixLabors.ImageSharp.Formats.Gif;
using SixLabors.ImageSharp.Formats.Jpeg;
+using SixLabors.ImageSharp.Formats.Pbm;
using SixLabors.ImageSharp.Formats.Png;
using SixLabors.ImageSharp.Formats.Tga;
using SixLabors.ImageSharp.Formats.Webp;
@@ -331,6 +332,109 @@ namespace SixLabors.ImageSharp
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(JpegFormat.Instance),
cancellationToken);
+ ///
+ /// Saves the image to the given stream with the Pbm format.
+ ///
+ /// The image this method extends.
+ /// The file path to save the image to.
+ /// Thrown if the path is null.
+ public static void SaveAsPbm(this Image source, string path) => SaveAsPbm(source, path, null);
+
+ ///
+ /// Saves the image to the given stream with the Pbm format.
+ ///
+ /// The image this method extends.
+ /// The file path to save the image to.
+ /// Thrown if the path is null.
+ /// A representing the asynchronous operation.
+ public static Task SaveAsPbmAsync(this Image source, string path) => SaveAsPbmAsync(source, path, null);
+
+ ///
+ /// Saves the image to the given stream with the Pbm format.
+ ///
+ /// The image this method extends.
+ /// The file path to save the image to.
+ /// The token to monitor for cancellation requests.
+ /// Thrown if the path is null.
+ /// A representing the asynchronous operation.
+ public static Task SaveAsPbmAsync(this Image source, string path, CancellationToken cancellationToken)
+ => SaveAsPbmAsync(source, path, null, cancellationToken);
+
+ ///
+ /// Saves the image to the given stream with the Pbm format.
+ ///
+ /// The image this method extends.
+ /// The file path to save the image to.
+ /// The encoder to save the image with.
+ /// Thrown if the path is null.
+ public static void SaveAsPbm(this Image source, string path, PbmEncoder encoder) =>
+ source.Save(
+ path,
+ encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(PbmFormat.Instance));
+
+ ///
+ /// Saves the image to the given stream with the Pbm format.
+ ///
+ /// The image this method extends.
+ /// The file path to save the image to.
+ /// The encoder to save the image with.
+ /// The token to monitor for cancellation requests.
+ /// Thrown if the path is null.
+ /// A representing the asynchronous operation.
+ public static Task SaveAsPbmAsync(this Image source, string path, PbmEncoder encoder, CancellationToken cancellationToken = default) =>
+ source.SaveAsync(
+ path,
+ encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(PbmFormat.Instance),
+ cancellationToken);
+
+ ///
+ /// Saves the image to the given stream with the Pbm format.
+ ///
+ /// The image this method extends.
+ /// The stream to save the image to.
+ /// Thrown if the stream is null.
+ public static void SaveAsPbm(this Image source, Stream stream)
+ => SaveAsPbm(source, stream, null);
+
+ ///
+ /// Saves the image to the given stream with the Pbm format.
+ ///
+ /// The image this method extends.
+ /// The stream to save the image to.
+ /// The token to monitor for cancellation requests.
+ /// Thrown if the stream is null.
+ /// A representing the asynchronous operation.
+ public static Task SaveAsPbmAsync(this Image source, Stream stream, CancellationToken cancellationToken = default)
+ => SaveAsPbmAsync(source, stream, null, cancellationToken);
+
+ ///
+ /// Saves the image to the given stream with the Pbm format.
+ ///
+ /// The image this method extends.
+ /// The stream to save the image to.
+ /// The encoder to save the image with.
+ /// Thrown if the stream is null.
+ /// A representing the asynchronous operation.
+ public static void SaveAsPbm(this Image source, Stream stream, PbmEncoder encoder)
+ => source.Save(
+ stream,
+ encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(PbmFormat.Instance));
+
+ ///
+ /// Saves the image to the given stream with the Pbm format.
+ ///
+ /// The image this method extends.
+ /// The stream to save the image to.
+ /// The encoder to save the image with.
+ /// The token to monitor for cancellation requests.
+ /// Thrown if the stream is null.
+ /// A representing the asynchronous operation.
+ public static Task SaveAsPbmAsync(this Image source, Stream stream, PbmEncoder encoder, CancellationToken cancellationToken = default) =>
+ source.SaveAsync(
+ stream,
+ encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(PbmFormat.Instance),
+ cancellationToken);
+
///
/// Saves the image to the given stream with the Png format.
///
diff --git a/src/ImageSharp/Formats/ImageExtensions.Save.tt b/src/ImageSharp/Formats/ImageExtensions.Save.tt
index 874f3ab0d..c4a00b37c 100644
--- a/src/ImageSharp/Formats/ImageExtensions.Save.tt
+++ b/src/ImageSharp/Formats/ImageExtensions.Save.tt
@@ -15,6 +15,7 @@ using SixLabors.ImageSharp.Advanced;
"Bmp",
"Gif",
"Jpeg",
+ "Pbm",
"Png",
"Tga",
"Webp",
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8.Intrinsic.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8.Intrinsic.cs
new file mode 100644
index 000000000..002d382dc
--- /dev/null
+++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8.Intrinsic.cs
@@ -0,0 +1,39 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+#if SUPPORTS_RUNTIME_INTRINSICS
+using System.Runtime.InteropServices;
+using System.Runtime.Intrinsics;
+
+namespace SixLabors.ImageSharp.Formats.Jpeg.Components
+{
+ internal unsafe partial struct Block8x8
+ {
+ [FieldOffset(0)]
+ public Vector128 V0;
+ [FieldOffset(16)]
+ public Vector128 V1;
+ [FieldOffset(32)]
+ public Vector128 V2;
+ [FieldOffset(48)]
+ public Vector128 V3;
+ [FieldOffset(64)]
+ public Vector128 V4;
+ [FieldOffset(80)]
+ public Vector128 V5;
+ [FieldOffset(96)]
+ public Vector128 V6;
+ [FieldOffset(112)]
+ public Vector128 V7;
+
+ [FieldOffset(0)]
+ public Vector256 V01;
+ [FieldOffset(32)]
+ public Vector256 V23;
+ [FieldOffset(64)]
+ public Vector256 V45;
+ [FieldOffset(96)]
+ public Vector256 V67;
+ }
+}
+#endif
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8.cs
index 27bb2fc3c..4b03f9f7b 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8.cs
@@ -18,7 +18,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
///
// ReSharper disable once InconsistentNaming
[StructLayout(LayoutKind.Explicit)]
- internal unsafe struct Block8x8 : IEquatable
+ internal unsafe partial struct Block8x8
{
///
/// A number of scalar coefficients in a
@@ -36,34 +36,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
private fixed short data[Size];
#pragma warning restore IDE0051
-#if SUPPORTS_RUNTIME_INTRINSICS
- [FieldOffset(0)]
- public Vector128 V0;
- [FieldOffset(16)]
- public Vector128 V1;
- [FieldOffset(32)]
- public Vector128 V2;
- [FieldOffset(48)]
- public Vector128 V3;
- [FieldOffset(64)]
- public Vector128 V4;
- [FieldOffset(80)]
- public Vector128 V5;
- [FieldOffset(96)]
- public Vector128 V6;
- [FieldOffset(112)]
- public Vector128 V7;
-
- [FieldOffset(0)]
- public Vector256 V01;
- [FieldOffset(32)]
- public Vector256 V23;
- [FieldOffset(64)]
- public Vector256 V45;
- [FieldOffset(96)]
- public Vector256 V67;
-#endif
-
///
/// Gets or sets a value at the given index
///
@@ -102,74 +74,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
set => this[(y * 8) + x] = value;
}
- public static bool operator ==(Block8x8 left, Block8x8 right) => left.Equals(right);
-
- public static bool operator !=(Block8x8 left, Block8x8 right) => !left.Equals(right);
-
- ///
- /// Multiply all elements by a given
- ///
- public static Block8x8 operator *(Block8x8 block, int value)
- {
- Block8x8 result = block;
- for (int i = 0; i < Size; i++)
- {
- int val = result[i];
- val *= value;
- result[i] = (short)val;
- }
-
- return result;
- }
-
- ///
- /// Divide all elements by a given
- ///
- public static Block8x8 operator /(Block8x8 block, int value)
- {
- Block8x8 result = block;
- for (int i = 0; i < Size; i++)
- {
- int val = result[i];
- val /= value;
- result[i] = (short)val;
- }
-
- return result;
- }
-
- ///
- /// Add an to all elements
- ///
- public static Block8x8 operator +(Block8x8 block, int value)
- {
- Block8x8 result = block;
- for (int i = 0; i < Size; i++)
- {
- int val = result[i];
- val += value;
- result[i] = (short)val;
- }
-
- return result;
- }
-
- ///
- /// Subtract an from all elements
- ///
- public static Block8x8 operator -(Block8x8 block, int value)
- {
- Block8x8 result = block;
- for (int i = 0; i < Size; i++)
- {
- int val = result[i];
- val -= value;
- result[i] = (short)val;
- }
-
- return result;
- }
-
public static Block8x8 Load(Span data)
{
Unsafe.SkipInit(out Block8x8 result);
@@ -260,26 +164,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
return sb.ToString();
}
- ///
- public bool Equals(Block8x8 other)
- {
- for (int i = 0; i < Size; i++)
- {
- if (this[i] != other[i])
- {
- return false;
- }
- }
-
- return true;
- }
-
- ///
- public override bool Equals(object obj) => obj is Block8x8 other && this.Equals(other);
-
- ///
- public override int GetHashCode() => (this[0] * 31) + this[1];
-
///
/// Returns index of the last non-zero element in given matrix.
///
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs
index 02f5a1324..f25286447 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs
@@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0.
using System;
-using System.Diagnostics;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@@ -98,58 +97,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
set => this[(y * 8) + x] = value;
}
- public static Block8x8F operator *(Block8x8F block, float value)
- {
- Block8x8F result = block;
- for (int i = 0; i < Size; i++)
- {
- float val = result[i];
- val *= value;
- result[i] = val;
- }
-
- return result;
- }
-
- public static Block8x8F operator /(Block8x8F block, float value)
- {
- Block8x8F result = block;
- for (int i = 0; i < Size; i++)
- {
- float val = result[i];
- val /= value;
- result[i] = val;
- }
-
- return result;
- }
-
- public static Block8x8F operator +(Block8x8F block, float value)
- {
- Block8x8F result = block;
- for (int i = 0; i < Size; i++)
- {
- float val = result[i];
- val += value;
- result[i] = val;
- }
-
- return result;
- }
-
- public static Block8x8F operator -(Block8x8F block, float value)
- {
- Block8x8F result = block;
- for (int i = 0; i < Size; i++)
- {
- float val = result[i];
- val -= value;
- result[i] = val;
- }
-
- return result;
- }
-
public static Block8x8F Load(Span data)
{
Block8x8F result = default;
@@ -157,13 +104,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
return result;
}
- public static Block8x8F Load(Span data)
- {
- Block8x8F result = default;
- result.LoadFrom(data);
- return result;
- }
-
///
/// Load raw 32bit floating point data from source.
///
@@ -177,15 +117,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
Unsafe.CopyBlock(ref d, ref s, Size * sizeof(float));
}
- ///
- /// Load raw 32bit floating point data from source.
- ///
- /// Block pointer
- /// Source
- [MethodImpl(InliningOptions.ShortMethod)]
- public static unsafe void LoadFrom(Block8x8F* blockPtr, Span source)
- => blockPtr->LoadFrom(source);
-
///
/// Load raw 32bit floating point data from source
///
@@ -202,44 +133,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
}
}
- ///
- /// Copy raw 32bit floating point data to dest,
- ///
- /// Destination
- [MethodImpl(InliningOptions.ShortMethod)]
- public void ScaledCopyTo(Span dest)
- {
- ref byte d = ref Unsafe.As(ref MemoryMarshal.GetReference(dest));
- ref byte s = ref Unsafe.As(ref this);
-
- Unsafe.CopyBlock(ref d, ref s, Size * sizeof(float));
- }
-
- ///
- /// Convert scalars to byte-s and copy to dest,
- ///
- /// Pointer to block
- /// Destination
- [MethodImpl(InliningOptions.ShortMethod)]
- public static unsafe void ScaledCopyTo(Block8x8F* blockPtr, Span dest)
- {
- float* fPtr = (float*)blockPtr;
- for (int i = 0; i < Size; i++)
- {
- dest[i] = (byte)*fPtr;
- fPtr++;
- }
- }
-
- ///
- /// Copy raw 32bit floating point data to dest.
- ///
- /// The block pointer.
- /// The destination.
- [MethodImpl(InliningOptions.ShortMethod)]
- public static unsafe void ScaledCopyTo(Block8x8F* blockPtr, Span dest)
- => blockPtr->ScaledCopyTo(dest);
-
///
/// Copy raw 32bit floating point data to dest
///
@@ -253,22 +146,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
}
}
- ///
- /// Copy raw 32bit floating point data to dest
- ///
- /// Destination
- public unsafe void ScaledCopyTo(Span dest)
- {
- fixed (Vector4* ptr = &this.V0L)
- {
- var fp = (float*)ptr;
- for (int i = 0; i < Size; i++)
- {
- dest[i] = (int)fp[i];
- }
- }
- }
-
public float[] ToArray()
{
float[] result = new float[Size];
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.Avx2JpegColorConverter.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.Avx2JpegColorConverter.cs
deleted file mode 100644
index 90ebce3b8..000000000
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.Avx2JpegColorConverter.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright (c) Six Labors.
-// Licensed under the Apache License, Version 2.0.
-
-namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
-{
- internal abstract partial class JpegColorConverter
- {
- internal abstract class Avx2JpegColorConverter : VectorizedJpegColorConverter
- {
- protected Avx2JpegColorConverter(JpegColorSpace colorSpace, int precision)
- : base(colorSpace, precision, 8)
- {
- }
-
- protected sealed override bool IsAvailable => SimdUtils.HasAvx2;
- }
- }
-}
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.BasicJpegColorConverter.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.BasicJpegColorConverter.cs
deleted file mode 100644
index ed2e2cd76..000000000
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.BasicJpegColorConverter.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright (c) Six Labors.
-// Licensed under the Apache License, Version 2.0.
-
-namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
-{
- internal abstract partial class JpegColorConverter
- {
- internal abstract class BasicJpegColorConverter : JpegColorConverter
- {
- protected BasicJpegColorConverter(JpegColorSpace colorSpace, int precision)
- : base(colorSpace, precision)
- {
- }
-
- protected override bool IsAvailable => true;
- }
- }
-}
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykAvx.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykAvx.cs
new file mode 100644
index 000000000..7366ee30a
--- /dev/null
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykAvx.cs
@@ -0,0 +1,52 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+#if SUPPORTS_RUNTIME_INTRINSICS
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.X86;
+
+namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
+{
+ internal abstract partial class JpegColorConverterBase
+ {
+ internal sealed class FromCmykAvx : JpegColorConverterAvx
+ {
+ public FromCmykAvx(int precision)
+ : base(JpegColorSpace.Cmyk, precision)
+ {
+ }
+
+ public override void ConvertToRgbInplace(in ComponentValues values)
+ {
+ ref Vector256 c0Base =
+ ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0));
+ ref Vector256 c1Base =
+ ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component1));
+ ref Vector256 c2Base =
+ ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component2));
+ ref Vector256 c3Base =
+ ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component3));
+
+ // Used for the color conversion
+ var scale = Vector256.Create(1 / (this.MaximumValue * this.MaximumValue));
+
+ nint n = values.Component0.Length / Vector256.Count;
+ for (nint i = 0; i < n; i++)
+ {
+ ref Vector256 c = ref Unsafe.Add(ref c0Base, i);
+ ref Vector256 m = ref Unsafe.Add(ref c1Base, i);
+ ref Vector256 y = ref Unsafe.Add(ref c2Base, i);
+ Vector256 k = Unsafe.Add(ref c3Base, i);
+
+ k = Avx.Multiply(k, scale);
+ c = Avx.Multiply(c, k);
+ m = Avx.Multiply(m, k);
+ y = Avx.Multiply(y, k);
+ }
+ }
+ }
+ }
+}
+#endif
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykAvx2.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykAvx2.cs
deleted file mode 100644
index 216c12735..000000000
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykAvx2.cs
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright (c) Six Labors.
-// Licensed under the Apache License, Version 2.0.
-
-using System;
-using System.Numerics;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-#if SUPPORTS_RUNTIME_INTRINSICS
-using System.Runtime.Intrinsics;
-using System.Runtime.Intrinsics.X86;
-using static SixLabors.ImageSharp.SimdUtils;
-#endif
-
-namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
-{
- internal abstract partial class JpegColorConverter
- {
- internal sealed class FromCmykAvx2 : Avx2JpegColorConverter
- {
- public FromCmykAvx2(int precision)
- : base(JpegColorSpace.Cmyk, precision)
- {
- }
-
- protected override void ConvertCoreVectorizedInplace(in ComponentValues values)
- {
-#if SUPPORTS_RUNTIME_INTRINSICS
- ref Vector256 c0Base =
- ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0));
- ref Vector256 c1Base =
- ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component1));
- ref Vector256 c2Base =
- ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component2));
- ref Vector256 c3Base =
- ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component3));
-
- // Used for the color conversion
- var scale = Vector256.Create(1 / this.MaximumValue);
-
- nint n = values.Component0.Length / 8;
- for (nint i = 0; i < n; i++)
- {
- ref Vector256 c = ref Unsafe.Add(ref c0Base, i);
- ref Vector256 m = ref Unsafe.Add(ref c1Base, i);
- ref Vector256 y = ref Unsafe.Add(ref c2Base, i);
- Vector256 k = Unsafe.Add(ref c3Base, i);
-
- k = Avx.Multiply(k, scale);
- c = Avx.Multiply(Avx.Multiply(c, k), scale);
- m = Avx.Multiply(Avx.Multiply(m, k), scale);
- y = Avx.Multiply(Avx.Multiply(y, k), scale);
- }
-#endif
- }
-
- protected override void ConvertCoreInplace(in ComponentValues values) =>
- FromCmykBasic.ConvertCoreInplace(values, this.MaximumValue);
- }
- }
-}
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykBasic.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykScalar.cs
similarity index 67%
rename from src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykBasic.cs
rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykScalar.cs
index b0ad50301..68dfa9bfb 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykBasic.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykScalar.cs
@@ -1,16 +1,15 @@
-// Copyright (c) Six Labors.
+// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System;
-using System.Numerics;
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
{
- internal abstract partial class JpegColorConverter
+ internal abstract partial class JpegColorConverterBase
{
- internal sealed class FromCmykBasic : BasicJpegColorConverter
+ internal sealed class FromCmykScalar : JpegColorConverterScalar
{
- public FromCmykBasic(int precision)
+ public FromCmykScalar(int precision)
: base(JpegColorSpace.Cmyk, precision)
{
}
@@ -25,17 +24,18 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
Span c2 = values.Component2;
Span c3 = values.Component3;
- float scale = 1 / maxValue;
+ float scale = 1 / (maxValue * maxValue);
for (int i = 0; i < c0.Length; i++)
{
float c = c0[i];
float m = c1[i];
float y = c2[i];
- float k = c3[i] / maxValue;
+ float k = c3[i];
- c0[i] = c * k * scale;
- c1[i] = m * k * scale;
- c2[i] = y * k * scale;
+ k *= scale;
+ c0[i] = c * k;
+ c1[i] = m * k;
+ c2[i] = y * k;
}
}
}
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector.cs
new file mode 100644
index 000000000..6b7ed169e
--- /dev/null
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector.cs
@@ -0,0 +1,51 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using System.Numerics;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
+{
+ internal abstract partial class JpegColorConverterBase
+ {
+ internal sealed class FromCmykVector : JpegColorConverterVector
+ {
+ public FromCmykVector(int precision)
+ : base(JpegColorSpace.Cmyk, precision)
+ {
+ }
+
+ protected override void ConvertCoreVectorizedInplace(in ComponentValues values)
+ {
+ ref Vector cBase =
+ ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0));
+ ref Vector mBase =
+ ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component1));
+ ref Vector yBase =
+ ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component2));
+ ref Vector kBase =
+ ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component3));
+
+ var scale = new Vector(1 / (this.MaximumValue * this.MaximumValue));
+
+ nint n = values.Component0.Length / Vector.Count;
+ for (nint i = 0; i < n; i++)
+ {
+ ref Vector c = ref Unsafe.Add(ref cBase, i);
+ ref Vector m = ref Unsafe.Add(ref mBase, i);
+ ref Vector y = ref Unsafe.Add(ref yBase, i);
+ Vector k = Unsafe.Add(ref kBase, i);
+
+ k *= scale;
+ c *= k;
+ m *= k;
+ y *= k;
+ }
+ }
+
+ protected override void ConvertCoreInplace(in ComponentValues values) =>
+ FromCmykScalar.ConvertCoreInplace(values, this.MaximumValue);
+ }
+ }
+}
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector8.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector8.cs
deleted file mode 100644
index 0da4c9ec2..000000000
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmykVector8.cs
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright (c) Six Labors.
-// Licensed under the Apache License, Version 2.0.
-
-using System;
-using System.Numerics;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-using SixLabors.ImageSharp.Tuples;
-
-namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
-{
- internal abstract partial class JpegColorConverter
- {
- internal sealed class FromCmykVector8 : Vector8JpegColorConverter
- {
- public FromCmykVector8(int precision)
- : base(JpegColorSpace.Cmyk, precision)
- {
- }
-
- protected override void ConvertCoreVectorizedInplace(in ComponentValues values)
- {
- ref Vector cBase =
- ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0));
- ref Vector mBase =
- ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component1));
- ref Vector yBase =
- ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component2));
- ref Vector kBase =
- ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component3));
-
- var scale = new Vector(1 / this.MaximumValue);
-
- // Walking 8 elements at one step:
- nint n = values.Component0.Length / 8;
- for (nint i = 0; i < n; i++)
- {
- ref Vector c = ref Unsafe.Add(ref cBase, i);
- ref Vector m = ref Unsafe.Add(ref mBase, i);
- ref Vector y = ref Unsafe.Add(ref yBase, i);
- Vector k = Unsafe.Add(ref kBase, i) * scale;
-
- c = (c * k) * scale;
- m = (m * k) * scale;
- y = (y * k) * scale;
- }
- }
-
- protected override void ConvertCoreInplace(in ComponentValues values) =>
- FromCmykBasic.ConvertCoreInplace(values, this.MaximumValue);
- }
- }
-}
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleAvx2.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleAvx.cs
similarity index 59%
rename from src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleAvx2.cs
rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleAvx.cs
index eca6b6292..963543ad4 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleAvx2.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleAvx.cs
@@ -1,47 +1,39 @@
-// Copyright (c) Six Labors.
+// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
-using System;
-using System.Numerics;
+#if SUPPORTS_RUNTIME_INTRINSICS
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
-#if SUPPORTS_RUNTIME_INTRINSICS
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
-using static SixLabors.ImageSharp.SimdUtils;
-#endif
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
{
- internal abstract partial class JpegColorConverter
+ internal abstract partial class JpegColorConverterBase
{
- internal sealed class FromGrayscaleAvx2 : Avx2JpegColorConverter
+ internal sealed class FromGrayscaleAvx : JpegColorConverterAvx
{
- public FromGrayscaleAvx2(int precision)
+ public FromGrayscaleAvx(int precision)
: base(JpegColorSpace.Grayscale, precision)
{
}
- protected override void ConvertCoreVectorizedInplace(in ComponentValues values)
+ public override void ConvertToRgbInplace(in ComponentValues values)
{
-#if SUPPORTS_RUNTIME_INTRINSICS
ref Vector256 c0Base =
ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0));
// Used for the color conversion
var scale = Vector256.Create(1 / this.MaximumValue);
- nint n = values.Component0.Length / 8;
+ nint n = values.Component0.Length / Vector256.Count;
for (nint i = 0; i < n; i++)
{
ref Vector256 c0 = ref Unsafe.Add(ref c0Base, i);
c0 = Avx.Multiply(c0, scale);
}
-#endif
}
-
- protected override void ConvertCoreInplace(in ComponentValues values) =>
- FromGrayscaleBasic.ScaleValues(values.Component0, this.MaximumValue);
}
}
}
+#endif
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleBasic.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleBasic.cs
deleted file mode 100644
index 76d57bf06..000000000
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleBasic.cs
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright (c) Six Labors.
-// Licensed under the Apache License, Version 2.0.
-
-using System;
-using System.Numerics;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
-{
- internal abstract partial class JpegColorConverter
- {
- internal sealed class FromGrayscaleBasic : BasicJpegColorConverter
- {
- public FromGrayscaleBasic(int precision)
- : base(JpegColorSpace.Grayscale, precision)
- {
- }
-
- public override void ConvertToRgbInplace(in ComponentValues values) =>
- ScaleValues(values.Component0, this.MaximumValue);
-
- internal static void ScaleValues(Span values, float maxValue)
- {
- Span vecValues = MemoryMarshal.Cast(values);
-
- var scaleVector = new Vector4(1 / maxValue);
-
- for (int i = 0; i < vecValues.Length; i++)
- {
- vecValues[i] *= scaleVector;
- }
-
- values = values.Slice(vecValues.Length * 4);
- if (!values.IsEmpty)
- {
- float scaleValue = 1f / maxValue;
- values[0] *= scaleValue;
-
- if ((uint)values.Length > 1)
- {
- values[1] *= scaleValue;
-
- if ((uint)values.Length > 2)
- {
- values[2] *= scaleValue;
- }
- }
- }
- }
- }
- }
-}
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleScalar.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleScalar.cs
new file mode 100644
index 000000000..3f6a6caa4
--- /dev/null
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleScalar.cs
@@ -0,0 +1,34 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
+{
+ internal abstract partial class JpegColorConverterBase
+ {
+ internal sealed class FromGrayscaleScalar : JpegColorConverterScalar
+ {
+ public FromGrayscaleScalar(int precision)
+ : base(JpegColorSpace.Grayscale, precision)
+ {
+ }
+
+ public override void ConvertToRgbInplace(in ComponentValues values) =>
+ ConvertCoreInplace(values.Component0, this.MaximumValue);
+
+ internal static void ConvertCoreInplace(Span values, float maxValue)
+ {
+ ref float valuesRef = ref MemoryMarshal.GetReference(values);
+ float scale = 1 / maxValue;
+
+ for (nint i = 0; i < values.Length; i++)
+ {
+ Unsafe.Add(ref valuesRef, i) *= scale;
+ }
+ }
+ }
+ }
+}
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleVector.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleVector.cs
new file mode 100644
index 000000000..c484aac28
--- /dev/null
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScaleVector.cs
@@ -0,0 +1,38 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using System.Numerics;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
+{
+ internal abstract partial class JpegColorConverterBase
+ {
+ internal sealed class FromGrayScaleVector : JpegColorConverterVector
+ {
+ public FromGrayScaleVector(int precision)
+ : base(JpegColorSpace.Grayscale, precision)
+ {
+ }
+
+ protected override void ConvertCoreVectorizedInplace(in ComponentValues values)
+ {
+ ref Vector cBase =
+ ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0));
+
+ var scale = new Vector(1 / this.MaximumValue);
+
+ nint n = values.Component0.Length / Vector.Count;
+ for (nint i = 0; i < n; i++)
+ {
+ ref Vector c0 = ref Unsafe.Add(ref cBase, i);
+ c0 *= scale;
+ }
+ }
+
+ protected override void ConvertCoreInplace(in ComponentValues values) =>
+ FromGrayscaleScalar.ConvertCoreInplace(values.Component0, this.MaximumValue);
+ }
+ }
+}
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbAvx2.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbAvx.cs
similarity index 53%
rename from src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbAvx2.cs
rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbAvx.cs
index 557e4e417..f017716e3 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbAvx2.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbAvx.cs
@@ -1,40 +1,35 @@
-// Copyright (c) Six Labors.
+// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
-using System;
-using System.Numerics;
+#if SUPPORTS_RUNTIME_INTRINSICS
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
-#if SUPPORTS_RUNTIME_INTRINSICS
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
-using static SixLabors.ImageSharp.SimdUtils;
-#endif
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
{
- internal abstract partial class JpegColorConverter
+ internal abstract partial class JpegColorConverterBase
{
- internal sealed class FromRgbAvx2 : Avx2JpegColorConverter
+ internal sealed class FromRgbAvx : JpegColorConverterAvx
{
- public FromRgbAvx2(int precision)
+ public FromRgbAvx(int precision)
: base(JpegColorSpace.RGB, precision)
{
}
- protected override void ConvertCoreVectorizedInplace(in ComponentValues values)
+ public override void ConvertToRgbInplace(in ComponentValues values)
{
-#if SUPPORTS_RUNTIME_INTRINSICS
ref Vector256 rBase =
- ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0));
+ ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0));
ref Vector256 gBase =
- ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component1));
+ ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component1));
ref Vector256 bBase =
- ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component2));
+ ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component2));
// Used for the color conversion
var scale = Vector256.Create(1 / this.MaximumValue);
- nint n = values.Component0.Length / 8;
+ nint n = values.Component0.Length / Vector256.Count;
for (nint i = 0; i < n; i++)
{
ref Vector256 r = ref Unsafe.Add(ref rBase, i);
@@ -44,11 +39,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
g = Avx.Multiply(g, scale);
b = Avx.Multiply(b, scale);
}
-#endif
}
-
- protected override void ConvertCoreInplace(in ComponentValues values) =>
- FromRgbBasic.ConvertCoreInplace(values, this.MaximumValue);
}
}
}
+#endif
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbBasic.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbBasic.cs
deleted file mode 100644
index 1425e7b58..000000000
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbBasic.cs
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright (c) Six Labors.
-// Licensed under the Apache License, Version 2.0.
-
-using System;
-using System.Numerics;
-using System.Runtime.InteropServices;
-
-namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
-{
- internal abstract partial class JpegColorConverter
- {
- internal sealed class FromRgbBasic : BasicJpegColorConverter
- {
- public FromRgbBasic(int precision)
- : base(JpegColorSpace.RGB, precision)
- {
- }
-
- public override void ConvertToRgbInplace(in ComponentValues values)
- {
- ConvertCoreInplace(values, this.MaximumValue);
- }
-
- internal static void ConvertCoreInplace(ComponentValues values, float maxValue)
- {
- FromGrayscaleBasic.ScaleValues(values.Component0, maxValue);
- FromGrayscaleBasic.ScaleValues(values.Component1, maxValue);
- FromGrayscaleBasic.ScaleValues(values.Component2, maxValue);
- }
- }
- }
-}
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbScalar.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbScalar.cs
new file mode 100644
index 000000000..24c59206d
--- /dev/null
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbScalar.cs
@@ -0,0 +1,26 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
+{
+ internal abstract partial class JpegColorConverterBase
+ {
+ internal sealed class FromRgbScalar : JpegColorConverterScalar
+ {
+ public FromRgbScalar(int precision)
+ : base(JpegColorSpace.RGB, precision)
+ {
+ }
+
+ public override void ConvertToRgbInplace(in ComponentValues values) =>
+ ConvertCoreInplace(values, this.MaximumValue);
+
+ internal static void ConvertCoreInplace(ComponentValues values, float maxValue)
+ {
+ FromGrayscaleScalar.ConvertCoreInplace(values.Component0, maxValue);
+ FromGrayscaleScalar.ConvertCoreInplace(values.Component1, maxValue);
+ FromGrayscaleScalar.ConvertCoreInplace(values.Component2, maxValue);
+ }
+ }
+ }
+}
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbVector8.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbVector.cs
similarity index 76%
rename from src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbVector8.cs
rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbVector.cs
index a00361d97..ff3a2bee1 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbVector8.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgbVector.cs
@@ -1,19 +1,17 @@
-// Copyright (c) Six Labors.
+// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
-using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
-using SixLabors.ImageSharp.Tuples;
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
{
- internal abstract partial class JpegColorConverter
+ internal abstract partial class JpegColorConverterBase
{
- internal sealed class FromRgbVector8 : Vector8JpegColorConverter
+ internal sealed class FromRgbVector : JpegColorConverterVector
{
- public FromRgbVector8(int precision)
+ public FromRgbVector(int precision)
: base(JpegColorSpace.RGB, precision)
{
}
@@ -29,8 +27,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
var scale = new Vector(1 / this.MaximumValue);
- // Walking 8 elements at one step:
- nint n = values.Component0.Length / 8;
+ nint n = values.Component0.Length / Vector.Count;
for (nint i = 0; i < n; i++)
{
ref Vector r = ref Unsafe.Add(ref rBase, i);
@@ -43,7 +40,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
}
protected override void ConvertCoreInplace(in ComponentValues values) =>
- FromRgbBasic.ConvertCoreInplace(values, this.MaximumValue);
+ FromRgbScalar.ConvertCoreInplace(values, this.MaximumValue);
}
}
}
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrAvx2.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrAvx.cs
similarity index 70%
rename from src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrAvx2.cs
rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrAvx.cs
index 5aae1faa2..892bcc79e 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrAvx2.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrAvx.cs
@@ -1,31 +1,27 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
-using System;
-using System.Numerics;
+#if SUPPORTS_RUNTIME_INTRINSICS
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
-#if SUPPORTS_RUNTIME_INTRINSICS
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
using static SixLabors.ImageSharp.SimdUtils;
-#endif
// ReSharper disable ImpureMethodCallOnReadonlyValueField
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
{
- internal abstract partial class JpegColorConverter
+ internal abstract partial class JpegColorConverterBase
{
- internal sealed class FromYCbCrAvx2 : Avx2JpegColorConverter
+ internal sealed class FromYCbCrAvx : JpegColorConverterAvx
{
- public FromYCbCrAvx2(int precision)
+ public FromYCbCrAvx(int precision)
: base(JpegColorSpace.YCbCr, precision)
{
}
- protected override void ConvertCoreVectorizedInplace(in ComponentValues values)
+ public override void ConvertToRgbInplace(in ComponentValues values)
{
-#if SUPPORTS_RUNTIME_INTRINSICS
ref Vector256 c0Base =
ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0));
ref Vector256 c1Base =
@@ -36,18 +32,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
// Used for the color conversion
var chromaOffset = Vector256.Create(-this.HalfValue);
var scale = Vector256.Create(1 / this.MaximumValue);
- var rCrMult = Vector256.Create(1.402F);
- var gCbMult = Vector256.Create(-0.344136F);
- var gCrMult = Vector256.Create(-0.714136F);
- var bCbMult = Vector256.Create(1.772F);
-
- // Used for packing.
- var va = Vector256.Create(1F);
- ref byte control = ref MemoryMarshal.GetReference(HwIntrinsics.PermuteMaskEvenOdd8x32);
- Vector256 vcontrol = Unsafe.As>(ref control);
+ var rCrMult = Vector256.Create(FromYCbCrScalar.RCrMult);
+ var gCbMult = Vector256.Create(-FromYCbCrScalar.GCbMult);
+ var gCrMult = Vector256.Create(-FromYCbCrScalar.GCrMult);
+ var bCbMult = Vector256.Create(FromYCbCrScalar.BCbMult);
// Walking 8 elements at one step:
- nint n = values.Component0.Length / 8;
+ nint n = values.Component0.Length / Vector256.Count;
for (nint i = 0; i < n; i++)
{
// y = yVals[i];
@@ -64,7 +55,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
// r = y + (1.402F * cr);
// g = y - (0.344136F * cb) - (0.714136F * cr);
// b = y + (1.772F * cb);
- // Adding & multiplying 8 elements at one time:
Vector256 r = HwIntrinsics.MultiplyAdd(y, cr, rCrMult);
Vector256 g = HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(y, cb, gCbMult), cr, gCrMult);
Vector256 b = HwIntrinsics.MultiplyAdd(y, cb, bCbMult);
@@ -77,11 +67,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
c1 = g;
c2 = b;
}
-#endif
}
-
- protected override void ConvertCoreInplace(in ComponentValues values) =>
- FromYCbCrBasic.ConvertCoreInplace(values, this.MaximumValue, this.HalfValue);
}
}
}
+#endif
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrBasic.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrBasic.cs
deleted file mode 100644
index 990d29aa0..000000000
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrBasic.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright (c) Six Labors.
-// Licensed under the Apache License, Version 2.0.
-
-using System;
-using System.Numerics;
-
-namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
-{
- internal abstract partial class JpegColorConverter
- {
- internal sealed class FromYCbCrBasic : BasicJpegColorConverter
- {
- public FromYCbCrBasic(int precision)
- : base(JpegColorSpace.YCbCr, precision)
- {
- }
-
- public override void ConvertToRgbInplace(in ComponentValues values)
- => ConvertCoreInplace(values, this.MaximumValue, this.HalfValue);
-
- internal static void ConvertCoreInplace(in ComponentValues values, float maxValue, float halfValue)
- {
- Span c0 = values.Component0;
- Span c1 = values.Component1;
- Span c2 = values.Component2;
-
- var scale = 1 / maxValue;
-
- for (int i = 0; i < c0.Length; i++)
- {
- float y = c0[i];
- float cb = c1[i] - halfValue;
- float cr = c2[i] - halfValue;
-
- c0[i] = MathF.Round(y + (1.402F * cr), MidpointRounding.AwayFromZero) * scale;
- c1[i] = MathF.Round(y - (0.344136F * cb) - (0.714136F * cr), MidpointRounding.AwayFromZero) * scale;
- c2[i] = MathF.Round(y + (1.772F * cb), MidpointRounding.AwayFromZero) * scale;
- }
- }
- }
- }
-}
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrScalar.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrScalar.cs
new file mode 100644
index 000000000..4b6d88f72
--- /dev/null
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrScalar.cs
@@ -0,0 +1,50 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+using System;
+
+namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
+{
+ internal abstract partial class JpegColorConverterBase
+ {
+ internal sealed class FromYCbCrScalar : JpegColorConverterScalar
+ {
+ // TODO: comments, derived from ITU-T Rec. T.871
+ internal const float RCrMult = 1.402f;
+ internal const float GCbMult = (float)(0.114 * 1.772 / 0.587);
+ internal const float GCrMult = (float)(0.299 * 1.402 / 0.587);
+ internal const float BCbMult = 1.772f;
+
+ public FromYCbCrScalar(int precision)
+ : base(JpegColorSpace.YCbCr, precision)
+ {
+ }
+
+ public override void ConvertToRgbInplace(in ComponentValues values)
+ => ConvertCoreInplace(values, this.MaximumValue, this.HalfValue);
+
+ internal static void ConvertCoreInplace(in ComponentValues values, float maxValue, float halfValue)
+ {
+ Span c0 = values.Component0;
+ Span c1 = values.Component1;
+ Span c2 = values.Component2;
+
+ float scale = 1 / maxValue;
+
+ for (int i = 0; i < c0.Length; i++)
+ {
+ float y = c0[i];
+ float cb = c1[i] - halfValue;
+ float cr = c2[i] - halfValue;
+
+ // r = y + (1.402F * cr);
+ // g = y - (0.344136F * cb) - (0.714136F * cr);
+ // b = y + (1.772F * cb);
+ c0[i] = MathF.Round(y + (RCrMult * cr), MidpointRounding.AwayFromZero) * scale;
+ c1[i] = MathF.Round(y - (GCbMult * cb) - (GCrMult * cr), MidpointRounding.AwayFromZero) * scale;
+ c2[i] = MathF.Round(y + (BCbMult * cb), MidpointRounding.AwayFromZero) * scale;
+ }
+ }
+ }
+ }
+}
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrVector8.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrVector.cs
similarity index 73%
rename from src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrVector8.cs
rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrVector.cs
index a077b9ed8..48e311d99 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrVector8.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrVector.cs
@@ -1,20 +1,18 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
-using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
-using SixLabors.ImageSharp.Tuples;
// ReSharper disable ImpureMethodCallOnReadonlyValueField
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
{
- internal abstract partial class JpegColorConverter
+ internal abstract partial class JpegColorConverterBase
{
- internal sealed class FromYCbCrVector8 : Vector8JpegColorConverter
+ internal sealed class FromYCbCrVector : JpegColorConverterVector
{
- public FromYCbCrVector8(int precision)
+ public FromYCbCrVector(int precision)
: base(JpegColorSpace.YCbCr, precision)
{
}
@@ -30,10 +28,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
var chromaOffset = new Vector(-this.HalfValue);
- // Walking 8 elements at one step:
- nint n = values.Component0.Length / 8;
var scale = new Vector(1 / this.MaximumValue);
+ var rCrMult = new Vector(FromYCbCrScalar.RCrMult);
+ var gCbMult = new Vector(-FromYCbCrScalar.GCbMult);
+ var gCrMult = new Vector(-FromYCbCrScalar.GCrMult);
+ var bCbMult = new Vector(FromYCbCrScalar.BCbMult);
+ nint n = values.Component0.Length / Vector.Count;
for (nint i = 0; i < n; i++)
{
// y = yVals[i];
@@ -49,10 +50,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
// r = y + (1.402F * cr);
// g = y - (0.344136F * cb) - (0.714136F * cr);
// b = y + (1.772F * cb);
- // Adding & multiplying 8 elements at one time:
- Vector r = y + (cr * new Vector(1.402F));
- Vector g = y - (cb * new Vector(0.344136F)) - (cr * new Vector(0.714136F));
- Vector b = y + (cb * new Vector(1.772F));
+ Vector r = y + (cr * rCrMult);
+ Vector g = y + (cb * gCbMult) + (cr * gCrMult);
+ Vector b = y + (cb * bCbMult);
r = r.FastRound();
g = g.FastRound();
@@ -68,7 +68,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
}
protected override void ConvertCoreInplace(in ComponentValues values) =>
- FromYCbCrBasic.ConvertCoreInplace(values, this.MaximumValue, this.HalfValue);
+ FromYCbCrScalar.ConvertCoreInplace(values, this.MaximumValue, this.HalfValue);
}
}
}
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrVector4.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrVector4.cs
deleted file mode 100644
index 1ebc3e879..000000000
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrVector4.cs
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright (c) Six Labors.
-// Licensed under the Apache License, Version 2.0.
-
-using System;
-using System.Numerics;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-using SixLabors.ImageSharp.Tuples;
-
-namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
-{
- internal abstract partial class JpegColorConverter
- {
- internal sealed class FromYCbCrVector4 : VectorizedJpegColorConverter
- {
- public FromYCbCrVector4(int precision)
- : base(JpegColorSpace.YCbCr, precision, 8)
- {
- }
-
- protected override bool IsAvailable => SimdUtils.HasVector4;
-
- protected override void ConvertCoreVectorizedInplace(in ComponentValues values)
- {
- DebugGuard.IsTrue(values.Component0.Length % 8 == 0, nameof(values), "Length should be divisible by 8!");
-
- ref Vector4Pair c0Base =
- ref Unsafe.As(ref MemoryMarshal.GetReference(values.Component0));
- ref Vector4Pair c1Base =
- ref Unsafe.As(ref MemoryMarshal.GetReference(values.Component1));
- ref Vector4Pair c2Base =
- ref Unsafe.As(ref MemoryMarshal.GetReference(values.Component2));
-
- var chromaOffset = new Vector4(-this.HalfValue);
- var maxValue = this.MaximumValue;
-
- // Walking 8 elements at one step:
- nint n = values.Component0.Length / 8;
-
- for (nint i = 0; i < n; i++)
- {
- // y = yVals[i];
- ref Vector4Pair c0 = ref Unsafe.Add(ref c0Base, i);
-
- // cb = cbVals[i] - halfValue);
- ref Vector4Pair c1 = ref Unsafe.Add(ref c1Base, i);
- c1.AddInplace(chromaOffset);
-
- // cr = crVals[i] - halfValue;
- ref Vector4Pair c2 = ref Unsafe.Add(ref c2Base, i);
- c2.AddInplace(chromaOffset);
-
- // r = y + (1.402F * cr);
- Vector4Pair r = c0;
- Vector4Pair tmp = c2;
- tmp.MultiplyInplace(1.402F);
- r.AddInplace(ref tmp);
-
- // g = y - (0.344136F * cb) - (0.714136F * cr);
- Vector4Pair g = c0;
- tmp = c1;
- tmp.MultiplyInplace(-0.344136F);
- g.AddInplace(ref tmp);
- tmp = c2;
- tmp.MultiplyInplace(-0.714136F);
- g.AddInplace(ref tmp);
-
- // b = y + (1.772F * cb);
- Vector4Pair b = c0;
- tmp = c1;
- tmp.MultiplyInplace(1.772F);
- b.AddInplace(ref tmp);
-
- r.RoundAndDownscalePreVector8(maxValue);
- g.RoundAndDownscalePreVector8(maxValue);
- b.RoundAndDownscalePreVector8(maxValue);
-
- c0 = r;
- c1 = g;
- c2 = b;
- }
- }
-
- protected override void ConvertCoreInplace(in ComponentValues values)
- => FromYCbCrBasic.ConvertCoreInplace(values, this.MaximumValue, this.HalfValue);
- }
- }
-}
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKAvx2.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKAvx.cs
similarity index 77%
rename from src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKAvx2.cs
rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKAvx.cs
index a3500a096..1f18d5324 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKAvx2.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKAvx.cs
@@ -1,30 +1,26 @@
-// Copyright (c) Six Labors.
+// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
-using System;
-using System.Numerics;
+#if SUPPORTS_RUNTIME_INTRINSICS
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
-#if SUPPORTS_RUNTIME_INTRINSICS
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
using static SixLabors.ImageSharp.SimdUtils;
-#endif
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
{
- internal abstract partial class JpegColorConverter
+ internal abstract partial class JpegColorConverterBase
{
- internal sealed class FromYccKAvx2 : Avx2JpegColorConverter
+ internal sealed class FromYccKAvx : JpegColorConverterAvx
{
- public FromYccKAvx2(int precision)
+ public FromYccKAvx(int precision)
: base(JpegColorSpace.Ycck, precision)
{
}
- protected override void ConvertCoreVectorizedInplace(in ComponentValues values)
+ public override void ConvertToRgbInplace(in ComponentValues values)
{
-#if SUPPORTS_RUNTIME_INTRINSICS
ref Vector256 c0Base =
ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component0));
ref Vector256 c1Base =
@@ -38,13 +34,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
var chromaOffset = Vector256.Create(-this.HalfValue);
var scale = Vector256.Create(1 / (this.MaximumValue * this.MaximumValue));
var max = Vector256.Create(this.MaximumValue);
- var rCrMult = Vector256.Create(1.402F);
- var gCbMult = Vector256.Create(-0.344136F);
- var gCrMult = Vector256.Create(-0.714136F);
- var bCbMult = Vector256.Create(1.772F);
+ var rCrMult = Vector256.Create(FromYCbCrScalar.RCrMult);
+ var gCbMult = Vector256.Create(-FromYCbCrScalar.GCbMult);
+ var gCrMult = Vector256.Create(-FromYCbCrScalar.GCrMult);
+ var bCbMult = Vector256.Create(FromYCbCrScalar.BCbMult);
// Walking 8 elements at one step:
- nint n = values.Component0.Length / 8;
+ nint n = values.Component0.Length / Vector256.Count;
for (nint i = 0; i < n; i++)
{
// y = yVals[i];
@@ -62,7 +58,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
// r = y + (1.402F * cr);
// g = y - (0.344136F * cb) - (0.714136F * cr);
// b = y + (1.772F * cb);
- // Adding & multiplying 8 elements at one time:
Vector256 r = HwIntrinsics.MultiplyAdd(y, cr, rCrMult);
Vector256 g =
HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(y, cb, gCbMult), cr, gCrMult);
@@ -80,11 +75,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
c1 = g;
c2 = b;
}
-#endif
}
-
- protected override void ConvertCoreInplace(in ComponentValues values) =>
- FromYccKBasic.ConvertCoreInplace(values, this.MaximumValue, this.HalfValue);
}
}
}
+#endif
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKBasic.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKScalar.cs
similarity index 81%
rename from src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKBasic.cs
rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKScalar.cs
index 4833f4868..d6387ae71 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKBasic.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKScalar.cs
@@ -1,16 +1,15 @@
-// Copyright (c) Six Labors.
+// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System;
-using System.Numerics;
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
{
- internal abstract partial class JpegColorConverter
+ internal abstract partial class JpegColorConverterBase
{
- internal sealed class FromYccKBasic : BasicJpegColorConverter
+ internal sealed class FromYccKScalar : JpegColorConverterScalar
{
- public FromYccKBasic(int precision)
+ public FromYccKScalar(int precision)
: base(JpegColorSpace.Ycck, precision)
{
}
@@ -25,9 +24,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
Span c2 = values.Component2;
Span c3 = values.Component3;
- var v = new Vector4(0, 0, 0, 1F);
-
- var scale = 1 / (maxValue * maxValue);
+ float scale = 1 / (maxValue * maxValue);
for (int i = 0; i < values.Component0.Length; i++)
{
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKVector8.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKVector.cs
similarity index 71%
rename from src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKVector8.cs
rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKVector.cs
index f830e5042..66c79ae7c 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKVector8.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccKVector.cs
@@ -1,19 +1,17 @@
-// Copyright (c) Six Labors.
+// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
-using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
-using SixLabors.ImageSharp.Tuples;
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
{
- internal abstract partial class JpegColorConverter
+ internal abstract partial class JpegColorConverterBase
{
- internal sealed class FromYccKVector8 : Vector8JpegColorConverter
+ internal sealed class FromYccKVector : JpegColorConverterVector
{
- public FromYccKVector8(int precision)
+ public FromYccKVector(int precision)
: base(JpegColorSpace.Ycck, precision)
{
}
@@ -30,13 +28,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
ref Unsafe.As>(ref MemoryMarshal.GetReference(values.Component3));
var chromaOffset = new Vector(-this.HalfValue);
-
- // Walking 8 elements at one step:
- nint n = values.Component0.Length / 8;
-
+ var scale = new Vector(1 / (this.MaximumValue * this.MaximumValue));
var max = new Vector(this.MaximumValue);
- var scale = new Vector(1f) / (max * max);
+ var rCrMult = new Vector(FromYCbCrScalar.RCrMult);
+ var gCbMult = new Vector(-FromYCbCrScalar.GCbMult);
+ var gCrMult = new Vector(-FromYCbCrScalar.GCrMult);
+ var bCbMult = new Vector(FromYCbCrScalar.BCbMult);
+ nint n = values.Component0.Length / Vector.Count;
for (nint i = 0; i < n; i++)
{
// y = yVals[i];
@@ -55,10 +54,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
// r = y + (1.402F * cr);
// g = y - (0.344136F * cb) - (0.714136F * cr);
// b = y + (1.772F * cb);
- // Adding & multiplying 8 elements at one time:
- Vector r = y + (cr * new Vector(1.402F));
- Vector g = y - (cb * new Vector(0.344136F)) - (cr * new Vector(0.714136F));
- Vector b = y + (cb * new Vector(1.772F));
+ Vector r = y + (cr * rCrMult);
+ Vector g = y + (cb * gCbMult) + (cr * gCrMult);
+ Vector b = y + (cb * bCbMult);
r = (max - r.FastRound()) * scaledK;
g = (max - g.FastRound()) * scaledK;
@@ -71,7 +69,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
}
protected override void ConvertCoreInplace(in ComponentValues values) =>
- FromYccKBasic.ConvertCoreInplace(values, this.MaximumValue, this.HalfValue);
+ FromYccKScalar.ConvertCoreInplace(values, this.MaximumValue, this.HalfValue);
}
}
}
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.Vector8JpegColorConverter.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.Vector8JpegColorConverter.cs
deleted file mode 100644
index 3e9b889db..000000000
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.Vector8JpegColorConverter.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright (c) Six Labors.
-// Licensed under the Apache License, Version 2.0.
-
-namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
-{
- internal abstract partial class JpegColorConverter
- {
- internal abstract class Vector8JpegColorConverter : VectorizedJpegColorConverter
- {
- protected Vector8JpegColorConverter(JpegColorSpace colorSpace, int precision)
- : base(colorSpace, precision, 8)
- {
- }
-
- protected sealed override bool IsAvailable => SimdUtils.HasVector8;
- }
- }
-}
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.VectorizedJpegColorConverter.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.VectorizedJpegColorConverter.cs
deleted file mode 100644
index fc4fb7786..000000000
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.VectorizedJpegColorConverter.cs
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright (c) Six Labors.
-// Licensed under the Apache License, Version 2.0.
-
-using System;
-using System.Numerics;
-
-namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
-{
- internal abstract partial class JpegColorConverter
- {
- internal abstract class VectorizedJpegColorConverter : JpegColorConverter
- {
- private readonly int vectorSize;
-
- protected VectorizedJpegColorConverter(JpegColorSpace colorSpace, int precision, int vectorSize)
- : base(colorSpace, precision)
- {
- this.vectorSize = vectorSize;
- }
-
- public override void ConvertToRgbInplace(in ComponentValues values)
- {
- int length = values.Component0.Length;
- int remainder = values.Component0.Length % this.vectorSize;
- int simdCount = length - remainder;
- if (simdCount > 0)
- {
- // This implementation is actually AVX specific.
- // An AVX register is capable of storing 8 float-s.
- if (!this.IsAvailable)
- {
- throw new InvalidOperationException(
- "This converter can be used only on architecture having 256 byte floating point SIMD registers!");
- }
-
- this.ConvertCoreVectorizedInplace(values.Slice(0, simdCount));
- }
-
- this.ConvertCoreInplace(values.Slice(simdCount, remainder));
- }
-
- protected virtual void ConvertCoreVectorizedInplace(in ComponentValues values) => throw new NotImplementedException();
-
- protected virtual void ConvertCoreInplace(in ComponentValues values) => throw new NotImplementedException();
- }
- }
-}
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterAvx.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterAvx.cs
new file mode 100644
index 000000000..81c7c0764
--- /dev/null
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterAvx.cs
@@ -0,0 +1,32 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+#if SUPPORTS_RUNTIME_INTRINSICS
+using System.Runtime.Intrinsics.X86;
+
+namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
+{
+ internal abstract partial class JpegColorConverterBase
+ {
+ ///
+ /// abstract base for implementations
+ /// based on instructions.
+ ///
+ ///
+ /// Converters of this family would expect input buffers lengths to be
+ /// divisible by 8 without a remainder.
+ /// This is guaranteed by real-life data as jpeg stores pixels via 8x8 blocks.
+ /// DO NOT pass test data of invalid size to these converters as they
+ /// potentially won't do a bound check and return a false positive result.
+ ///
+ internal abstract class JpegColorConverterAvx : JpegColorConverterBase
+ {
+ protected JpegColorConverterAvx(JpegColorSpace colorSpace, int precision)
+ : base(colorSpace, precision)
+ {
+ }
+
+ public override bool IsAvailable => Avx.IsSupported;
+ }
+ }
+}
+#endif
diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterBase.cs
similarity index 59%
rename from src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs
rename to src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterBase.cs
index 11ea4cda8..808ca687b 100644
--- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs
+++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverterBase.cs
@@ -4,26 +4,24 @@
using System;
using System.Collections.Generic;
using System.Linq;
-using System.Numerics;
using SixLabors.ImageSharp.Memory;
-using SixLabors.ImageSharp.Tuples;
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
{
///
- /// Encapsulates the conversion of Jpeg channels to RGBA values packed in buffer.
+ /// Encapsulates the conversion of color channels from jpeg image to RGB channels.
///
- internal abstract partial class JpegColorConverter
+ internal abstract partial class JpegColorConverterBase
{
///
/// The available converters
///
- private static readonly JpegColorConverter[] Converters = CreateConverters();
+ private static readonly JpegColorConverterBase[] Converters = CreateConverters();
///
- /// Initializes a new instance of the class.
+ /// Initializes a new instance of the class.
///
- protected JpegColorConverter(JpegColorSpace colorSpace, int precision)
+ protected JpegColorConverterBase(JpegColorSpace colorSpace, int precision)
{
this.ColorSpace = colorSpace;
this.Precision = precision;
@@ -32,10 +30,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
}
///
- /// Gets a value indicating whether this is available
+ /// Gets a value indicating whether this is available
/// on the current runtime and CPU architecture.
///
- protected abstract bool IsAvailable { get; }
+ public abstract bool IsAvailable { get; }
///
/// Gets the of this converter.
@@ -58,11 +56,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
private float HalfValue { get; }
///
- /// Returns the corresponding to the given
+ /// Returns the corresponding to the given
///
- public static JpegColorConverter GetConverter(JpegColorSpace colorSpace, int precision)
+ public static JpegColorConverterBase GetConverter(JpegColorSpace colorSpace, int precision)
{
- JpegColorConverter converter = Array.Find(
+ JpegColorConverterBase converter = Array.Find(
Converters,
c => c.ColorSpace == colorSpace
&& c.Precision == precision);
@@ -82,11 +80,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
public abstract void ConvertToRgbInplace(in ComponentValues values);
///
- /// Returns the s for all supported colorspaces and precisions.
+ /// Returns the s for all supported colorspaces and precisions.
///
- private static JpegColorConverter[] CreateConverters()
+ private static JpegColorConverterBase[] CreateConverters()
{
- var converters = new List();
+ var converters = new List();
// 8-bit converters
converters.AddRange(GetYCbCrConverters(8));
@@ -106,63 +104,63 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
}
///
- /// Returns the s for the YCbCr colorspace.
+ /// Returns the s for the YCbCr colorspace.
///
- private static IEnumerable GetYCbCrConverters(int precision)
+ private static IEnumerable GetYCbCrConverters(int precision)
{
#if SUPPORTS_RUNTIME_INTRINSICS
- yield return new FromYCbCrAvx2(precision);
+ yield return new FromYCbCrAvx(precision);
#endif
- yield return new FromYCbCrVector8(precision);
- yield return new FromYCbCrVector4(precision);
- yield return new FromYCbCrBasic(precision);
+ yield return new FromYCbCrVector(precision);
+ yield return new FromYCbCrScalar(precision);
}
///
- /// Returns the