Search code examples
c#python.netsixlabors.imagesharp

Problem with using C# dll which references SixLabors.ImageSharp, in Python code with Python.NET


I'm having trouble getting PythonNet to work with a C# dll which references SixLabors.ImageSharp (v3.1.3). My bare minimal C# code (.NET 7.0 class library, which is compiled into a dll) is shown below. It contains three test methods, RunTest1, RunTest2, and RunTest3.

using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats;

namespace PythonNetTest
{
    public class TestClass
    {
        public void RunTest1()
        {
            Console.WriteLine("Test PythonNet");
        }

        public Image RunTest2()
        {
            return null;
        }

        public Image RunTest3()
        {
            return new Image<Rgba32>(100, 100);
        }
    }
}

The Python code which I'm using to load and work with this C# dll is below:

import os
import sys
import clr

from System.Reflection import Assembly
from System.IO import File
from System import Activator

clr.AddReference(r'<Path to ImageSharp DLL>\SixLabors.ImageSharp.dll')

path = r'<Path to C# dll>\PythonNetTest.dll'

dll = Assembly.Load(File.ReadAllBytes(path))

obj_type = dll.GetType('PythonNetTest.TestClass')

obj = Activator.CreateInstance(obj_type)

obj.RunTest1()

v2=obj.RunTest2()

v3=obj.RunTest3()

When I run the Python code, RunTest1 correctly prints the string "Test PythonNet", and RunTest2 correctly returns a null object.

RunTest3, however, fails with the following exception in the Python console:


TypeLoadException: Could not load type 'System.Environment' from assembly 'System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.
   at SixLabors.ImageSharp.Configuration..ctor(IImageFormatConfigurationModule[] configurationModules)
   at SixLabors.ImageSharp.Configuration.CreateDefaultInstance()
   at System.Lazy`1.CreateValue()
   at System.Lazy`1.LazyInitValue()
   at SixLabors.ImageSharp.Configuration..cctor()


The above exception was the direct cause of the following exception:

Traceback (most recent call last):

  File ~\miniconda3\lib\site-packages\spyder_kernels\py3compat.py:356 in compat_exec
    exec(code, globals, locals)

  File c:\users\<***>\documents\untitled0.py:31
    v3=obj.RunTest3()

TypeInitializationException: The type initializer for 'SixLabors.ImageSharp.Configuration' threw an exception. ---> System.TypeLoadException: Could not load type 'System.Environment' from assembly 'System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.
   at SixLabors.ImageSharp.Configuration..ctor(IImageFormatConfigurationModule[] configurationModules)
   at SixLabors.ImageSharp.Configuration.CreateDefaultInstance()
   at System.Lazy`1.CreateValue()
   at System.Lazy`1.LazyInitValue()
   at SixLabors.ImageSharp.Configuration..cctor()
   --- End of inner exception stack trace ---
   at SixLabors.ImageSharp.Image`1..ctor(Int32 width, Int32 height)
   at PythonNetTest.TestClass.RunTest3()

What could be the cause of this exception? I'm using the ImageSharp dll, which I downloaded directly. I'm not using the ImageSharp source code to build the ImageSharp dll. However, I did take a look at the ImageSharp source code, and it seems it uses some Environment functions, such as Environment.ProcessorCount and Environment.Newline. I presume these come from System.Runtime.

Any help is appreciated.


Solution

  • I figured it out on my own. I'm posting the answer, in case it helps somebody else.

    I had to modify my Python code as follows:

    from pythonnet import load
    load('coreclr')
    
    import os
    import sys
    import clr
    
    from System.Reflection import Assembly
    from System.IO import File
    from System import Activator
    
    clr.AddReference(r'<Path to ImageSharp DLL>\SixLabors.ImageSharp.dll')
    
    path = r'<Path to C# dll>\PythonNetTest.dll'
    
    dll = Assembly.Load(File.ReadAllBytes(path))
    
    obj_type = dll.GetType('PythonNetTest.TestClass')
    
    obj = Activator.CreateInstance(obj_type)
    
    obj.RunTest1()
    
    v2=obj.RunTest2()
    
    v3=obj.RunTest3()
    

    Basically, explicitly load 'coreclr'. Hope this is of use to others.