Browse Source

Merge pull request #3177 from SixLabors/js/net10-net11-targets

Retarget builds to .NET 10 and 11
pull/3178/head
James Jackson-South 2 weeks ago
committed by GitHub
parent
commit
d0930b9e4c
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 1
      .gitattributes
  2. 37
      .github/workflows/build-and-test.yml
  3. 4
      .github/workflows/code-coverage.yml
  4. 8
      Directory.Build.props
  5. 18
      global.json
  6. 2
      shared-infrastructure
  7. 4
      src/ImageSharp/Common/Extensions/StreamExtensions.cs
  8. 42
      src/ImageSharp/Common/Helpers/Numerics.cs
  9. 6
      src/ImageSharp/Common/Helpers/SimdUtils.Shuffle.cs
  10. 4
      src/ImageSharp/Common/Helpers/SimdUtils.cs
  11. 6
      src/ImageSharp/Formats/Exr/Compression/Decompressors/B44ExrCompression.cs
  12. 4
      src/ImageSharp/Formats/Exr/Compression/ExrBaseDecompressor.cs
  13. 16
      src/ImageSharp/Formats/Exr/ExrDecoderCore.cs
  14. 8
      src/ImageSharp/Formats/Exr/ExrEncoderCore.cs
  15. 4
      src/ImageSharp/Formats/Jpeg/Components/Block8x8.cs
  16. 4
      src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs
  17. 6
      src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
  18. 6
      src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs
  19. 6
      src/ImageSharp/Formats/Png/PngEncoderCore.cs
  20. 6
      src/ImageSharp/Formats/Tga/TgaEncoderCore.cs
  21. 4
      src/ImageSharp/Formats/Tiff/Compression/Compressors/T6BitCompressor.cs
  22. 6
      src/ImageSharp/Formats/Tiff/Compression/Compressors/TiffLzwEncoder.cs
  23. 18
      src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs
  24. 4
      src/ImageSharp/Formats/Tiff/Writers/TiffStreamWriter.cs
  25. 12
      src/ImageSharp/Formats/Webp/AlphaDecoder.cs
  26. 4
      src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs
  27. 4
      src/ImageSharp/Formats/Webp/BitWriter/Vp8BitWriter.cs
  28. 4
      src/ImageSharp/Formats/Webp/Lossless/BackwardReferenceEncoder.cs
  29. 6
      src/ImageSharp/Formats/Webp/Lossless/ColorSpaceTransformUtils.cs
  30. 2
      src/ImageSharp/Formats/Webp/Lossless/CostModel.cs
  31. 2
      src/ImageSharp/Formats/Webp/Lossless/HistogramEncoder.cs
  32. 8
      src/ImageSharp/Formats/Webp/Lossless/HuffmanUtils.cs
  33. 4
      src/ImageSharp/Formats/Webp/Lossless/LosslessUtils.cs
  34. 2
      src/ImageSharp/Formats/Webp/Lossless/NearLosslessEnc.cs
  35. 10
      src/ImageSharp/Formats/Webp/Lossless/PredictorEncoder.cs
  36. 8
      src/ImageSharp/Formats/Webp/Lossless/Vp8LBitEntropy.cs
  37. 16
      src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs
  38. 10
      src/ImageSharp/Formats/Webp/Lossless/Vp8LHistogram.cs
  39. 4
      src/ImageSharp/Formats/Webp/Lossless/WebpLosslessDecoder.cs
  40. 50
      src/ImageSharp/Formats/Webp/Lossy/LossyUtils.cs
  41. 2
      src/ImageSharp/Formats/Webp/Lossy/Vp8EncIterator.cs
  42. 2
      src/ImageSharp/Formats/Webp/Lossy/Vp8EncProba.cs
  43. 28
      src/ImageSharp/Formats/Webp/Lossy/Vp8Encoding.cs
  44. 2
      src/ImageSharp/Formats/Webp/Lossy/Vp8Residual.cs
  45. 2
      src/ImageSharp/Formats/Webp/Lossy/Vp8SegmentInfo.cs
  46. 10
      src/ImageSharp/Formats/Webp/Lossy/YuvConversion.cs
  47. 4
      src/ImageSharp/ImageSharp.csproj
  48. 2
      src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs
  49. 2
      tests/Directory.Build.targets
  50. 4
      tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj
  51. 4
      tests/ImageSharp.PublicApi.Tests/ImageSharp.PublicApi.Tests.csproj
  52. 4
      tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj
  53. 10
      tests/ImageSharp.Tests/IO/LocalFileSystemTests.cs
  54. 4
      tests/ImageSharp.Tests/ImageSharp.Tests.csproj
  55. 7
      tests/ImageSharp.Tests/TestUtilities/FeatureTesting/FeatureTestRunner.cs
  56. 28
      tests/ImageSharp.Tests/TestUtilities/Tests/FeatureTestRunnerTests.cs

1
.gitattributes

@ -110,6 +110,7 @@
###############################################################################
# Handle image files by git lfs
###############################################################################
*.pdf filter=lfs diff=lfs merge=lfs -text
*.jpg filter=lfs diff=lfs merge=lfs -text
*.jpeg filter=lfs diff=lfs merge=lfs -text
*.bmp filter=lfs diff=lfs merge=lfs -text

37
.github/workflows/build-and-test.yml

@ -64,48 +64,48 @@ jobs:
matrix:
options:
- os: ubuntu-latest
framework: net10.0
sdk: 10.0.x
framework: net11.0
sdk: 11.0.x
sdk-preview: true
runtime: -x64
codecov: false
- os: macos-26
framework: net10.0
sdk: 10.0.x
framework: net11.0
sdk: 11.0.x
sdk-preview: true
runtime: -x64
codecov: false
- os: windows-latest
framework: net10.0
sdk: 10.0.x
framework: net11.0
sdk: 11.0.x
sdk-preview: true
runtime: -x64
codecov: false
- os: ubuntu-22.04-arm
framework: net10.0
sdk: 10.0.x
framework: net11.0
sdk: 11.0.x
sdk-preview: true
runtime: -x64
codecov: false
- os: ubuntu-latest
framework: net8.0
sdk: 8.0.x
framework: net10.0
sdk: 10.0.x
runtime: -x64
codecov: false
- os: macos-26
framework: net8.0
sdk: 8.0.x
framework: net10.0
sdk: 10.0.x
runtime: -x64
codecov: false
- os: windows-latest
framework: net8.0
sdk: 8.0.x
framework: net10.0
sdk: 10.0.x
runtime: -x64
codecov: false
- os: ubuntu-22.04-arm
framework: net8.0
sdk: 8.0.x
framework: net10.0
sdk: 10.0.x
runtime: -x64
codecov: false
@ -169,14 +169,15 @@ jobs:
uses: actions/setup-dotnet@v6
with:
dotnet-version: |
8.0.x
10.0.x
- name: DotNet Setup Preview
if: ${{ matrix.options.sdk-preview == true }}
uses: actions/setup-dotnet@v6
with:
dotnet-quality: preview
dotnet-version: |
10.0.x
11.0.x
- name: DotNet Build
if: ${{ matrix.options.sdk-preview != true }}

4
.github/workflows/code-coverage.yml

@ -11,7 +11,7 @@ jobs:
matrix:
options:
- os: ubuntu-latest
framework: net8.0
framework: net10.0
runtime: -x64
codecov: true
@ -70,7 +70,7 @@ jobs:
uses: actions/setup-dotnet@v6
with:
dotnet-version: |
8.0.x
10.0.x
- name: DotNet Build
shell: pwsh

8
Directory.Build.props

@ -21,14 +21,6 @@
<!-- Import the shared global .props file -->
<Import Project="$(MSBuildThisFileDirectory)shared-infrastructure\msbuild\props\SixLabors.Global.props" />
<PropertyGroup Condition="'$(TargetFramework)' == 'net8.0' OR '$(TargetFramework)' == 'net9.0'">
<LangVersion>12.0</LangVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(TargetFramework)' == 'net10.0'">
<LangVersion>14.0</LangVersion>
</PropertyGroup>
<!--
Ensure all custom build configurations based upon "Release" are optimized.
This is easier than setting each project individually.

18
global.json

@ -0,0 +1,18 @@
// Pins the .NET SDK to major version 10 or later for all SixLabors repositories.
// The build copies this file to consuming repositories together with .editorconfig and
// the other shared config files (see msbuild/targets/SixLabors.Src.targets).
{
"sdk": {
// The floor, not an exact build: resolution never selects an SDK below major 10.
"version": "10.0.0",
// Select the newest installed SDK at or above the floor. This spans feature bands,
// minor versions, and major versions, so a machine with only stable 10.0.x SDKs
// resolves the newest of those, and a machine with a newer SDK resolves that instead.
"rollForward": "latestMajor",
// Let the CLI and Visual Studio select preview SDKs when one is installed.
// Machines and CI lanes without a preview SDK are unaffected.
"allowPrerelease": true
}
}

2
shared-infrastructure

@ -1 +1 @@
Subproject commit 6949b1094c3ccf672b93608f3f74a8b483426d4b
Subproject commit 52fc1c3e87a755b2b17ce77e8cd22ec4bea17bcb

4
src/ImageSharp/Common/Extensions/StreamExtensions.cs

@ -1,4 +1,4 @@
// Copyright (c) Six Labors.
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Buffers;
@ -17,7 +17,7 @@ internal static class StreamExtensions
/// <param name="buffer">The buffer.</param>
/// <param name="offset">The offset within the buffer to begin writing.</param>
/// <param name="count">The number of bytes to write to the stream.</param>
public static void Write(this Stream stream, Span<byte> buffer, int offset, int count)
public static void Write(this Stream stream, ReadOnlySpan<byte> buffer, int offset, int count)
=> stream.Write(buffer.Slice(offset, count));
/// <summary>

42
src/ImageSharp/Common/Helpers/Numerics.cs

