System.DllNotFoundException: Unable to load shared library 'gdiplus.dll' or one of its
dependencies. ..., wrapped in The type initializer for 'Windows.Win32.PInvoke' threw
an exception, is what new Bitmap(10, 10) from System.Drawing.Common
9.0.0 gave on the Linux runtime:10.0 image. The tested way out was to draw
with SkiaSharp instead.
The expected message, System.Drawing.Common is not supported on this
platform, did not appear in this test. The failure was a missing Windows library
instead, and the post is about that output.
The error
PS> docker run --rm --name fix10-dn-d1 fix10-dn-lab drawing
Unhandled exception. System.TypeInitializationException: The type initializer for 'Windows.Win32.PInvoke' threw an exception.
---> System.TypeInitializationException: The type initializer for 'System.Drawing.Gdip' threw an exception.
---> System.TypeInitializationException: The type initializer for 'Windows.Win32.Graphics.GdiPlus.GdiPlusInitialization' threw an exception.
---> System.DllNotFoundException: Unable to load shared library 'gdiplus.dll' or one of its dependencies. In order to help diagnose loading problems, consider using a tool like strace. If you're using glibc, consider setting the LD_DEBUG environment variable:
/usr/share/dotnet/shared/Microsoft.NETCore.App/10.0.13/gdiplus.dll.so: cannot open shared object file: No such file or directory
/usr/share/dotnet/shared/Microsoft.NETCore.App/10.0.13/libgdiplus.dll.so: cannot open shared object file: No such file or directory
/usr/share/dotnet/shared/Microsoft.NETCore.App/10.0.13/gdiplus.dll: cannot open shared object file: No such file or directory
/usr/share/dotnet/shared/Microsoft.NETCore.App/10.0.13/libgdiplus.dll: cannot open shared object file: No such file or directory
...
at System.Drawing.Bitmap..ctor(Int32 width, Int32 height)
at Program.<Main>$(String[] args) in /src/Program.cs:line 22
Why it happens
The innermost exception is the cause: the Bitmap constructor went through
System.Drawing.Gdip, which tried to load gdiplus.dll, and the
runtime looked for it under four names in the runtime folder and found none: the Linux image has no file under any of those names. The outer
TypeInitializationException layers are the static constructors that failed
on the way, which is why the top line names Windows.Win32.PInvoke rather than
anything you wrote.
The project compiled with the CA1416 platform warning switched off in the project file
(<NoWarn>CA1416</NoWarn>). A full build without
-q printed only NU1902 and NU1903 warnings for
System.Security.Cryptography.Pkcs 9.0.4 and no warning that named
System.Drawing; the image built and the crash came at the first Bitmap.
The fix
No change to the image was tested for System.Drawing.Common. What was tested is replacing
the call with SkiaSharp 3.119.0 plus its Linux native assets, on the same
runtime:10.0 base:
using var bmp = new SkiaSharp.SKBitmap(10, 10);
Console.WriteLine($"SKBitmap {bmp.Width}x{bmp.Height}");
RUN dotnet add package SkiaSharp.NativeAssets.Linux.NoDependencies --version 3.119.0
PS> docker run --rm --name fix10-dn-s2 fix10-dn-lab-skiafix skia
SKBitmap 10x10
This is a code change, not a package swap: SKBitmap is a different type
from Bitmap, so every drawing call has to be rewritten against the SkiaSharp
API. Only the 10 by 10 bitmap above was tested. The native assets package is not
optional: without it SkiaSharp fails on Linux with its
own DllNotFoundException, covered in the post linked below.
How it was reproduced
A console app referencing System.Drawing.Common 9.0.0, built on
mcr.microsoft.com/dotnet/sdk:10.0 (SDK 10.0.302) and run on
mcr.microsoft.com/dotnet/runtime:10.0 (Microsoft.NETCore.App 10.0.13), whose
drawing mode creates a 10 by 10 Bitmap. Docker engine 29.9.3 on
Windows 11. No other System.Drawing.Common version was tried.
Frequently asked
- Does System.Drawing.Common work in a Linux Docker container?
- Not in this test. System.Drawing.Common 9.0.0 on runtime:10.0 failed at new Bitmap(10, 10) with DllNotFoundException for gdiplus.dll inside several TypeInitializationException layers.
- What can I use instead of System.Drawing in a .NET Linux container?
- SkiaSharp worked in the test: SkiaSharp 3.119.0 with SkiaSharp.NativeAssets.Linux.NoDependencies 3.119.0 created an SKBitmap on runtime:10.0.
- Why does the error mention Windows.Win32.PInvoke?
- That is the outermost static constructor that failed. The real cause is the innermost exception, which says gdiplus.dll could not be loaded.
The SkiaSharp side: Unable to load shared library 'libSkiaSharp'. More decoded errors in the Fixes category.