diff --git a/src/ImageSharp/Advanced/AotCompilerTools.cs b/src/ImageSharp/Advanced/AotCompilerTools.cs
new file mode 100644
index 0000000000..9e7624480d
--- /dev/null
+++ b/src/ImageSharp/Advanced/AotCompilerTools.cs
@@ -0,0 +1,103 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+using SixLabors.ImageSharp.PixelFormats;
+using SixLabors.ImageSharp.Processing.Processors.Dithering;
+using SixLabors.ImageSharp.Processing.Processors.Quantization;
+
+namespace SixLabors.ImageSharp.Advanced
+{
+ ///
+ /// Unlike traditional Mono/.NET, code on the iPhone is statically compiled ahead of time instead of being
+ /// compiled on demand by a JIT compiler. This means there are a few limitations with respect to generics,
+ /// these are caused because not every possible generic instantiation can be determined up front at compile time.
+ /// The Aot Compiler is designed to overcome the limitations of this compiler.
+ ///
+ public static class AotCompilerTools
+ {
+ ///
+ /// Seeds the compiler using the given pixel format.
+ ///
+ /// The pixel format.
+ public static void Seed()
+ where TPixel : struct, IPixel
+ {
+ // This is we actually call all the individual methods you need to seed.
+ AotCompileOctreeQuantizer();
+ AotCompileWuQuantizer();
+ AotCompileDithering();
+
+ // TODO: Do the discovery work to figure out what works and what doesn't.
+ }
+
+ ///
+ /// Seeds the compiler using the given pixel formats.
+ ///
+ /// The first pixel format.
+ /// The second pixel format.
+ public static void Seed()
+ where TPixel : struct, IPixel
+ where TPixel2 : struct, IPixel
+ {
+ Seed();
+ Seed();
+ }
+
+ ///
+ /// Seeds the compiler using the given pixel formats.
+ ///
+ /// The first pixel format.
+ /// The second pixel format.
+ /// The third pixel format.
+ public static void Seed()
+ where TPixel : struct, IPixel
+ where TPixel2 : struct, IPixel
+ where TPixel3 : struct, IPixel
+ {
+ Seed();
+ Seed();
+ }
+
+ ///
+ /// This method doesn't actually do anything but serves an important purpose...
+ /// If you are running ImageSharp on iOS and try to call SaveAsGif, it will throw an excepion:
+ /// "Attempting to JIT compile method... OctreeFrameQuantizer.ConstructPalette... while running in aot-only mode."
+ /// The reason this happens is the SaveAsGif method makes haevy use of generics, which are too confusing for the AoT
+ /// compiler used on Xamarin.iOS. It spins up the JIT compiler to try and figure it out, but that is an illegal op on
+ /// iOS so it bombs out.
+ /// If you are getting the above error, you need to call this method, which will pre-seed the AoT compiler with the
+ /// necessary methods to complete the SaveAsGif call. That's it, otherwise you should NEVER need this method!!!
+ ///
+ /// The pixel format.
+ private static void AotCompileOctreeQuantizer()
+ where TPixel : struct, IPixel
+ {
+ var test = new OctreeFrameQuantizer(new OctreeQuantizer(false));
+ test.AotGetPalette();
+ }
+
+ ///
+ /// This method pre-seeds the WuQuantizer in the AoT compiler for iOS.
+ ///
+ /// The pixel format.
+ private static void AotCompileWuQuantizer()
+ where TPixel : struct, IPixel
+ {
+ var test = new WuFrameQuantizer(new WuQuantizer(false));
+ test.QuantizeFrame(new ImageFrame(Configuration.Default, 1, 1));
+ test.AotGetPalette();
+ }
+
+ ///
+ /// This method pre-seeds the default dithering engine (FloydSteinbergDiffuser) in the AoT compiler for iOS.
+ ///
+ /// The pixel format.
+ private static void AotCompileDithering()
+ where TPixel : struct, IPixel
+ {
+ var test = new FloydSteinbergDiffuser();
+ TPixel pixel = default;
+ test.Dither(new ImageFrame(Configuration.Default, 1, 1), pixel, pixel, 0, 0, 0, 0, 0, 0);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs
index 1eeb0be410..dd56375f63 100644
--- a/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs
@@ -136,6 +136,8 @@ protected override void SecondPass(
}
}
+ internal TPixel[] AotGetPalette() => this.GetPalette();
+
///
protected override TPixel[] GetPalette() => this.octree.Palletize(this.colors);
diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs
index 43d22597df..44df226cfd 100644
--- a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs
@@ -173,6 +173,8 @@ public override QuantizedFrame QuantizeFrame(ImageFrame image)
}
}
+ internal TPixel[] AotGetPalette() => this.GetPalette();
+
///
protected override TPixel[] GetPalette()
{
diff --git a/tests/ImageSharp.Tests/Advanced/AotCompilerTests.cs b/tests/ImageSharp.Tests/Advanced/AotCompilerTests.cs
new file mode 100644
index 0000000000..5c1dd4bb08
--- /dev/null
+++ b/tests/ImageSharp.Tests/Advanced/AotCompilerTests.cs
@@ -0,0 +1,18 @@
+// Copyright (c) Six Labors and contributors.
+// Licensed under the Apache License, Version 2.0.
+
+using SixLabors.ImageSharp.Advanced;
+using SixLabors.ImageSharp.PixelFormats;
+using Xunit;
+
+namespace SixLabors.ImageSharp.Tests.Advanced
+{
+ public class AotCompilerTests
+ {
+ [Fact]
+ public void AotCompiler_NoExceptions()
+ {
+ AotCompilerTools.Seed();
+ }
+ }
+}