@ -1,4 +1,4 @@
// Copyright (c) Six Labors.
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
@ -939,20 +939,10 @@ internal static class Numerics
/// <typeparam name="TVector">The type of the vector.</typeparam>
/// <param name="span">The given span.</param>
/// <returns>Count of vectors that safely fit into the span.</returns>
public static nuint VectorCount<TVector>(this Span<byte> span)
public static nuint VectorCount<TVector>(this ReadOnlySpan<byte> span)
where TVector : struct
=> (uint)span.Length / (uint)Vector<TVector>.Count;
/// <summary>
/// Gets the count of vectors that safely fit into the given span.
/// </summary>
/// <typeparam name="TVector">The type of the vector.</typeparam>
/// <param name="span">The given span.</param>
/// <returns>Count of vectors that safely fit into the span.</returns>
public static nuint Vector128Count<TVector>(this Span<byte> span)
where TVector : struct
=> (uint)span.Length / (uint)Vector128<TVector>.Count;
/// <summary>
/// Gets the count of vectors that safely fit into the given span.
/// </summary>
@ -963,16 +953,6 @@ internal static class Numerics
where TVector : struct
=> (uint)span.Length / (uint)Vector128<TVector>.Count;
/// <summary>
/// Gets the count of vectors that safely fit into the given span.
/// </summary>
/// <typeparam name="TVector">The type of the vector.</typeparam>
/// <param name="span">The given span.</param>
/// <returns>Count of vectors that safely fit into the span.</returns>
public static nuint Vector256Count<TVector>(this Span<byte> span)
where TVector : struct
=> (uint)span.Length / (uint)Vector256<TVector>.Count;
/// <summary>
/// Gets the count of vectors that safely fit into the given span.
/// </summary>
@ -983,16 +963,6 @@ internal static class Numerics
where TVector : struct
=> (uint)span.Length / (uint)Vector256<TVector>.Count;
/// <summary>
/// Gets the count of vectors that safely fit into the given span.
/// </summary>
/// <typeparam name="TVector">The type of the vector.</typeparam>
/// <param name="span">The given span.</param>
/// <returns>Count of vectors that safely fit into the span.</returns>
public static nuint Vector512Count<TVector>(this Span<byte> span)
where TVector : struct
=> (uint)span.Length / (uint)Vector512<TVector>.Count;
/// <summary>
/// Gets the count of vectors that safely fit into the given span.
/// </summary>
@ -1009,7 +979,7 @@ internal static class Numerics
/// <typeparam name="TVector">The type of the vector.</typeparam>
/// <param name="span">The given span.</param>
/// <returns>Count of vectors that safely fit into the span.</returns>
public static nuint VectorCount<TVector>(this Span<float> span)
public static nuint VectorCount<TVector>(this ReadOnlySpan<float> span)
where TVector : struct
=> (uint)span.Length / (uint)Vector<TVector>.Count;
@ -1019,7 +989,7 @@ internal static class Numerics
/// <typeparam name="TVector">The type of the vector.</typeparam>
/// <param name="span">The given span.</param>
/// <returns>Count of vectors that safely fit into the span.</returns>
public static nuint Vector128Count<TVector>(this Span<float> span)
public static nuint Vector128Count<TVector>(this ReadOnlySpan<float> span)
where TVector : struct
=> (uint)span.Length / (uint)Vector128<TVector>.Count;
@ -1029,7 +999,7 @@ internal static class Numerics
/// <typeparam name="TVector">The type of the vector.</typeparam>
/// <param name="span">The given span.</param>
/// <returns>Count of vectors that safely fit into the span.</returns>
public static nuint Vector256Count<TVector>(this Span<float> span)
public static nuint Vector256Count<TVector>(this ReadOnlySpan<float> span)
where TVector : struct
=> (uint)span.Length / (uint)Vector256<TVector>.Count;
@ -1049,7 +1019,7 @@ internal static class Numerics
/// <typeparam name="TVector">The type of the vector.</typeparam>
/// <param name="span">The given span.</param>
/// <returns>Count of vectors that safely fit into the span.</returns>
public static nuint Vector512Count<TVector>(this Span<float> span)
public static nuint Vector512Count<TVector>(this ReadOnlySpan<float> span)
where TVector : struct
=> (uint)span.Length / (uint)Vector512<TVector>.Count;

6
src/ImageSharp/Common/Helpers/SimdUtils.Shuffle.cs

