From 7e1b5a63d9eb4a33fe839a2beae998aa8b1ab81c Mon Sep 17 00:00:00 2001 From: Stefan Nikolei Date: Sun, 16 Nov 2025 09:11:25 +0100 Subject: [PATCH 1/6] Add ARM hosted runners Added macos-26 and ubuntu-2204 github runners which run on arm --- .github/workflows/build-and-test.yml | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index e00757cb7b..ab4a931f36 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -77,13 +77,19 @@ jobs: sdk-preview: true runtime: -x64 codecov: false + - os: macos-26 + framework: net9.0 + sdk: 9.0.x + sdk-preview: true + runtime: -x64 + codecov: false - os: windows-latest framework: net9.0 sdk: 9.0.x sdk-preview: true runtime: -x64 codecov: false - - os: buildjet-4vcpu-ubuntu-2204-arm + - os: ubuntu-22.04-arm framework: net9.0 sdk: 9.0.x sdk-preview: true @@ -100,12 +106,17 @@ jobs: sdk: 8.0.x runtime: -x64 codecov: false + - os: macos-26 + framework: net8.0 + sdk: 8.0.x + runtime: -x64 + codecov: false - os: windows-latest framework: net8.0 sdk: 8.0.x runtime: -x64 codecov: false - - os: buildjet-4vcpu-ubuntu-2204-arm + - os: ubuntu-22.04-arm framework: net8.0 sdk: 8.0.x runtime: -x64 From 16f0840a2963066fcdc4ecde4a796d2cb3e0254d Mon Sep 17 00:00:00 2001 From: Stefan Nikolei Date: Sun, 16 Nov 2025 09:19:54 +0100 Subject: [PATCH 2/6] Use Tolerant ImageComparer We now use the tolerant Image Comparer for now. --- tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs index 26dc4f5878..5df730cb1d 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs @@ -360,7 +360,7 @@ public void TiffDecoder_CanDecode_YccK(TestImageProvider provide { using Image image = provider.GetImage(TiffDecoder.Instance); image.DebugSave(provider); - image.CompareToReferenceOutput(ImageComparer.Exact, provider); + image.CompareToReferenceOutput(ImageComparer.Tolerant(), provider); } [Theory] From e64ed4da7d1a6a24e53531c4c5fb216915af1e46 Mon Sep 17 00:00:00 2001 From: Stefan Nikolei Date: Sun, 16 Nov 2025 09:27:25 +0100 Subject: [PATCH 3/6] Disable Tests which need libgdiplus This disables all tests which need libgdiplus for macs with arm. The hosted runners do not have libgdiplus installed --- .../Formats/Bmp/BmpDecoderTests.cs | 10 +++++++ .../TestUtilities/TestEnvironment.cs | 2 ++ .../Tests/MagickReferenceCodecTests.cs | 10 +++++++ .../Tests/SystemDrawingReferenceCodecTests.cs | 27 ++++++++++++++++++- 4 files changed, 48 insertions(+), 1 deletion(-) diff --git a/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs index 94cfe85ee5..d2cc78c153 100644 --- a/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs @@ -111,6 +111,11 @@ public void BmpDecoder_CanDecode_Inverted(TestImageProvider prov public void BmpDecoder_CanDecode_1Bit(TestImageProvider provider) where TPixel : unmanaged, IPixel { + if (TestEnvironment.IsMacOS && TestEnvironment.IsArm64Process) + { + return; + } + using Image image = provider.GetImage(BmpDecoder.Instance); image.DebugSave(provider); image.CompareToOriginal(provider, new SystemDrawingReferenceDecoder(BmpFormat.Instance)); @@ -144,6 +149,11 @@ public void BmpDecoder_CanDecode_4Bit(TestImageProvider provider public void BmpDecoder_CanDecode_8Bit(TestImageProvider provider) where TPixel : unmanaged, IPixel { + if (TestEnvironment.IsMacOS && TestEnvironment.IsArm64Process) + { + return; + } + using Image image = provider.GetImage(BmpDecoder.Instance); image.DebugSave(provider); image.CompareToOriginal(provider); diff --git a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.cs b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.cs index 5eb5be0d9a..062defe461 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.cs @@ -114,6 +114,8 @@ internal static string GetReferenceOutputFileName(string actualOutputFileName) = internal static bool Is64BitProcess => IntPtr.Size == 8; + internal static bool IsArm64Process => RuntimeInformation.ProcessArchitecture == Architecture.Arm64; + internal static bool IsFramework => NetCoreVersion == null; internal static Architecture OSArchitecture => RuntimeInformation.OSArchitecture; diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/MagickReferenceCodecTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/MagickReferenceCodecTests.cs index b818e80b05..34c8cb022b 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/MagickReferenceCodecTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/MagickReferenceCodecTests.cs @@ -29,6 +29,11 @@ public class MagickReferenceCodecTests public void MagickDecode_8BitDepthImage_IsEquivalentTo_SystemDrawingResult(TestImageProvider dummyProvider, string testImage) where TPixel : unmanaged, IPixel { + if (TestEnvironment.IsMacOS && TestEnvironment.IsArm64Process) + { + return; + } + string path = TestFile.GetInputFileFullPath(testImage); MagickReferenceDecoder magickDecoder = MagickReferenceDecoder.Png; @@ -61,6 +66,11 @@ public void MagickDecode_8BitDepthImage_IsEquivalentTo_SystemDrawingResult(TestImageProvider dummyProvider, string testImage) where TPixel : unmanaged, IPixel { + if (TestEnvironment.IsMacOS && TestEnvironment.IsArm64Process) + { + return; + } + string path = TestFile.GetInputFileFullPath(testImage); MagickReferenceDecoder magickDecoder = MagickReferenceDecoder.Png; diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/SystemDrawingReferenceCodecTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/SystemDrawingReferenceCodecTests.cs index 555041890a..ab57e559e6 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/SystemDrawingReferenceCodecTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/SystemDrawingReferenceCodecTests.cs @@ -23,6 +23,11 @@ public class SystemDrawingReferenceCodecTests public void To32bppArgbSystemDrawingBitmap(TestImageProvider provider) where TPixel : unmanaged, IPixel { + if (TestEnvironment.IsMacOS && TestEnvironment.IsArm64Process) + { + return; + } + using Image image = provider.GetImage(); using System.Drawing.Bitmap sdBitmap = SystemDrawingBridge.To32bppArgbSystemDrawingBitmap(image); string fileName = provider.Utility.GetTestOutputFileName("png"); @@ -34,6 +39,11 @@ public void To32bppArgbSystemDrawingBitmap(TestImageProvider pro public void From32bppArgbSystemDrawingBitmap(TestImageProvider dummyProvider) where TPixel : unmanaged, IPixel { + if (TestEnvironment.IsMacOS && TestEnvironment.IsArm64Process) + { + return; + } + string path = TestFile.GetInputFileFullPath(TestImages.Png.Splash); using Bitmap sdBitmap = new(path); @@ -59,7 +69,7 @@ private static string SavePng(TestImageProvider provider, PngCol public void From32bppArgbSystemDrawingBitmap2(TestImageProvider provider) where TPixel : unmanaged, IPixel { - if (TestEnvironment.IsLinux) + if (TestEnvironment.IsLinux || (TestEnvironment.IsArm64Process && TestEnvironment.IsMacOS)) { return; } @@ -78,6 +88,11 @@ public void From32bppArgbSystemDrawingBitmap2(TestImageProvider public void From24bppRgbSystemDrawingBitmap(TestImageProvider provider) where TPixel : unmanaged, IPixel { + if (TestEnvironment.IsMacOS && TestEnvironment.IsArm64Process) + { + return; + } + string path = SavePng(provider, PngColorType.Rgb); using Image original = provider.GetImage(); @@ -92,6 +107,11 @@ public void From24bppRgbSystemDrawingBitmap(TestImageProvider pr public void OpenWithReferenceDecoder(TestImageProvider dummyProvider) where TPixel : unmanaged, IPixel { + if (TestEnvironment.IsMacOS && TestEnvironment.IsArm64Process) + { + return; + } + string path = TestFile.GetInputFileFullPath(TestImages.Png.Splash); using FileStream stream = File.OpenRead(path); using Image image = SystemDrawingReferenceDecoder.Png.Decode(DecoderOptions.Default, stream); @@ -103,6 +123,11 @@ public void OpenWithReferenceDecoder(TestImageProvider dummyProv public void SaveWithReferenceEncoder(TestImageProvider provider) where TPixel : unmanaged, IPixel { + if (TestEnvironment.IsMacOS && TestEnvironment.IsArm64Process) + { + return; + } + using Image image = provider.GetImage(); provider.Utility.SaveTestOutputFile(image, "png", SystemDrawingReferenceEncoder.Png); } From 0c0046985038728d8a9bdbde0534f66c660d1603 Mon Sep 17 00:00:00 2001 From: Stefan Nikolei Date: Mon, 17 Nov 2025 07:24:26 +0100 Subject: [PATCH 4/6] Install libgdiplus on mac --- .github/workflows/build-and-test.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index ab4a931f36..5e97374e3a 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -135,6 +135,11 @@ jobs: sudo apt-get update sudo apt-get -y install libgdiplus libgif-dev libglib2.0-dev libcairo2-dev libtiff-dev libexif-dev + - name: Install libgdi+, which is required for tests running on macos + if: ${{ contains(matrix.options.os, 'macos-26') }} + run: | + brew install mono-libgdiplus + - name: Git Config shell: bash run: | From 66a5ba7d28d221f8da28ceb7227771e2f0a9e789 Mon Sep 17 00:00:00 2001 From: Stefan Nikolei Date: Mon, 17 Nov 2025 07:34:21 +0100 Subject: [PATCH 5/6] Enable disabled tests on arm --- .github/workflows/build-and-test.yml | 2 +- .../Formats/Bmp/BmpDecoderTests.cs | 10 ------- .../TestUtilities/TestEnvironment.cs | 2 -- .../Tests/MagickReferenceCodecTests.cs | 10 ------- .../Tests/SystemDrawingReferenceCodecTests.cs | 30 ------------------- 5 files changed, 1 insertion(+), 53 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 5e97374e3a..e9ac4f50d8 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -139,7 +139,7 @@ jobs: if: ${{ contains(matrix.options.os, 'macos-26') }} run: | brew install mono-libgdiplus - + - name: Git Config shell: bash run: | diff --git a/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs index d2cc78c153..94cfe85ee5 100644 --- a/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs @@ -111,11 +111,6 @@ public void BmpDecoder_CanDecode_Inverted(TestImageProvider prov public void BmpDecoder_CanDecode_1Bit(TestImageProvider provider) where TPixel : unmanaged, IPixel { - if (TestEnvironment.IsMacOS && TestEnvironment.IsArm64Process) - { - return; - } - using Image image = provider.GetImage(BmpDecoder.Instance); image.DebugSave(provider); image.CompareToOriginal(provider, new SystemDrawingReferenceDecoder(BmpFormat.Instance)); @@ -149,11 +144,6 @@ public void BmpDecoder_CanDecode_4Bit(TestImageProvider provider public void BmpDecoder_CanDecode_8Bit(TestImageProvider provider) where TPixel : unmanaged, IPixel { - if (TestEnvironment.IsMacOS && TestEnvironment.IsArm64Process) - { - return; - } - using Image image = provider.GetImage(BmpDecoder.Instance); image.DebugSave(provider); image.CompareToOriginal(provider); diff --git a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.cs b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.cs index 062defe461..5eb5be0d9a 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.cs @@ -114,8 +114,6 @@ internal static string GetReferenceOutputFileName(string actualOutputFileName) = internal static bool Is64BitProcess => IntPtr.Size == 8; - internal static bool IsArm64Process => RuntimeInformation.ProcessArchitecture == Architecture.Arm64; - internal static bool IsFramework => NetCoreVersion == null; internal static Architecture OSArchitecture => RuntimeInformation.OSArchitecture; diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/MagickReferenceCodecTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/MagickReferenceCodecTests.cs index 34c8cb022b..b818e80b05 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/MagickReferenceCodecTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/MagickReferenceCodecTests.cs @@ -29,11 +29,6 @@ public class MagickReferenceCodecTests public void MagickDecode_8BitDepthImage_IsEquivalentTo_SystemDrawingResult(TestImageProvider dummyProvider, string testImage) where TPixel : unmanaged, IPixel { - if (TestEnvironment.IsMacOS && TestEnvironment.IsArm64Process) - { - return; - } - string path = TestFile.GetInputFileFullPath(testImage); MagickReferenceDecoder magickDecoder = MagickReferenceDecoder.Png; @@ -66,11 +61,6 @@ public void MagickDecode_8BitDepthImage_IsEquivalentTo_SystemDrawingResult(TestImageProvider dummyProvider, string testImage) where TPixel : unmanaged, IPixel { - if (TestEnvironment.IsMacOS && TestEnvironment.IsArm64Process) - { - return; - } - string path = TestFile.GetInputFileFullPath(testImage); MagickReferenceDecoder magickDecoder = MagickReferenceDecoder.Png; diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/SystemDrawingReferenceCodecTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/SystemDrawingReferenceCodecTests.cs index ab57e559e6..40540ec6c7 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/SystemDrawingReferenceCodecTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/SystemDrawingReferenceCodecTests.cs @@ -23,11 +23,6 @@ public class SystemDrawingReferenceCodecTests public void To32bppArgbSystemDrawingBitmap(TestImageProvider provider) where TPixel : unmanaged, IPixel { - if (TestEnvironment.IsMacOS && TestEnvironment.IsArm64Process) - { - return; - } - using Image image = provider.GetImage(); using System.Drawing.Bitmap sdBitmap = SystemDrawingBridge.To32bppArgbSystemDrawingBitmap(image); string fileName = provider.Utility.GetTestOutputFileName("png"); @@ -39,11 +34,6 @@ public void To32bppArgbSystemDrawingBitmap(TestImageProvider pro public void From32bppArgbSystemDrawingBitmap(TestImageProvider dummyProvider) where TPixel : unmanaged, IPixel { - if (TestEnvironment.IsMacOS && TestEnvironment.IsArm64Process) - { - return; - } - string path = TestFile.GetInputFileFullPath(TestImages.Png.Splash); using Bitmap sdBitmap = new(path); @@ -69,11 +59,6 @@ private static string SavePng(TestImageProvider provider, PngCol public void From32bppArgbSystemDrawingBitmap2(TestImageProvider provider) where TPixel : unmanaged, IPixel { - if (TestEnvironment.IsLinux || (TestEnvironment.IsArm64Process && TestEnvironment.IsMacOS)) - { - return; - } - string path = SavePng(provider, PngColorType.RgbWithAlpha); using Bitmap sdBitmap = new(path); @@ -88,11 +73,6 @@ public void From32bppArgbSystemDrawingBitmap2(TestImageProvider public void From24bppRgbSystemDrawingBitmap(TestImageProvider provider) where TPixel : unmanaged, IPixel { - if (TestEnvironment.IsMacOS && TestEnvironment.IsArm64Process) - { - return; - } - string path = SavePng(provider, PngColorType.Rgb); using Image original = provider.GetImage(); @@ -107,11 +87,6 @@ public void From24bppRgbSystemDrawingBitmap(TestImageProvider pr public void OpenWithReferenceDecoder(TestImageProvider dummyProvider) where TPixel : unmanaged, IPixel { - if (TestEnvironment.IsMacOS && TestEnvironment.IsArm64Process) - { - return; - } - string path = TestFile.GetInputFileFullPath(TestImages.Png.Splash); using FileStream stream = File.OpenRead(path); using Image image = SystemDrawingReferenceDecoder.Png.Decode(DecoderOptions.Default, stream); @@ -123,11 +98,6 @@ public void OpenWithReferenceDecoder(TestImageProvider dummyProv public void SaveWithReferenceEncoder(TestImageProvider provider) where TPixel : unmanaged, IPixel { - if (TestEnvironment.IsMacOS && TestEnvironment.IsArm64Process) - { - return; - } - using Image image = provider.GetImage(); provider.Utility.SaveTestOutputFile(image, "png", SystemDrawingReferenceEncoder.Png); } From 17ae34def4701abf21a685b52ef5876e9bbe2dd3 Mon Sep 17 00:00:00 2001 From: Stefan Nikolei Date: Mon, 17 Nov 2025 08:01:07 +0100 Subject: [PATCH 6/6] Try to create symlink --- .github/workflows/build-and-test.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index e9ac4f50d8..37b42e1e9f 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -138,7 +138,14 @@ jobs: - name: Install libgdi+, which is required for tests running on macos if: ${{ contains(matrix.options.os, 'macos-26') }} run: | + brew update brew install mono-libgdiplus + # Create symlinks to make libgdiplus discoverable + sudo mkdir -p /usr/local/lib + sudo ln -sf $(brew --prefix)/lib/libgdiplus.dylib /usr/local/lib/libgdiplus.dylib + # Verify installation + ls -la $(brew --prefix)/lib/libgdiplus* || echo "libgdiplus not found in brew prefix" + ls -la /usr/local/lib/libgdiplus* || echo "libgdiplus not found in /usr/local/lib" - name: Git Config shell: bash @@ -209,6 +216,7 @@ jobs: env: SIXLABORS_TESTING: True XUNIT_PATH: .\tests\ImageSharp.Tests # Required for xunit + DYLD_FALLBACK_LIBRARY_PATH: /usr/local/lib:${{ env.DYLD_FALLBACK_LIBRARY_PATH }} - name: DotNet Test Preview if: ${{ matrix.options.sdk-preview == true }} @@ -217,6 +225,7 @@ jobs: env: SIXLABORS_TESTING_PREVIEW: True XUNIT_PATH: .\tests\ImageSharp.Tests # Required for xunit + DYLD_FALLBACK_LIBRARY_PATH: /usr/local/lib:${{ env.DYLD_FALLBACK_LIBRARY_PATH }} - name: Export Failed Output uses: actions/upload-artifact@v4