System.Drawing.Common only supported on Windows

The System.Drawing.Common NuGet package is now attributed as a Windows-specific library. The platform analyzer emits warning at compile time when compiling for non-Windows operating systems.

On non-Windows operating systems, unless you set a runtime configuration switch, a TypeInitializationException exception is thrown with PlatformNotSupportedException as the inner exception.

Old behavior

Prior to .NET 6, using the System.Drawing.Common package did not produce any compile-time warnings, and no run-time exceptions were thrown.

New behavior

Starting in .NET 6, the platform analyzer emits compile-time warnings when referencing code is compiled for non-Windows operating systems. In addition, the following run-time exception is thrown unless you set a configuration option:

System.TypeInitializationException : The type initializer for 'Gdip' threw an exception.
      ---- System.PlatformNotSupportedException : System.Drawing.Common is not supported on non-Windows platforms. See https://aka.ms/systemdrawingnonwindows for more information.
      Stack Trace:
           at System.Drawing.SafeNativeMethods.Gdip.GdipCreateBitmapFromFile(String filename, IntPtr& bitmap)
        /_/src/libraries/System.Drawing.Common/src/System/Drawing/Bitmap.cs(42,0): at System.Drawing.Bitmap..ctor(String filename, Boolean useIcm)
        /_/src/libraries/System.Drawing.Common/src/System/Drawing/Bitmap.cs(25,0): at System.Drawing.Bitmap..ctor(String filename)
        /_/src/libraries/System.Resources.ResourceManager/tests/ResourceManagerTests.cs(270,0): at System.Resources.Tests.ResourceManagerTests.EnglishImageResourceData()+MoveNext()
        /_/src/libraries/System.Linq/src/System/Linq/Select.cs(136,0): at System.Linq.Enumerable.SelectEnumerableIterator`2.MoveNext()
        ----- Inner Stack Trace -----
        /_/src/libraries/System.Drawing.Common/src/System/Drawing/LibraryResolver.cs(31,0): at System.Drawing.LibraryResolver.EnsureRegistered()
        /_/src/libraries/System.Drawing.Common/src/System/Drawing/GdiplusNative.Unix.cs(65,0): at System.Drawing.SafeNativeMethods.Gdip.PlatformInitialize()
        /_/src/libraries/System.Drawing.Common/src/System/Drawing/Gdiplus.cs(27,0): at System.Drawing.SafeNativeMethods.Gdip..cctor()

Version introduced

.NET 6

Type of breaking change

This change can affect source compatibility and binary compatibility.

Reason for change

Because System.Drawing.Common was designed to be a thin wrapper over Windows technologies, its cross-platform implementation is subpar.

libgdiplus is the main provider of the cross-platform implementation of System.Drawing.Common on the native side. libgdiplus is effectively a reimplementation of the parts of Windows that System.Drawing.Common depends on. That implementation makes libgdiplus a non-trivial component. It's around 30,000 lines of C code that's largely untested, and it lacks a lot of functionality. libgdiplus also has numerous external dependencies for image processing and text rendering, such as cairo, pango, and other native libraries. Those dependencies make maintaining and shipping the component even more challenging. Since the inclusion of the Mono cross-platform implementation, we have redirected numerous issues to libgdiplus that never got fixed. In comparison, other external dependencies we have taken, such as icu or openssl, are high-quality libraries. It's not viable to get libgdiplus to the point where its feature set and quality is on par with the rest of the .NET stack.

From analysis of NuGet packages, we've observed that System.Drawing.Common is used cross-platform mostly for image manipulation, such as QR code generators and text rendering. We haven't noticed heavy graphics usage, as our cross-platform graphics support is incomplete. The usages we see of System.Drawing.Common in non-Windows environments are typically well supported with SkiaSharp and ImageSharp.

System.Drawing.Common will continue to evolve only in the context of Windows Forms and GDI+.

To use these APIs for cross-platform apps, migrate to one of the following libraries:

Alternatively, you can enable support for non-Windows platforms in .NET 6 by setting the System.Drawing.EnableUnixSupport runtime configuration switch to true in the runtimeconfig.json file.

runtimeconfig.template.json template file:

{
   "configProperties": {
      "System.Drawing.EnableUnixSupport": true
   }
}

[appname].runtimeconfig.json output file:

{
   "runtimeOptions": {
      "configProperties": {
         "System.Drawing.EnableUnixSupport": true
      }
   }
}

Note

  • This configuration switch was added to give cross-platform apps that depend heavily on this package time to migrate to more modern libraries. However, non-Windows bugs will not be fixed.
  • This switch is only available in .NET 6 and was removed in .NET 7.

Affected APIs

System.Drawing namespace:

System.Drawing.Drawing2D namespace:

System.Drawing.Imaging namespace:

System.Drawing.Printing namespace:

System.Drawing.Text namespace:

See also