@ -1,4 +1,4 @@
// Copyright (c) Six Labors.
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Diagnostics;
@ -464,7 +464,7 @@ internal static partial class SimdUtils
}
[Conditional("DEBUG")]
internal static void VerifyShuffle4SpanInput<T>(ReadOnlySpan<T> source, Span<T> destination)
internal static void VerifyShuffle4SpanInput<T>(ReadOnlySpan<T> source, ReadOnlySpan<T> destination)
where T : struct
{
DebugGuard.IsTrue(
@ -479,7 +479,7 @@ internal static partial class SimdUtils
}
[Conditional("DEBUG")]
private static void VerifyShuffle3SpanInput<T>(ReadOnlySpan<T> source, Span<T> destination)
private static void VerifyShuffle3SpanInput<T>(ReadOnlySpan<T> source, ReadOnlySpan<T> destination)
where T : struct
{
DebugGuard.IsTrue(

4
src/ImageSharp/Common/Helpers/SimdUtils.cs

@ -72,7 +72,7 @@ internal static partial class SimdUtils
}
[Conditional("DEBUG")]
private static void DebugVerifySpanInput(ReadOnlySpan<byte> source, Span<float> dest, int shouldBeDivisibleBy)
private static void DebugVerifySpanInput(ReadOnlySpan<byte> source, ReadOnlySpan<float> dest, int shouldBeDivisibleBy)
{
DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!");
DebugGuard.IsTrue(
@ -82,7 +82,7 @@ internal static partial class SimdUtils
}
[Conditional("DEBUG")]
private static void DebugVerifySpanInput(ReadOnlySpan<float> source, Span<byte> destination, int shouldBeDivisibleBy)
private static void DebugVerifySpanInput(ReadOnlySpan<float> source, ReadOnlySpan<byte> destination, int shouldBeDivisibleBy)
{
DebugGuard.IsTrue(source.Length == destination.Length, nameof(source), "Input spans must be of same length!");
DebugGuard.IsTrue(

6
src/ImageSharp/Formats/Exr/Compression/Decompressors/B44ExrCompression.cs

@ -1,4 +1,4 @@
// Copyright (c) Six Labors.
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Buffers;
@ -141,7 +141,7 @@ internal class B44ExrCompression : ExrBaseDecompressor
/// </summary>
/// <param name="b">The source byte data to unpack.</param>
/// <param name="s">Destintation buffer.</param>
private static void Unpack14(Span<byte> b, Span<ushort> s)
private static void Unpack14(ReadOnlySpan<byte> b, Span<ushort> s)
{
s[0] = (ushort)((b[0] << 8) | b[1]);
@ -185,7 +185,7 @@ internal class B44ExrCompression : ExrBaseDecompressor
/// </summary>
/// <param name="b">The source byte data to unpack.</param>
/// <param name="s">The destination buffer.</param>
private static void Unpack3(Span<byte> b, Span<ushort> s)
private static void Unpack3(ReadOnlySpan<byte> b, Span<ushort> s)
{
s[0] = (ushort)((b[0] << 8) | b[1]);

4
src/ImageSharp/Formats/Exr/Compression/ExrBaseDecompressor.cs

@ -1,4 +1,4 @@
// Copyright (c) Six Labors.
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.IO.Compression;
@ -98,7 +98,7 @@ internal abstract class ExrBaseDecompressor : ExrBaseCompression
/// <param name="source">The source data.</param>
/// <param name="unCompressedBytes">The uncompressed bytes.</param>
/// <param name="output">The output to write to.</param>
protected static void Interleave(Span<byte> source, uint unCompressedBytes, Span<byte> output)
protected static void Interleave(ReadOnlySpan<byte> source, uint unCompressedBytes, Span<byte> output)
{
int sourceOffset = 0;
int offset0 = 0;

16
src/ImageSharp/Formats/Exr/ExrDecoderCore.cs

@ -1,4 +1,4 @@
// Copyright (c) Six Labors.
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
#nullable disable
@ -320,7 +320,7 @@ internal sealed class ExrDecoderCore : ImageDecoderCore
private static int ReadFloatChannelData(
BufferedReadStream stream,
ExrChannelInfo channel,
Span<byte> decompressedPixelData,
ReadOnlySpan<byte> decompressedPixelData,
Span<float> redPixelData,
Span<float> greenPixelData,
Span<float> bluePixelData,
@ -371,7 +371,7 @@ internal sealed class ExrDecoderCore : ImageDecoderCore
private int ReadUnsignedIntChannelData(
BufferedReadStream stream,
ExrChannelInfo channel,
Span<byte> decompressedPixelData,
ReadOnlySpan<byte> decompressedPixelData,
Span<uint> redPixelData,
Span<uint> greenPixelData,
Span<uint> bluePixelData,
@ -414,7 +414,7 @@ internal sealed class ExrDecoderCore : ImageDecoderCore
/// <param name="pixelData">The pixel data as float.</param>
/// <param name="width">The width in pixel of a row.</param>
/// <returns>The bytes read.</returns>
private static int ReadChannelData(ExrChannelInfo channel, Span<byte> decompressedPixelData, Span<float> pixelData, int width) => channel.PixelType switch
private static int ReadChannelData(ExrChannelInfo channel, ReadOnlySpan<byte> decompressedPixelData, Span<float> pixelData, int width) => channel.PixelType switch
{
ExrPixelType.Half => ReadPixelRowChannelHalfSingle(decompressedPixelData, pixelData, width),
ExrPixelType.Float => ReadPixelRowChannelSingle(decompressedPixelData, pixelData, width),
@ -429,7 +429,7 @@ internal sealed class ExrDecoderCore : ImageDecoderCore
/// <param name="pixelData">The pixel data as uint.</param>
/// <param name="width">The width in pixels.</param>
/// <returns>The bytes read.</returns>
private static int ReadChannelData(ExrChannelInfo channel, Span<byte> decompressedPixelData, Span<uint> pixelData, int width) => channel.PixelType switch
private static int ReadChannelData(ExrChannelInfo channel, ReadOnlySpan<byte> decompressedPixelData, Span<uint> pixelData, int width) => channel.PixelType switch
{
ExrPixelType.UnsignedInt => ReadPixelRowChannelUnsignedInt(decompressedPixelData, pixelData, width),
_ => 0,
@ -442,7 +442,7 @@ internal sealed class ExrDecoderCore : ImageDecoderCore
/// <param name="channelData">The channel data as float.</param>
/// <param name="width">The width of a row in pixels.</param>
/// <returns>The bytes read.</returns>
private static int ReadPixelRowChannelHalfSingle(Span<byte> decompressedPixelData, Span<float> channelData, int width)
private static int ReadPixelRowChannelHalfSingle(ReadOnlySpan<byte> decompressedPixelData, Span<float> channelData, int width)
{
int offset = 0;
for (int x = 0; x < width; x++)
@ -462,7 +462,7 @@ internal sealed class ExrDecoderCore : ImageDecoderCore
/// <param name="channelData">The pixel data as float.</param>
/// <param name="width">The width in pixels of a row.</param>
/// <returns>The bytes read.</returns>
private static int ReadPixelRowChannelSingle(Span<byte> decompressedPixelData, Span<float> channelData, int width)
private static int ReadPixelRowChannelSingle(ReadOnlySpan<byte> decompressedPixelData, Span<float> channelData, int width)
{
int offset = 0;
for (int x = 0; x < width; x++)
@ -482,7 +482,7 @@ internal sealed class ExrDecoderCore : ImageDecoderCore
/// <param name="channelData">The uint pixel data.</param>
/// <param name="width">The width of a row in pixels.</param>
/// <returns>The bytes read.</returns>
private static int ReadPixelRowChannelUnsignedInt(Span<byte> decompressedPixelData, Span<uint> channelData, int width)
private static int ReadPixelRowChannelUnsignedInt(ReadOnlySpan<byte> decompressedPixelData, Span<uint> channelData, int width)
{
int offset = 0;
for (int x = 0; x < width; x++)

8
src/ImageSharp/Formats/Exr/ExrEncoderCore.cs

@ -1,4 +1,4 @@
// Copyright (c) Six Labors.
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Buffers;
@ -364,7 +364,7 @@ internal sealed class ExrEncoderCore
/// <param name="blueBuffer">The blue channel buffer.</param>
/// <param name="greenBuffer">The green channel buffer.</param>
/// <param name="redBuffer">The red channel buffer.</param>
private static void WriteSingleRow(Span<byte> buffer, int width, Span<float> alphaBuffer, Span<float> blueBuffer, Span<float> greenBuffer, Span<float> redBuffer)
private static void WriteSingleRow(Span<byte> buffer, int width, ReadOnlySpan<float> alphaBuffer, ReadOnlySpan<float> blueBuffer, ReadOnlySpan<float> greenBuffer, ReadOnlySpan<float> redBuffer)
{
int offset = 0;
for (int x = 0; x < width; x++)
@ -401,7 +401,7 @@ internal sealed class ExrEncoderCore
/// <param name="blueBuffer">The blue channel buffer.</param>
/// <param name="greenBuffer">The green channel buffer.</param>
/// <param name="redBuffer">The red channel buffer.</param>
private static void WriteHalfSingleRow(Span<byte> buffer, int width, Span<float> alphaBuffer, Span<float> blueBuffer, Span<float> greenBuffer, Span<float> redBuffer)
private static void WriteHalfSingleRow(Span<byte> buffer, int width, ReadOnlySpan<float> alphaBuffer, ReadOnlySpan<float> blueBuffer, ReadOnlySpan<float> greenBuffer, ReadOnlySpan<float> redBuffer)
{
int offset = 0;
for (int x = 0; x < width; x++)
@ -438,7 +438,7 @@ internal sealed class ExrEncoderCore
/// <param name="blueBuffer">The blue channel buffer.</param>
/// <param name="greenBuffer">The green channel buffer.</param>
/// <param name="redBuffer">The red channel buffer.</param>
private static void WriteUnsignedIntRow(Span<byte> buffer, int width, Span<uint> alphaBuffer, Span<uint> blueBuffer, Span<uint> greenBuffer, Span<uint> redBuffer)
private static void WriteUnsignedIntRow(Span<byte> buffer, int width, ReadOnlySpan<uint> alphaBuffer, ReadOnlySpan<uint> blueBuffer, ReadOnlySpan<uint> greenBuffer, ReadOnlySpan<uint> redBuffer)
{
int offset = 0;
for (int x = 0; x < width; x++)

4
src/ImageSharp/Formats/Jpeg/Components/Block8x8.cs

@ -1,4 +1,4 @@
// Copyright (c) Six Labors.
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
@ -129,7 +129,7 @@ internal partial struct Block8x8
/// <summary>
/// Cast and copy <see cref="Size"/> <see cref="int"/>-s from the beginning of 'source' span.
/// </summary>
public void LoadFrom(Span<int> source)
public void LoadFrom(ReadOnlySpan<int> source)
{
for (int i = 0; i < Size; i++)
{

4
src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs

@ -1,4 +1,4 @@
// Copyright (c) Six Labors.
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
@ -115,7 +115,7 @@ internal partial struct Block8x8F : IEquatable<Block8x8F>
/// Load raw 32bit floating point data from source
/// </summary>
/// <param name="source">Source</param>
public unsafe void LoadFrom(Span<int> source)
public unsafe void LoadFrom(ReadOnlySpan<int> source)
{
fixed (Vector4* ptr = &this.V0L)
{

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

@ -1,4 +1,4 @@
// Copyright (c) Six Labors.
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
#nullable disable
@ -1126,7 +1126,7 @@ internal sealed class JpegDecoderCore : ImageDecoderCore, IRawJpegData
/// <param name="blockDataSpan">The span holding the block resource data.</param>
/// <returns>The length of the name.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
private static int ReadImageResourceNameLength(Span<byte> blockDataSpan)
private static int ReadImageResourceNameLength(ReadOnlySpan<byte> blockDataSpan)
{
byte nameLength = blockDataSpan[2];
int nameDataSize = nameLength == 0 ? 2 : nameLength;
@ -1145,7 +1145,7 @@ internal sealed class JpegDecoderCore : ImageDecoderCore, IRawJpegData
/// <param name="resourceBlockNameLength">The length of the block name.</param>
/// <returns>The block length.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
private static int ReadResourceDataLength(Span<byte> blockDataSpan, int resourceBlockNameLength)
private static int ReadResourceDataLength(ReadOnlySpan<byte> blockDataSpan, int resourceBlockNameLength)
=> BinaryPrimitives.ReadInt32BigEndian(blockDataSpan.Slice(2 + resourceBlockNameLength, 4));
/// <summary>

6
src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs

@ -1,4 +1,4 @@
// Copyright (c) Six Labors.
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
#nullable disable
@ -620,7 +620,7 @@ internal sealed unsafe partial class JpegEncoderCore
/// </summary>
/// <param name="components">The collecction of component configuration items.</param>
/// <param name="buffer">Temporary buffer.</param>
private void WriteStartOfScan(Span<JpegComponentConfig> components, Span<byte> buffer) =>
private void WriteStartOfScan(ReadOnlySpan<JpegComponentConfig> components, Span<byte> buffer) =>
this.WriteStartOfScan(components, buffer, 0x00, 0x3f);
/// <summary>
@ -630,7 +630,7 @@ internal sealed unsafe partial class JpegEncoderCore
/// <param name="buffer">Temporary buffer.</param>
/// <param name="spectralStart">Start of spectral selection</param>
/// <param name="spectralEnd">End of spectral selection</param>
private void WriteStartOfScan(Span<JpegComponentConfig> components, Span<byte> buffer, byte spectralStart, byte spectralEnd)
private void WriteStartOfScan(ReadOnlySpan<JpegComponentConfig> components, Span<byte> buffer, byte spectralStart, byte spectralEnd)
{
// Write the SOS (Start Of Scan) marker "\xff\xda" followed by 12 bytes:
// - the marker length "\x00\x0c",

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

@ -1541,7 +1541,7 @@ internal sealed class PngEncoderCore : IDisposable
/// <param name="stream">The <see cref="Stream"/> to write to.</param>
/// <param name="type">The type of chunk to write.</param>
/// <param name="data">The <see cref="T:byte[]"/> containing data.</param>
private void WriteChunk(Stream stream, PngChunkType type, Span<byte> data)
private void WriteChunk(Stream stream, PngChunkType type, ReadOnlySpan<byte> data)
=> this.WriteChunk(stream, type, data, 0, data.Length);
/// <summary>
@ -1552,7 +1552,7 @@ internal sealed class PngEncoderCore : IDisposable
/// <param name="data">The <see cref="Span{Byte}"/> containing data.</param>
/// <param name="offset">The position to offset the data at.</param>
/// <param name="length">The of the data to write.</param>
private void WriteChunk(Stream stream, PngChunkType type, Span<byte> data, int offset, int length)
private void WriteChunk(Stream stream, PngChunkType type, ReadOnlySpan<byte> data, int offset, int length)
{
Span<byte> buffer = stackalloc byte[8];
@ -1584,7 +1584,7 @@ internal sealed class PngEncoderCore : IDisposable
/// <param name="data">The <see cref="Span{Byte}"/> containing data.</param>
/// <param name="offset">The position to offset the data at.</param>
/// <param name="length">The of the data to write.</param>
private void WriteFrameDataChunk(Stream stream, uint sequenceNumber, Span<byte> data, int offset, int length)
private void WriteFrameDataChunk(Stream stream, uint sequenceNumber, ReadOnlySpan<byte> data, int offset, int length)
{
Span<byte> buffer = stackalloc byte[12];

6
src/ImageSharp/Formats/Tga/TgaEncoderCore.cs

@ -1,4 +1,4 @@
// Copyright (c) Six Labors.
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Buffers;
@ -268,7 +268,7 @@ internal sealed class TgaEncoderCore
/// <param name="pixelRow">A pixel row of the image to encode.</param>
/// <param name="xStart">X coordinate to start searching for the same pixels.</param>
/// <returns>The number of equal pixels.</returns>
private static byte FindEqualPixels<TPixel>(Span<TPixel> pixelRow, int xStart)
private static byte FindEqualPixels<TPixel>(ReadOnlySpan<TPixel> pixelRow, int xStart)
where TPixel : unmanaged, IPixel<TPixel>
{
byte equalPixelCount = 0;
@ -301,7 +301,7 @@ internal sealed class TgaEncoderCore
/// <param name="pixelRow">A pixel row of the image to encode.</param>
/// <param name="xStart">X coordinate to start searching for the unequal pixels.</param>
/// <returns>The number of equal pixels.</returns>
private static byte FindUnEqualPixels<TPixel>(Span<TPixel> pixelRow, int xStart)
private static byte FindUnEqualPixels<TPixel>(ReadOnlySpan<TPixel> pixelRow, int xStart)
where TPixel : unmanaged, IPixel<TPixel>
{
byte unEqualPixelCount = 0;

4
src/ImageSharp/Formats/Tiff/Compression/Compressors/T6BitCompressor.cs

@ -1,4 +1,4 @@
// Copyright (c) Six Labors.
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
#nullable disable
@ -148,7 +148,7 @@ internal sealed class T6BitCompressor : TiffCcittCompressor
/// <returns>The index of the first pixel at or after <paramref name="startIndex"/>
/// that does not match <paramref name="color"/>, or the length of <paramref name="row"/>,
/// whichever comes first.</returns>
private static uint FindRunEnd(Span<byte> row, uint startIndex, byte? color = null)
private static uint FindRunEnd(ReadOnlySpan<byte> row, uint startIndex, byte? color = null)
{
if (startIndex >= row.Length)
{

6
src/ImageSharp/Formats/Tiff/Compression/Compressors/TiffLzwEncoder.cs

@ -1,4 +1,4 @@
// Copyright (c) Six Labors.
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Buffers;
@ -104,7 +104,7 @@ internal sealed class TiffLzwEncoder : IDisposable
/// </summary>
/// <param name="data">The data to compress.</param>
/// <param name="stream">The stream to write to.</param>
public void Encode(Span<byte> data, Stream stream)
public void Encode(ReadOnlySpan<byte> data, Stream stream)
{
this.Reset();
@ -214,7 +214,7 @@ internal sealed class TiffLzwEncoder : IDisposable
this.bufferPosition = 0;
}
private byte ReadNextByte(Span<byte> data) => data[this.bufferPosition++];
private byte ReadNextByte(ReadOnlySpan<byte> data) => data[this.bufferPosition++];
private void IncreaseCodeSizeOrResetIfNeeded(Stream stream)
{

18
src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs

@ -1,4 +1,4 @@
// Copyright (c) Six Labors.
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
#nullable disable
@ -440,8 +440,8 @@ internal class TiffDecoderCore : ImageDecoderCore
int width,
int height,
int rowsPerStrip,
Span<ulong> stripOffsets,
Span<ulong> stripByteCounts,
ReadOnlySpan<ulong> stripOffsets,
ReadOnlySpan<ulong> stripByteCounts,
CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel<TPixel>
{
@ -518,8 +518,8 @@ internal class TiffDecoderCore : ImageDecoderCore
int width,
int height,
int rowsPerStrip,
Span<ulong> stripOffsets,
Span<ulong> stripByteCounts,
ReadOnlySpan<ulong> stripOffsets,
ReadOnlySpan<ulong> stripByteCounts,
CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel<TPixel>
{
@ -670,8 +670,8 @@ internal class TiffDecoderCore : ImageDecoderCore
int tileLength,
int tilesAcross,
int tilesDown,
Span<ulong> tileOffsets,
Span<ulong> tileByteCounts,
ReadOnlySpan<ulong> tileOffsets,
ReadOnlySpan<ulong> tileByteCounts,
CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel<TPixel>
{
@ -780,8 +780,8 @@ internal class TiffDecoderCore : ImageDecoderCore
int tileLength,
int tilesAcross,
int tilesDown,
Span<ulong> tileOffsets,
Span<ulong> tileByteCounts,
ReadOnlySpan<ulong> tileOffsets,
ReadOnlySpan<ulong> tileByteCounts,
CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel<TPixel>
{

4
src/ImageSharp/Formats/Tiff/Writers/TiffStreamWriter.cs

@ -1,4 +1,4 @@
// Copyright (c) Six Labors.
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Buffers.Binary;
@ -103,7 +103,7 @@ internal sealed class TiffStreamWriter : IDisposable
/// Writes an array of bytes to the current stream, padded to four-bytes.
/// </summary>
/// <param name="value">The bytes to write.</param>
public void WritePadded(Span<byte> value)
public void WritePadded(ReadOnlySpan<byte> value)
{
this.BaseStream.Write(value);

12
src/ImageSharp/Formats/Webp/AlphaDecoder.cs

@ -1,4 +1,4 @@
// Copyright (c) Six Labors.
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Buffers;
@ -275,7 +275,7 @@ internal class AlphaDecoder : IDisposable
Vp8LTransform transform,
int yStart,
int yEnd,
Span<byte> src,
ReadOnlySpan<byte> src,
Span<byte> dst)
{
int bitsPerPixel = 8 >> transform.Bits;
@ -311,7 +311,7 @@ internal class AlphaDecoder : IDisposable
}
}
private static void HorizontalUnfilter(Span<byte> prev, Span<byte> input, Span<byte> dst, int width)
private static void HorizontalUnfilter(ReadOnlySpan<byte> prev, Span<byte> input, Span<byte> dst, int width)
{
if (Vector128.IsHardwareAccelerated && width >= 9)
{
@ -368,7 +368,7 @@ internal class AlphaDecoder : IDisposable
}
}
private static void GradientUnfilter(Span<byte> prev, Span<byte> input, Span<byte> dst, int width)
private static void GradientUnfilter(ReadOnlySpan<byte> prev, Span<byte> input, Span<byte> dst, int width)
{
if (prev.IsEmpty)
{
@ -424,7 +424,7 @@ internal class AlphaDecoder : IDisposable
return true;
}
private static void MapAlpha(Span<byte> src, Span<uint> colorMap, Span<byte> dst, int yStart, int yEnd, int width)
private static void MapAlpha(ReadOnlySpan<byte> src, ReadOnlySpan<uint> colorMap, Span<byte> dst, int yStart, int yEnd, int width)
{
int offset = 0;
for (int y = yStart; y < yEnd; y++)
@ -448,7 +448,7 @@ internal class AlphaDecoder : IDisposable
}
[MethodImpl(InliningOptions.ShortMethod)]
private static void ExtractGreen(Span<uint> argb, Span<byte> alpha, int size)
private static void ExtractGreen(ReadOnlySpan<uint> argb, Span<byte> alpha, int size)
{
for (int i = 0; i < size; i++)
{

4
src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs

@ -1,4 +1,4 @@
// Copyright (c) Six Labors.
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using SixLabors.ImageSharp.Formats.Webp.Chunks;
@ -177,7 +177,7 @@ internal abstract class BitWriterBase
/// <param name="stream">The stream to write to.</param>
/// <param name="dataBytes">The alpha channel data bytes.</param>
/// <param name="alphaDataIsCompressed">Indicates, if the alpha channel data is compressed.</param>
public static void WriteAlphaChunk(Stream stream, Span<byte> dataBytes, bool alphaDataIsCompressed)
public static void WriteAlphaChunk(Stream stream, ReadOnlySpan<byte> dataBytes, bool alphaDataIsCompressed)
{
long pos = RiffHelper.BeginWriteChunk(stream, (uint)WebpChunkType.Alpha);
byte flags = 0;

4
src/ImageSharp/Formats/Webp/BitWriter/Vp8BitWriter.cs

@ -1,4 +1,4 @@
// Copyright (c) Six Labors.
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Buffers.Binary;
@ -223,7 +223,7 @@ internal class Vp8BitWriter : BitWriterBase
}
}
public int PutI4Mode(int mode, Span<byte> prob)
public int PutI4Mode(int mode, ReadOnlySpan<byte> prob)
{
if (this.PutBit(mode != B_DC_PRED, prob[0]))
{

4
src/ImageSharp/Formats/Webp/Lossless/BackwardReferenceEncoder.cs

@ -1,4 +1,4 @@
// Copyright (c) Six Labors.
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Buffers;
@ -375,7 +375,7 @@ internal static class BackwardReferenceEncoder
return chosenPathSize;
}
private static void BackwardReferencesHashChainFollowChosenPath(ReadOnlySpan<uint> bgra, int cacheBits, Span<ushort> chosenPath, int chosenPathSize, Vp8LHashChain hashChain, Vp8LBackwardRefs backwardRefs)
private static void BackwardReferencesHashChainFollowChosenPath(ReadOnlySpan<uint> bgra, int cacheBits, ReadOnlySpan<ushort> chosenPath, int chosenPathSize, Vp8LHashChain hashChain, Vp8LBackwardRefs backwardRefs)
{
bool useColorCache = cacheBits > 0;
ColorCache? colorCache = null;

6
src/ImageSharp/Formats/Webp/Lossless/ColorSpaceTransformUtils.cs

@ -17,7 +17,7 @@ internal static class ColorSpaceTransformUtils
const int span = 16;
Span<ushort> values = stackalloc ushort[span];
// These shuffle masks are safe for use with Avx2.Shuffle because all indices are within their respective 128-bit lanes (0–15 for the low mask, 16–31 for the high mask),
// These shuffle masks are safe for use with Avx2.Shuffle because all indices are within their respective 128-bit lanes (0-15 for the low mask, 16-31 for the high mask),
// and all disabled lanes are set to 0xFF to zero those bytes per the vpshufb specification. This guarantees lane-local shuffling with no cross-lane violations.
Vector256<byte> collectColorBlueTransformsShuffleLowMask256 = Vector256.Create(255, 2, 255, 6, 255, 10, 255, 14, 255, 255, 255, 255, 255, 255, 255, 255, 255, 18, 255, 22, 255, 26, 255, 30, 255, 255, 255, 255, 255, 255, 255, 255);
Vector256<byte> collectColorBlueTransformsShuffleHighMask256 = Vector256.Create(255, 255, 255, 255, 255, 255, 255, 255, 255, 2, 255, 6, 255, 10, 255, 14, 255, 255, 255, 255, 255, 255, 255, 255, 255, 18, 255, 22, 255, 26, 255, 30);
@ -121,7 +121,7 @@ internal static class ColorSpaceTransformUtils
}
}
private static void CollectColorBlueTransformsScalar(Span<uint> bgra, int stride, int tileWidth, int tileHeight, int greenToBlue, int redToBlue, Span<int> histo)
private static void CollectColorBlueTransformsScalar(ReadOnlySpan<uint> bgra, int stride, int tileWidth, int tileHeight, int greenToBlue, int redToBlue, Span<int> histo)
{
int pos = 0;
while (tileHeight-- > 0)
@ -230,7 +230,7 @@ internal static class ColorSpaceTransformUtils
}
}
private static void CollectColorRedTransformsScalar(Span<uint> bgra, int stride, int tileWidth, int tileHeight, int greenToRed, Span<int> histo)
private static void CollectColorRedTransformsScalar(ReadOnlySpan<uint> bgra, int stride, int tileWidth, int tileHeight, int greenToRed, Span<int> histo)
{
int pos = 0;
while (tileHeight-- > 0)

2
src/ImageSharp/Formats/Webp/Lossless/CostModel.cs

@ -74,7 +74,7 @@ internal class CostModel
public double GetLiteralCost(uint v) => this.Alpha[v >> 24] + this.Red[(v >> 16) & 0xff] + this.Literal[(v >> 8) & 0xff] + this.Blue[v & 0xff];
private static void ConvertPopulationCountTableToBitEstimates(int numSymbols, Span<uint> populationCounts, double[] output)
private static void ConvertPopulationCountTableToBitEstimates(int numSymbols, ReadOnlySpan<uint> populationCounts, double[] output)
{
uint sum = 0;
int nonzeros = 0;

2
src/ImageSharp/Formats/Webp/Lossless/HistogramEncoder.cs

@ -196,7 +196,7 @@ internal static class HistogramEncoder
private static void HistogramCombineEntropyBin(
Vp8LHistogramSet histograms,
Span<ushort> clusters,
ReadOnlySpan<ushort> clusters,
Span<ushort> clusterMappings,
Vp8LHistogram curCombo,
ReadOnlySpan<ushort> binMap,

8
src/ImageSharp/Formats/Webp/Lossless/HuffmanUtils.cs

@ -159,7 +159,7 @@ internal static class HuffmanUtils
/// <param name="histogramSize">The size of the histogram.</param>
/// <param name="treeDepthLimit">The tree depth limit.</param>
/// <param name="bitDepths">How many bits are used for the symbol.</param>
public static void GenerateOptimalTree(Span<HuffmanTree> tree, Span<uint> histogram, int histogramSize, int treeDepthLimit, byte[] bitDepths)
public static void GenerateOptimalTree(Span<HuffmanTree> tree, ReadOnlySpan<uint> histogram, int histogramSize, int treeDepthLimit, byte[] bitDepths)
{
uint countMin;
int treeSizeOrig = 0;
@ -445,7 +445,7 @@ internal static class HuffmanUtils
return totalSize;
}
private static int CodeRepeatedZeros(int repetitions, Span<HuffmanTreeToken> tokens)
private static int CodeRepeatedZeros(int repetitions, ReadOnlySpan<HuffmanTreeToken> tokens)
{
int pos = 0;
while (repetitions >= 1)
@ -487,7 +487,7 @@ internal static class HuffmanUtils
return pos;
}
private static int CodeRepeatedValues(int repetitions, Span<HuffmanTreeToken> tokens, int value, int prevValue)
private static int CodeRepeatedValues(int repetitions, ReadOnlySpan<HuffmanTreeToken> tokens, int value, int prevValue)
{
int pos = 0;
@ -565,7 +565,7 @@ internal static class HuffmanUtils
}
}
private static void SetBitDepths(Span<HuffmanTree> tree, Span<HuffmanTree> pool, byte[] bitDepths, int level)
private static void SetBitDepths(ReadOnlySpan<HuffmanTree> tree, Span<HuffmanTree> pool, byte[] bitDepths, int level)
{
if (tree[0].PoolIndexLeft >= 0)
{

4
src/ImageSharp/Formats/Webp/Lossless/LosslessUtils.cs

@ -98,7 +98,7 @@ internal static unsafe class LosslessUtils
if (Vector256.IsHardwareAccelerated && pixelData.Length >= 8)
{
// The `255` values disable the write for alpha (A), since 0x80 is set in the control byte (high bit set).
// Each byte index is within its respective 128-bit lane (0–15 and 16–31), so this is safe for per-lane shuffle.
// Each byte index is within its respective 128-bit lane (0-15 and 16-31), so this is safe for per-lane shuffle.
// The high bits are not set for the index bytes, and the values are always < 16 per lane, satisfying AVX2 lane rules.
Vector256<byte> addGreenToBlueAndRedMask = Vector256.Create(1, 255, 1, 255, 5, 255, 5, 255, 9, 255, 9, 255, 13, 255, 13, 255, 17, 255, 17, 255, 21, 255, 21, 255, 25, 255, 25, 255, 29, 255, 29, 255);
nuint numPixels = (uint)pixelData.Length;
@ -675,7 +675,7 @@ internal static unsafe class LosslessUtils
/// <summary>
/// Bundles multiple (1, 2, 4 or 8) pixels into a single pixel.
/// </summary>
public static void BundleColorMap(Span<byte> row, int width, int xBits, Span<uint> dst)
public static void BundleColorMap(ReadOnlySpan<byte> row, int width, int xBits, Span<uint> dst)
{
int x;
if (xBits > 0)

2
src/ImageSharp/Formats/Webp/Lossless/NearLosslessEnc.cs

@ -99,7 +99,7 @@ internal static class NearLosslessEnc
return biased & ~mask;
}
private static bool IsSmooth(Span<uint> prevRow, Span<uint> currRow, Span<uint> nextRow, int ix, int limit) =>
private static bool IsSmooth(ReadOnlySpan<uint> prevRow, ReadOnlySpan<uint> currRow, ReadOnlySpan<uint> nextRow, int ix, int limit) =>
IsNear(currRow[ix], currRow[ix - 1], limit) && // Check that all pixels in 4-connected neighborhood are smooth.
IsNear(currRow[ix], currRow[ix + 1], limit) &&
IsNear(currRow[ix], prevRow[ix], limit) &&

10
src/ImageSharp/Formats/Webp/Lossless/PredictorEncoder.cs

@ -205,7 +205,7 @@ internal static unsafe class PredictorEncoder
TransparentColorMode transparentColorMode,
bool usedSubtractGreen,
bool nearLossless,
Span<uint> modes,
ReadOnlySpan<uint> modes,
Span<short> scratch)
{
const int numPredModes = 14;
@ -334,7 +334,7 @@ internal static unsafe class PredictorEncoder
int height,
Span<uint> upperRowSpan,
Span<uint> currentRowSpan,
Span<byte> maxDiffs,
ReadOnlySpan<byte> maxDiffs,
int mode,
int xStart,
int xEnd,
@ -575,7 +575,7 @@ internal static unsafe class PredictorEncoder
int width,
int height,
int bits,
Span<uint> modes,
ReadOnlySpan<uint> modes,
Span<uint> argbScratch,
Span<uint> argb,
int maxQuantization,
@ -746,7 +746,7 @@ internal static unsafe class PredictorEncoder
}
#pragma warning restore SA1503 // Braces should not be omitted
private static void MaxDiffsForRow(int width, int stride, Span<uint> argb, int offset, Span<byte> maxDiffs, bool usedSubtractGreen)
private static void MaxDiffsForRow(int width, int stride, ReadOnlySpan<uint> argb, int offset, Span<byte> maxDiffs, bool usedSubtractGreen)
{
if (width <= 2)
{
@ -1058,7 +1058,7 @@ internal static unsafe class PredictorEncoder
}
[MethodImpl(InliningOptions.ShortMethod)]
private static float PredictionCostSpatial(Span<int> counts, int weight0, double expVal)
private static float PredictionCostSpatial(ReadOnlySpan<int> counts, int weight0, double expVal)
{
int significantSymbols = 256 >> 4;
double expDecayFactor = 0.6;

8
src/ImageSharp/Formats/Webp/Lossless/Vp8LBitEntropy.cs

@ -100,7 +100,7 @@ internal class Vp8LBitEntropy
return this.Entropy < minLimit ? minLimit : this.Entropy;
}
public void BitsEntropyUnrefined(Span<uint> array, int n)
public void BitsEntropyUnrefined(ReadOnlySpan<uint> array, int n)
{
this.Init();
@ -125,7 +125,7 @@ internal class Vp8LBitEntropy
/// <summary>
/// Get the entropy for the distribution 'X'.
/// </summary>
public void BitsEntropyUnrefined(Span<uint> x, int length, Vp8LStreaks stats)
public void BitsEntropyUnrefined(ReadOnlySpan<uint> x, int length, Vp8LStreaks stats)
{
int i;
int iPrev = 0;
@ -147,7 +147,7 @@ internal class Vp8LBitEntropy
this.Entropy += LosslessUtils.FastSLog2(this.Sum);
}
public void GetCombinedEntropyUnrefined(Span<uint> x, Span<uint> y, int length, Vp8LStreaks stats)
public void GetCombinedEntropyUnrefined(ReadOnlySpan<uint> x, ReadOnlySpan<uint> y, int length, Vp8LStreaks stats)
{
int i;
int iPrev = 0;
@ -169,7 +169,7 @@ internal class Vp8LBitEntropy
this.Entropy += LosslessUtils.FastSLog2(this.Sum);
}
public void GetEntropyUnrefined(Span<uint> x, int length, Vp8LStreaks stats)
public void GetEntropyUnrefined(ReadOnlySpan<uint> x, int length, Vp8LStreaks stats)
{
int i;
int iPrev = 0;

16
src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs

@ -812,7 +812,7 @@ internal class Vp8LEncoder : IDisposable
this.EncodeImageNoHuffman(this.TransformData.GetSpan(), this.HashChain, this.Refs[0], this.Refs[1], transformWidth, transformHeight, this.quality, lowEffort);
}
private void EncodeImageNoHuffman(Span<uint> bgra, Vp8LHashChain hashChain, Vp8LBackwardRefs refsTmp1, Vp8LBackwardRefs refsTmp2, int width, int height, uint quality, bool lowEffort)
private void EncodeImageNoHuffman(ReadOnlySpan<uint> bgra, Vp8LHashChain hashChain, Vp8LBackwardRefs refsTmp1, Vp8LBackwardRefs refsTmp2, int width, int height, uint quality, bool lowEffort)
{
int cacheBits = 0;
ushort[] histogramSymbols = new ushort[1]; // Only one tree, one symbol.
@ -1044,7 +1044,7 @@ internal class Vp8LEncoder : IDisposable
int width,
int histoBits,
Vp8LBackwardRefs backwardRefs,
Span<ushort> histogramSymbols,
ReadOnlySpan<ushort> histogramSymbols,
HuffmanTreeCode[] huffmanCodes)
{
int histoXSize = histoBits > 0 ? LosslessUtils.SubSampleSize(width, histoBits) : 1;
@ -1457,7 +1457,7 @@ internal class Vp8LEncoder : IDisposable
}
}
private static void ApplyPaletteFor(int width, int height, Span<uint> palette, int hashIdx, Span<uint> src, int srcStride, Span<uint> dst, int dstStride, Span<byte> tmpRow, uint[] buffer, int xBits)
private static void ApplyPaletteFor(int width, int height, ReadOnlySpan<uint> palette, int hashIdx, Span<uint> src, int srcStride, Span<uint> dst, int dstStride, Span<byte> tmpRow, uint[] buffer, int xBits)
{
uint prevPix = palette[0];
uint prevIdx = 0;
@ -1494,7 +1494,7 @@ internal class Vp8LEncoder : IDisposable
}
}
private static void ApplyPaletteForWithIdxMap(int width, int height, Span<uint> palette, Span<uint> src, int srcStride, Span<uint> dst, int dstStride, Span<byte> tmpRow, uint[] idxMap, int xBits, uint[] paletteSorted, int paletteSize)
private static void ApplyPaletteForWithIdxMap(int width, int height, ReadOnlySpan<uint> palette, Span<uint> src, int srcStride, Span<uint> dst, int dstStride, Span<byte> tmpRow, uint[] idxMap, int xBits, uint[] paletteSorted, int paletteSize)
{
uint prevPix = palette[0];
uint prevIdx = 0;
@ -1590,7 +1590,7 @@ internal class Vp8LEncoder : IDisposable
/// <param name="palette">The palette.</param>
/// <param name="numColors">Number of colors in the palette.</param>
/// <returns>True, if the palette has no monotonous deltas.</returns>
private static bool PaletteHasNonMonotonousDeltas(Span<uint> palette, int numColors)
private static bool PaletteHasNonMonotonousDeltas(ReadOnlySpan<uint> palette, int numColors)
{
const uint predict = 0x000000;
byte signFound = 0x00;
@ -1619,6 +1619,7 @@ internal class Vp8LEncoder : IDisposable
return (signFound & (signFound << 1)) != 0; // two consequent signs.
}
#pragma warning disable CA1517 // False positive: https://github.com/dotnet/sdk/issues/53388
/// <summary>
/// Find greedily always the closest color of the predicted color to minimize
/// deltas in the palette. This reduces storage needs since the palette is stored with delta encoding.
@ -1647,6 +1648,7 @@ internal class Vp8LEncoder : IDisposable
predict = palette[i];
}
}
#pragma warning restore CA1517
private static void GetHuffBitLengthsAndCodes(Vp8LHistogramSet histogramImage, HuffmanTreeCode[] huffmanCodes)
{
@ -1762,7 +1764,7 @@ internal class Vp8LEncoder : IDisposable
/// <summary>
/// Bundles multiple (1, 2, 4 or 8) pixels into a single pixel.
/// </summary>
private static void BundleColorMap(Span<byte> row, int width, int xBits, Span<uint> dst)
private static void BundleColorMap(ReadOnlySpan<byte> row, int width, int xBits, Span<uint> dst)
{
int x;
if (xBits > 0)
@ -1836,7 +1838,7 @@ internal class Vp8LEncoder : IDisposable
}
[MethodImpl(InliningOptions.ShortMethod)]
private static uint SearchColorGreedy(Span<uint> palette, uint color)
private static uint SearchColorGreedy(ReadOnlySpan<uint> palette, uint color)
{
if (color == palette[0])
{

10
src/ImageSharp/Formats/Webp/Lossless/Vp8LHistogram.cs

@ -441,8 +441,8 @@ internal abstract unsafe class Vp8LHistogram
}
private static double GetCombinedEntropy(
Span<uint> x,
Span<uint> y,
ReadOnlySpan<uint> x,
ReadOnlySpan<uint> y,
int length,
bool isXUsed,
bool isYUsed,
@ -494,7 +494,7 @@ internal abstract unsafe class Vp8LHistogram
return bitEntropy.BitsEntropyRefine() + stats.FinalHuffmanCost();
}
private static double ExtraCostCombined(Span<uint> x, Span<uint> y, int length)
private static double ExtraCostCombined(ReadOnlySpan<uint> x, ReadOnlySpan<uint> y, int length)
{
double cost = 0.0d;
for (int i = 2; i < length - 2; i++)
@ -509,7 +509,7 @@ internal abstract unsafe class Vp8LHistogram
/// <summary>
/// Get the symbol entropy for the distribution 'population'.
/// </summary>
private double PopulationCost(Span<uint> population, int length, ref uint trivialSym, int isUsedIndex, Vp8LStreaks stats, Vp8LBitEntropy bitEntropy)
private double PopulationCost(ReadOnlySpan<uint> population, int length, ref uint trivialSym, int isUsedIndex, Vp8LStreaks stats, Vp8LBitEntropy bitEntropy)
{
bitEntropy.Init();
stats.Clear();
@ -523,7 +523,7 @@ internal abstract unsafe class Vp8LHistogram
return bitEntropy.BitsEntropyRefine() + stats.FinalHuffmanCost();
}
private static double ExtraCost(Span<uint> population, int length)
private static double ExtraCost(ReadOnlySpan<uint> population, int length)
{
double cost = 0.0d;
for (int i = 2; i < length - 2; i++)

4
src/ImageSharp/Formats/Webp/Lossless/WebpLosslessDecoder.cs

@ -339,7 +339,7 @@ internal sealed class WebpLosslessDecoder
}
}
private static void AdvanceByOne(ref int col, ref int row, int width, ColorCache colorCache, ref int decodedPixels, Span<uint> pixelData, ref int lastCached)
private static void AdvanceByOne(ref int col, ref int row, int width, ColorCache colorCache, ref int decodedPixels, ReadOnlySpan<uint> pixelData, ref int lastCached)
{
col++;
decodedPixels++;
@ -826,7 +826,7 @@ internal sealed class WebpLosslessDecoder
decoder.Metadata.HuffmanMask = numBits == 0 ? ~0 : (1 << numBits) - 1;
}
private uint ReadPackedSymbols(Span<HTreeGroup> group, Span<uint> pixelData, int decodedPixels)
private uint ReadPackedSymbols(ReadOnlySpan<HTreeGroup> group, Span<uint> pixelData, int decodedPixels)
{
uint val = (uint)(this.bitReader.PrefetchBits() & (HuffmanUtils.HuffmanPackedTableSize - 1));
HuffmanCode code = group[0].PackedTable[val];

50
src/ImageSharp/Formats/Webp/Lossy/LossyUtils.cs

@ -123,7 +123,7 @@ internal static class LossyUtils
}
[MethodImpl(InliningOptions.ShortMethod)]
public static int Vp8_SseNxN(Span<byte> a, Span<byte> b, int w, int h)
public static int Vp8_SseNxN(ReadOnlySpan<byte> a, ReadOnlySpan<byte> b, int w, int h)
{
int count = 0;
int offset = 0;
@ -285,7 +285,7 @@ internal static class LossyUtils
return Math.Abs(sum2 - sum1) >> 5;
}
public static void DC16(Span<byte> dst, Span<byte> yuv, int offset)
public static void DC16(Span<byte> dst, ReadOnlySpan<byte> yuv, int offset)
{
int offsetMinus1 = offset - 1;
int offsetMinusBps = offset - WebpConstants.Bps;
@ -313,7 +313,7 @@ internal static class LossyUtils
}
}
public static void HE16(Span<byte> dst, Span<byte> yuv, int offset)
public static void HE16(Span<byte> dst, ReadOnlySpan<byte> yuv, int offset)
{
// horizontal
offset--;
@ -327,7 +327,7 @@ internal static class LossyUtils
}
}
public static void DC16NoTop(Span<byte> dst, Span<byte> yuv, int offset)
public static void DC16NoTop(Span<byte> dst, ReadOnlySpan<byte> yuv, int offset)
{
// DC with top samples not available.
int dc = 8;
@ -340,7 +340,7 @@ internal static class LossyUtils
Put16(dc >> 4, dst);
}
public static void DC16NoLeft(Span<byte> dst, Span<byte> yuv, int offset)
public static void DC16NoLeft(Span<byte> dst, ReadOnlySpan<byte> yuv, int offset)
{
// DC with left samples not available.
int dc = 8;
@ -357,7 +357,7 @@ internal static class LossyUtils
public static void DC16NoTopLeft(Span<byte> dst) =>
Put16(0x80, dst); // DC with no top and left samples.
public static void DC8uv(Span<byte> dst, Span<byte> yuv, int offset)
public static void DC8uv(Span<byte> dst, ReadOnlySpan<byte> yuv, int offset)
{
int dc0 = 8;
int offsetMinus1 = offset - 1;
@ -388,7 +388,7 @@ internal static class LossyUtils
}
}
public static void HE8uv(Span<byte> dst, Span<byte> yuv, int offset)
public static void HE8uv(Span<byte> dst, ReadOnlySpan<byte> yuv, int offset)
{
// horizontal
offset--;
@ -403,7 +403,7 @@ internal static class LossyUtils
}
}
public static void DC8uvNoTop(Span<byte> dst, Span<byte> yuv, int offset)
public static void DC8uvNoTop(Span<byte> dst, ReadOnlySpan<byte> yuv, int offset)
{
// DC with no top samples.
int dc0 = 4;
@ -418,7 +418,7 @@ internal static class LossyUtils
Put8x8uv((byte)(dc0 >> 3), dst);
}
public static void DC8uvNoLeft(Span<byte> dst, Span<byte> yuv, int offset)
public static void DC8uvNoLeft(Span<byte> dst, ReadOnlySpan<byte> yuv, int offset)
{
// DC with no left samples.
int offsetMinusBps = offset - WebpConstants.Bps;
@ -436,7 +436,7 @@ internal static class LossyUtils
public static void DC8uvNoTopLeft(Span<byte> dst) =>
Put8x8uv(0x80, dst); // DC with nothing.
public static void DC4(Span<byte> dst, Span<byte> yuv, int offset)
public static void DC4(Span<byte> dst, ReadOnlySpan<byte> yuv, int offset)
{
int dc = 4;
int offsetMinusBps = offset - WebpConstants.Bps;
@ -457,7 +457,7 @@ internal static class LossyUtils
[MethodImpl(InliningOptions.ShortMethod)]
public static void TM4(Span<byte> dst, Span<byte> yuv, int offset) => TrueMotion(dst, yuv, offset, 4);
public static void VE4(Span<byte> dst, Span<byte> yuv, int offset, Span<byte> vals)
public static void VE4(Span<byte> dst, ReadOnlySpan<byte> yuv, int offset, Span<byte> vals)
{
// vertical
int topOffset = offset - WebpConstants.Bps;
@ -472,7 +472,7 @@ internal static class LossyUtils
}
}
public static void HE4(Span<byte> dst, Span<byte> yuv, int offset)
public static void HE4(Span<byte> dst, ReadOnlySpan<byte> yuv, int offset)
{
// horizontal
int offsetMinusOne = offset - 1;
@ -491,7 +491,7 @@ internal static class LossyUtils
BinaryPrimitives.WriteUInt32BigEndian(dst[(3 * WebpConstants.Bps)..], val);
}
public static void RD4(Span<byte> dst, Span<byte> yuv, int offset)
public static void RD4(Span<byte> dst, ReadOnlySpan<byte> yuv, int offset)
{
// Down-right
int offsetMinusOne = offset - 1;
@ -528,7 +528,7 @@ internal static class LossyUtils
Dst(dst, 3, 0, Avg3(d, c, b));
}
public static void VR4(Span<byte> dst, Span<byte> yuv, int offset)
public static void VR4(Span<byte> dst, ReadOnlySpan<byte> yuv, int offset)
{
// Vertical-Right
int offsetMinusOne = offset - 1;
@ -565,7 +565,7 @@ internal static class LossyUtils
Dst(dst, 3, 1, Avg3(b, c, d));
}
public static void LD4(Span<byte> dst, Span<byte> yuv, int offset)
public static void LD4(Span<byte> dst, ReadOnlySpan<byte> yuv, int offset)
{
// Down-Left
byte a = yuv[offset - WebpConstants.Bps];
@ -600,7 +600,7 @@ internal static class LossyUtils
Dst(dst, 3, 3, Avg3(g, h, h));
}
public static void VL4(Span<byte> dst, Span<byte> yuv, int offset)
public static void VL4(Span<byte> dst, ReadOnlySpan<byte> yuv, int offset)
{
// Vertical-Left
byte a = yuv[offset - WebpConstants.Bps];
@ -636,7 +636,7 @@ internal static class LossyUtils
Dst(dst, 3, 3, Avg3(f, g, h));
}
public static void HD4(Span<byte> dst, Span<byte> yuv, int offset)
public static void HD4(Span<byte> dst, ReadOnlySpan<byte> yuv, int offset)
{
// Horizontal-Down
byte i = yuv[offset - 1];
@ -672,7 +672,7 @@ internal static class LossyUtils
Dst(dst, 1, 3, Avg3(l, k, j));
}
public static void HU4(Span<byte> dst, Span<byte> yuv, int offset)
public static void HU4(Span<byte> dst, ReadOnlySpan<byte> yuv, int offset)
{
// Horizontal-Up
byte i = yuv[offset - 1];
@ -705,7 +705,7 @@ internal static class LossyUtils
/// <summary>
/// Paragraph 14.3: Implementation of the Walsh-Hadamard transform inversion.
/// </summary>
public static void TransformWht(Span<short> input, Span<short> output, Span<int> scratch)
public static void TransformWht(ReadOnlySpan<short> input, Span<short> output, Span<int> scratch)
{
Span<int> tmp = scratch[..16];
tmp.Clear();
@ -746,7 +746,7 @@ internal static class LossyUtils
/// Returns the weighted sum of the absolute value of transformed coefficients.
/// w[] contains a row-major 4 by 4 symmetric matrix.
/// </summary>
public static int TTransform(Span<byte> input, Span<ushort> w, Span<int> scratch)
public static int TTransform(ReadOnlySpan<byte> input, Span<ushort> w, Span<int> scratch)
{
int sum = 0;
Span<int> tmp = scratch[..16];
@ -1249,7 +1249,7 @@ internal static class LossyUtils
}
}
public static void TransformDc(Span<short> src, Span<byte> dst)
public static void TransformDc(ReadOnlySpan<short> src, Span<byte> dst)
{
int dc = src[0] + 4;
for (int j = 0; j < 4; j++)
@ -1262,7 +1262,7 @@ internal static class LossyUtils
}
// Simplified transform when only src[0], src[1] and src[4] are non-zero
public static void TransformAc3(Span<short> src, Span<byte> dst)
public static void TransformAc3(ReadOnlySpan<short> src, Span<byte> dst)
{
int a = src[0] + 4;
int c4 = Mul2(src[4]);
@ -2133,7 +2133,7 @@ internal static class LossyUtils
}
[MethodImpl(InliningOptions.ShortMethod)]
private static bool NeedsFilter(Span<byte> p, int offset, int step, int t)
private static bool NeedsFilter(ReadOnlySpan<byte> p, int offset, int step, int t)
{
int p1 = p[offset + (-2 * step)];
int p0 = p[offset - step];
@ -2142,7 +2142,7 @@ internal static class LossyUtils
return (4 * WebpLookupTables.Abs0(p0 - q0)) + WebpLookupTables.Abs0(p1 - q1) <= t;
}
private static bool NeedsFilter2(Span<byte> p, int offset, int step, int t, int it)
private static bool NeedsFilter2(ReadOnlySpan<byte> p, int offset, int step, int t, int it)
{
int step2 = 2 * step;
int step3 = 3 * step;
@ -2357,7 +2357,7 @@ internal static class LossyUtils
=> Vector128_.SubtractSaturate(q, p) | Vector128_.SubtractSaturate(p, q);
[MethodImpl(InliningOptions.ShortMethod)]
private static bool Hev(Span<byte> p, int offset, int step, int thresh)
private static bool Hev(ReadOnlySpan<byte> p, int offset, int step, int thresh)
{
int p1 = p[offset - (2 * step)];
int p0 = p[offset - step];

2
src/ImageSharp/Formats/Webp/Lossy/Vp8EncIterator.cs

@ -854,7 +854,7 @@ internal class Vp8EncIterator
}
}
private static void ImportLine(Span<byte> src, int srcStride, Span<byte> dst, int len, int totalLen)
private static void ImportLine(ReadOnlySpan<byte> src, int srcStride, Span<byte> dst, int len, int totalLen)
{
int i;
int srcIdx = 0;

2
src/ImageSharp/Formats/Webp/Lossy/Vp8EncProba.cs

@ -234,7 +234,7 @@ internal class Vp8EncProba
private static int CalcSkipProba(long nb, long total) => (int)(total != 0 ? (total - nb) * 255 / total : 255);
private static int VariableLevelCost(int level, Span<byte> probas)
private static int VariableLevelCost(int level, ReadOnlySpan<byte> probas)
{
int pattern = WebpLookupTables.Vp8LevelCodes[level - 1][0];
int bits = WebpLookupTables.Vp8LevelCodes[level - 1][1];

28
src/ImageSharp/Formats/Webp/Lossy/Vp8Encoding.cs

@ -599,7 +599,7 @@ internal static unsafe class Vp8Encoding
Unsafe.As<short, Vector128<short>>(ref Unsafe.Add(ref outputRef, 8)) = d2f3.AsInt16();
}
public static void FTransformWht(Span<short> input, Span<short> output, Span<int> scratch)
public static void FTransformWht(ReadOnlySpan<short> input, Span<short> output, Span<int> scratch)
{
Span<int> tmp = scratch[..16];
@ -679,7 +679,7 @@ internal static unsafe class Vp8Encoding
// Left samples are top[-5 .. -2], top_left is top[-1], top are
// located at top[0..3], and top right is top[4..7]
public static void EncPredLuma4(Span<byte> dst, Span<byte> top, int topOffset, Span<byte> vals)
public static void EncPredLuma4(Span<byte> dst, ReadOnlySpan<byte> top, int topOffset, Span<byte> vals)
{
Dc4(dst[I4DC4..], top, topOffset);
Tm4(dst[I4TM4..], top, topOffset);
@ -764,7 +764,7 @@ internal static unsafe class Vp8Encoding
}
}
private static void DcMode(Span<byte> dst, Span<byte> left, Span<byte> top, int size, int round, int shift)
private static void DcMode(Span<byte> dst, Span<byte> left, ReadOnlySpan<byte> top, int size, int round, int shift)
{
int dc = 0;
int j;
@ -813,7 +813,7 @@ internal static unsafe class Vp8Encoding
Fill(dst, dc, size);
}
private static void Dc4(Span<byte> dst, Span<byte> top, int topOffset)
private static void Dc4(Span<byte> dst, ReadOnlySpan<byte> top, int topOffset)
{
uint dc = 4;
int i;
@ -825,7 +825,7 @@ internal static unsafe class Vp8Encoding
Fill(dst, (int)(dc >> 3), 4);
}
private static void Tm4(Span<byte> dst, Span<byte> top, int topOffset)
private static void Tm4(Span<byte> dst, ReadOnlySpan<byte> top, int topOffset)
{
Span<byte> clip = Clip1.AsSpan(255 - top[topOffset - 1]);
for (int y = 0; y < 4; y++)
@ -840,7 +840,7 @@ internal static unsafe class Vp8Encoding
}
}
private static void Ve4(Span<byte> dst, Span<byte> top, int topOffset, Span<byte> vals)
private static void Ve4(Span<byte> dst, ReadOnlySpan<byte> top, int topOffset, Span<byte> vals)
{
// vertical
vals[0] = LossyUtils.Avg3(top[topOffset - 1], top[topOffset], top[topOffset + 1]);
@ -853,7 +853,7 @@ internal static unsafe class Vp8Encoding
}
}
private static void He4(Span<byte> dst, Span<byte> top, int topOffset)
private static void He4(Span<byte> dst, ReadOnlySpan<byte> top, int topOffset)
{
// horizontal
byte x = top[topOffset - 1];
@ -872,7 +872,7 @@ internal static unsafe class Vp8Encoding
BinaryPrimitives.WriteUInt32BigEndian(dst[(3 * WebpConstants.Bps)..], val);
}
private static void Rd4(Span<byte> dst, Span<byte> top, int topOffset)
private static void Rd4(Span<byte> dst, ReadOnlySpan<byte> top, int topOffset)
{
byte x = top[topOffset - 1];
byte i = top[topOffset - 2];
@ -907,7 +907,7 @@ internal static unsafe class Vp8Encoding
LossyUtils.Dst(dst, 3, 0, LossyUtils.Avg3(d, c, b));
}
private static void Vr4(Span<byte> dst, Span<byte> top, int topOffset)
private static void Vr4(Span<byte> dst, ReadOnlySpan<byte> top, int topOffset)
{
byte x = top[topOffset - 1];
byte i = top[topOffset - 2];
@ -942,7 +942,7 @@ internal static unsafe class Vp8Encoding
LossyUtils.Dst(dst, 3, 1, LossyUtils.Avg3(b, c, d));
}
private static void Ld4(Span<byte> dst, Span<byte> top, int topOffset)
private static void Ld4(Span<byte> dst, ReadOnlySpan<byte> top, int topOffset)
{
byte a = top[topOffset + 0];
byte b = top[topOffset + 1];
@ -976,7 +976,7 @@ internal static unsafe class Vp8Encoding
LossyUtils.Dst(dst, 3, 3, LossyUtils.Avg3(g, h, h));
}
private static void Vl4(Span<byte> dst, Span<byte> top, int topOffset)
private static void Vl4(Span<byte> dst, ReadOnlySpan<byte> top, int topOffset)
{
byte a = top[topOffset + 0];
byte b = top[topOffset + 1];
@ -1011,7 +1011,7 @@ internal static unsafe class Vp8Encoding
LossyUtils.Dst(dst, 3, 3, LossyUtils.Avg3(f, g, h));
}
private static void Hd4(Span<byte> dst, Span<byte> top, int topOffset)
private static void Hd4(Span<byte> dst, ReadOnlySpan<byte> top, int topOffset)
{
byte x = top[topOffset - 1];
byte i = top[topOffset - 2];
@ -1046,7 +1046,7 @@ internal static unsafe class Vp8Encoding
LossyUtils.Dst(dst, 1, 3, LossyUtils.Avg3(l, k, j));
}
private static void Hu4(Span<byte> dst, Span<byte> top, int topOffset)
private static void Hu4(Span<byte> dst, ReadOnlySpan<byte> top, int topOffset)
{
byte i = top[topOffset - 2];
byte j = top[topOffset - 3];
@ -1088,7 +1088,7 @@ internal static unsafe class Vp8Encoding
private static byte Clip8b(int v) => (v & ~0xff) == 0 ? (byte)v : v < 0 ? (byte)0 : (byte)255;
[MethodImpl(InliningOptions.ShortMethod)]
private static void Store(Span<byte> dst, Span<byte> reference, int x, int y, int v) => dst[x + (y * WebpConstants.Bps)] = LossyUtils.Clip8B(reference[x + (y * WebpConstants.Bps)] + (v >> 3));
private static void Store(Span<byte> dst, ReadOnlySpan<byte> reference, int x, int y, int v) => dst[x + (y * WebpConstants.Bps)] = LossyUtils.Clip8B(reference[x + (y * WebpConstants.Bps)] + (v >> 3));
[MethodImpl(InliningOptions.ShortMethod)]
private static int Mul(int a, int b) => (a * b) >> 16;

2
src/ImageSharp/Formats/Webp/Lossy/Vp8Residual.cs

@ -235,7 +235,7 @@ internal class Vp8Residual
}
[MethodImpl(InliningOptions.ShortMethod)]
private static int LevelCost(Span<ushort> table, int level)
private static int LevelCost(ReadOnlySpan<ushort> table, int level)
=> WebpLookupTables.Vp8LevelFixedCosts[level] + table[level > WebpConstants.MaxVariableLevel ? WebpConstants.MaxVariableLevel : level];
private static int RecordStats(int bit, Vp8StatsArray statsArr, int idx)

2
src/ImageSharp/Formats/Webp/Lossy/Vp8SegmentInfo.cs

@ -67,7 +67,7 @@ internal class Vp8SegmentInfo
public int LambdaMode { get; set; }
public void StoreMaxDelta(Span<short> dcs)
public void StoreMaxDelta(ReadOnlySpan<short> dcs)
{
// We look at the first three AC coefficients to determine what is the average
// delta between each sub-4x4 block.

10
src/ImageSharp/Formats/Webp/Lossy/YuvConversion.cs

@ -39,7 +39,7 @@ internal static class YuvConversion
}
}
private static void UpSampleScalar(Span<byte> topY, Span<byte> bottomY, Span<byte> topU, Span<byte> topV, Span<byte> curU, Span<byte> curV, Span<byte> topDst, Span<byte> bottomDst, int len)
private static void UpSampleScalar(ReadOnlySpan<byte> topY, ReadOnlySpan<byte> bottomY, ReadOnlySpan<byte> topU, ReadOnlySpan<byte> topV, ReadOnlySpan<byte> curU, ReadOnlySpan<byte> curV, Span<byte> topDst, Span<byte> bottomDst, int len)
{
const int xStep = 3;
int lastPixelPair = (len - 1) >> 1;
@ -346,7 +346,7 @@ internal static class YuvConversion
/// <param name="y">The destination span for y.</param>
/// <param name="width">The width.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public static void ConvertRgbaToY(Span<Bgra32> rowSpan, Span<byte> y, int width)
public static void ConvertRgbaToY(ReadOnlySpan<Bgra32> rowSpan, Span<byte> y, int width)
{
for (int x = 0; x < width; x++)
{
@ -361,7 +361,7 @@ internal static class YuvConversion
/// <param name="u">The destination span for u.</param>
/// <param name="v">The destination span for v.</param>
/// <param name="width">The width.</param>
public static void ConvertRgbaToUv(Span<ushort> rgb, Span<byte> u, Span<byte> v, int width)
public static void ConvertRgbaToUv(ReadOnlySpan<ushort> rgb, Span<byte> u, Span<byte> v, int width)
{
int rgbIdx = 0;
for (int i = 0; i < width; i += 1, rgbIdx += 4)
@ -372,7 +372,7 @@ internal static class YuvConversion
}
}
public static void AccumulateRgb(Span<Bgra32> rowSpan, Span<Bgra32> nextRowSpan, Span<ushort> dst, int width)
public static void AccumulateRgb(ReadOnlySpan<Bgra32> rowSpan, ReadOnlySpan<Bgra32> nextRowSpan, Span<ushort> dst, int width)
{
Bgra32 bgra0;
Bgra32 bgra1;
@ -416,7 +416,7 @@ internal static class YuvConversion
}
}
public static void AccumulateRgba(Span<Bgra32> rowSpan, Span<Bgra32> nextRowSpan, Span<ushort> dst, int width)
public static void AccumulateRgba(ReadOnlySpan<Bgra32> rowSpan, ReadOnlySpan<Bgra32> nextRowSpan, Span<ushort> dst, int width)
{
Bgra32 bgra0;
Bgra32 bgra1;

4
src/ImageSharp/ImageSharp.csproj

@ -30,12 +30,12 @@
<Choose>
<When Condition="$(SIXLABORS_TESTING_PREVIEW) == true">
<PropertyGroup>
<TargetFrameworks>net8.0;net10.0</TargetFrameworks>
<TargetFrameworks>net10.0;net11.0</TargetFrameworks>
</PropertyGroup>
</When>
<Otherwise>
<PropertyGroup>
<TargetFrameworks>net8.0</TargetFrameworks>
<TargetFrameworks>net10.0</TargetFrameworks>
</PropertyGroup>
</Otherwise>
</Choose>

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

@ -412,7 +412,7 @@ public partial class PixelOperations<TPixel>
}
[MethodImpl(InliningOptions.ShortMethod)]
internal static void GuardUnpackIntoRgbPlanes(Span<float> redChannel, Span<float> greenChannel, Span<float> blueChannel, ReadOnlySpan<TPixel> source)
internal static void GuardUnpackIntoRgbPlanes(ReadOnlySpan<float> redChannel, Span<float> greenChannel, Span<float> blueChannel, ReadOnlySpan<TPixel> source)
{
Guard.IsTrue(greenChannel.Length == redChannel.Length, nameof(greenChannel), "Channels must be of same size!");
Guard.IsTrue(blueChannel.Length == redChannel.Length, nameof(blueChannel), "Channels must be of same size!");

2
tests/Directory.Build.targets

@ -23,7 +23,7 @@
Magick.NET 14.15.0 disables WebP-compressed TIFF support on Windows.
https://github.com/ImageMagick/tiff/commit/978181b6c999ee013f1b6df0a010d8c550d378cf
-->
<PackageReference Update="Magick.NET-Q16-AnyCPU" Version="14.14.0" />
<PackageReference Update="Magick.NET-Q16-AnyCPU" Version="14.16.0" />
<PackageReference Update="Microsoft.DotNet.RemoteExecutor" Version="10.0.0-beta.25563.105" />
<PackageReference Update="Moq" Version="4.20.72" />
<PackageReference Update="NetVips" Version="3.0.0" />

4
tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj

@ -39,12 +39,12 @@
<Choose>
<When Condition="$(SIXLABORS_TESTING_PREVIEW) == true">
<PropertyGroup>
<TargetFrameworks>net8.0;net10.0</TargetFrameworks>
<TargetFrameworks>net10.0;net11.0</TargetFrameworks>
</PropertyGroup>
</When>
<Otherwise>
<PropertyGroup>
<TargetFrameworks>net8.0</TargetFrameworks>
<TargetFrameworks>net10.0</TargetFrameworks>
</PropertyGroup>
</Otherwise>
</Choose>

4
tests/ImageSharp.PublicApi.Tests/ImageSharp.PublicApi.Tests.csproj

@ -10,12 +10,12 @@
<Choose>
<When Condition="$(SIXLABORS_TESTING_PREVIEW) == true">
<PropertyGroup>
<TargetFrameworks>net8.0;net10.0</TargetFrameworks>
<TargetFrameworks>net10.0;net11.0</TargetFrameworks>
</PropertyGroup>
</When>
<Otherwise>
<PropertyGroup>
<TargetFrameworks>net8.0</TargetFrameworks>
<TargetFrameworks>net10.0</TargetFrameworks>
</PropertyGroup>
</Otherwise>
</Choose>

4
tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj

@ -18,12 +18,12 @@
<Choose>
<When Condition="$(SIXLABORS_TESTING_PREVIEW) == true">
<PropertyGroup>
<TargetFrameworks>net8.0;net10.0</TargetFrameworks>
<TargetFrameworks>net10.0;net11.0</TargetFrameworks>
</PropertyGroup>
</When>
<Otherwise>
<PropertyGroup>
<TargetFrameworks>net8.0</TargetFrameworks>
<TargetFrameworks>net10.0</TargetFrameworks>
</PropertyGroup>
</Otherwise>
</Choose>

10
tests/ImageSharp.Tests/IO/LocalFileSystemTests.cs

@ -50,7 +50,12 @@ public class LocalFileSystemTests
await using (FileStream stream = (FileStream)fs.OpenReadAsynchronous(path))
using (StreamReader reader = new(stream))
{
// .NET 11 reports IsAsync false for regular files on Unix: https://github.com/dotnet/runtime/pull/125220
#if NET11_0_OR_GREATER
Assert.Equal(OperatingSystem.IsWindows(), stream.IsAsync);
#else
Assert.True(stream.IsAsync);
#endif
Assert.True(stream.CanRead);
Assert.False(stream.CanWrite);
@ -105,7 +110,12 @@ public class LocalFileSystemTests
await using (FileStream stream = (FileStream)fs.CreateAsynchronous(path))
await using (StreamWriter writer = new(stream))
{
// .NET 11 reports IsAsync false for regular files on Unix: https://github.com/dotnet/runtime/pull/125220
#if NET11_0_OR_GREATER
Assert.Equal(OperatingSystem.IsWindows(), stream.IsAsync);
#else
Assert.True(stream.IsAsync);
#endif
Assert.True(stream.CanRead);
Assert.True(stream.CanWrite);

4
tests/ImageSharp.Tests/ImageSharp.Tests.csproj

@ -12,12 +12,12 @@
<Choose>
<When Condition="$(SIXLABORS_TESTING_PREVIEW) == true">
<PropertyGroup>
<TargetFrameworks>net8.0;net10.0</TargetFrameworks>
<TargetFrameworks>net10.0;net11.0</TargetFrameworks>
</PropertyGroup>
</When>
<Otherwise>
<PropertyGroup>
<TargetFrameworks>net8.0</TargetFrameworks>
<TargetFrameworks>net10.0</TargetFrameworks>
</PropertyGroup>
</Otherwise>
</Choose>

7
tests/ImageSharp.Tests/TestUtilities/FeatureTesting/FeatureTestRunner.cs

@ -414,7 +414,14 @@ public static class FeatureTestRunner
// Not a COMPlus value. We filter in calling method.
features.Add(key, nameof(HwIntrinsics.AllowAll));
break;
#if NET11_0_OR_GREATER
case nameof(HwIntrinsics.DisableSSE42):
// SSE3 through SSE4.2 and POPCNT are x86-64-v2 baseline in .NET 11+ and the
// switch is inert, so skip it entirely rather than spawn a child that tests nothing.
// https://learn.microsoft.com/en-us/dotnet/core/compatibility/jit/11/minimum-hardware-requirements
break;
#endif
default:
features.Add(key, intrinsic.Replace("Disable", "Enable"));
break;

28
tests/ImageSharp.Tests/TestUtilities/Tests/FeatureTestRunnerTests.cs

@ -11,20 +11,25 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.Tests;
public class FeatureTestRunnerTests
{
public static TheoryData<HwIntrinsics, string[]> Intrinsics =>
public static TheoryData<HwIntrinsics, HwIntrinsics, string[]> Intrinsics =>
new()
{
{ HwIntrinsics.DisableAES | HwIntrinsics.AllowAll, ["EnableAES", "AllowAll"] },
{ HwIntrinsics.DisableHWIntrinsic, ["EnableHWIntrinsic"] },
{ HwIntrinsics.DisableSSE42 | HwIntrinsics.DisableAVX, ["EnableSSE42", "EnableAVX"] }
{ HwIntrinsics.DisableAES | HwIntrinsics.AllowAll, HwIntrinsics.DisableAES | HwIntrinsics.AllowAll, ["EnableAES", "AllowAll"] },
{ HwIntrinsics.DisableHWIntrinsic, HwIntrinsics.DisableHWIntrinsic, ["EnableHWIntrinsic"] },
#if NET11_0_OR_GREATER
// ToFeatureKeyValueCollection filters DisableSSE42: SSE4.2 is x86-64-v2 baseline in .NET 11+ and cannot be disabled.
{ HwIntrinsics.DisableSSE42 | HwIntrinsics.DisableAVX, HwIntrinsics.DisableAVX, ["EnableAVX"] }
#else
{ HwIntrinsics.DisableSSE42 | HwIntrinsics.DisableAVX, HwIntrinsics.DisableSSE42 | HwIntrinsics.DisableAVX, ["EnableSSE42", "EnableAVX"] }
#endif
};
[Theory]
[MemberData(nameof(Intrinsics))]
public void ToFeatureCollectionReturnsExpectedResult(HwIntrinsics expectedIntrinsics, string[] expectedValues)
public void ToFeatureCollectionReturnsExpectedResult(HwIntrinsics intrinsics, HwIntrinsics expectedIntrinsics, string[] expectedValues)
{
Dictionary<HwIntrinsics, string> features = expectedIntrinsics.ToFeatureKeyValueCollection();
HwIntrinsics[] keys = features.Keys.ToArray();
Dictionary<HwIntrinsics, string> features = intrinsics.ToFeatureKeyValueCollection();
HwIntrinsics[] keys = [.. features.Keys];
HwIntrinsics actualIntrinsics = keys[0];
for (int i = 1; i < keys.Length; i++)
@ -122,9 +127,8 @@ public class FeatureTestRunnerTests
Assert.False(Ssse3.IsSupported, "Ssse3 should be disabled.");
Assert.False(Sse41.IsSupported, "Sse41 should be disabled.");
Assert.False(Popcnt.IsSupported, "Popcnt should be disabled.");
#else
Assert.False(Sse42.IsSupported, "Sse42 should be disabled when DisableSSE42 is set.");
#endif
Assert.False(Sse42.IsSupported, "Sse42 should be disabled when DisableSSE42 is set.");
break;
case HwIntrinsics.DisableAVX:
Assert.False(Avx.IsSupported, "AVX should be disabled when DisableAVX is set.");
@ -169,12 +173,12 @@ public class FeatureTestRunnerTests
{
Assert.NotNull(serializable);
Assert.NotNull(FeatureTestRunner.DeserializeForXunit<FakeSerializable>(serializable));
Assert.False(Sse42.IsSupported, "SSE42 should be disabled when DisableSSE42 is set (sanity check using serializable param overload).");
Assert.False(Avx.IsSupported, "AVX should be disabled when DisableAVX is set (sanity check using serializable param overload).");
}
FeatureTestRunner.RunWithHwIntrinsicsFeature(
AssertHwIntrinsicsFeatureDisabled,
HwIntrinsics.DisableSSE42,
HwIntrinsics.DisableAVX,
new FakeSerializable());
}
@ -256,7 +260,7 @@ public class FeatureTestRunnerTests
}
}
foreach (HwIntrinsics intrinsic in (HwIntrinsics[])Enum.GetValues(typeof(HwIntrinsics)))
foreach (HwIntrinsics intrinsic in Enum.GetValues<HwIntrinsics>())
{
FeatureTestRunner.RunWithHwIntrinsicsFeature(AssertHwIntrinsicsFeatureDisabled, intrinsic, new FakeSerializable());
}

Loading…
Cancel
Save