Skip to content

[Breaking change]: System.Drawing.Common no longer supported on non-Windows OSs #25257

Closed

Description

Description

As proposed on: dotnet/designs#234

System.Drawing.Common is now attributed as a Windows specific library which will cause the platform analyzer to emit warnings when compiled for non-windows OSs.

At runtime on non-windows OSs will now throw by default a TypeInitializerException with a PlatformNotSupportedException as the inner exception, unless a runtime config switch is set. The exception looks like this one:

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()

To enable Unix support, the runtime config switch, System.Drawing.EnableUnixSupport, needs to be set to true.

Even if applications set the runtime config switch to true, this is just to give applications that heavily depend on this behavior cross plat, to migrate to more modern like libraries, and we will no longer give support for non-Windows bugs. This runtime config switch will be removed in .NET 7.

The libraries that we recommend libraries to search as an alternative are:

Version

.NET 6 Preview 7

Previous behavior

There was no compile warnings.

There was no runtime exception and no need to set a runtime config switch.

New behavior

  1. Compile time warnings emitted by the Platform analyzer as the assembly is now marked as windows specific.
  2. Runtime exception like the following unless a runtime config switch is set:
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()

Type of breaking change

  • Binary incompatible (existing binaries may encounter a breaking change in behavior - for example, failure to load/execute or different run-time behavior)
  • Source incompatible (existing source code may encounter a breaking change in behavior when targeting the new runtime/component/SDK - for example, compile errors or different run-time behavior)

Reason for change

The cross-platform implementation of System.Drawing.Common is mainly provided
on the native side, via libgdiplus. It's effectively a re-implementation of
the parts of Windows that System.Drawing.Common is depending on. As you can
imagine, that makes libgdiplus a very non-trivial component. It's around 30k
lines of pretty old C code, virtually untested, and lacks a lot of
functionality. libgdiplus also has a lot of external dependencies for all the
image processing and text rendering, such as cairo, pango, and other native
libraries, which makes maintaining and shipping it even more challenging.

Since System.Drawing.Common was really designed to be a thin wrapper over
Windows technologies, its cross-platform implementation is a bit like a square
peg in a round hole; it's subpar because it was only designed with Windows in
mind.

Since the inclusion of the Mono cross-platform implementation we spent lot of
time redirecting issues to libgdiplus that never got fixed, or helping people
install libgdiplus correctly (because it's not part of .NET Core proper). This
is very different from other external dependencies we have taken, for example,
icu or openssl, which are high-quality libraries, rather than poorly
maintained re-implementation of Windows components. Thus, we have come to
believe that 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.

We have noticed (such as from analysis of NuGet packages) that
System.Drawing.Common is used on cross-platform mostly for image manipulation
like QR code generators and text rendering. We haven't noticed heavy graphics
usage as our cross-platform graphics support is very incomplete. For example,
right now some components crash on macOS because the native APIs we use have
been deprecated and are no longer included with recent macOS releases. We have
never gotten a report about that crash; we discovered it ourselves while making
System.Drawing.Common trim compatible.

The usages we see of System.Drawing.Common in non-Windows environments are
typically well supported with SkiaSharp and ImageSharp.

Thus, we believe it is not worth investing in making System.Drawing.Common
work on non-Windows platforms and instead propose we only keep evolving it in
the context of Windows Forms and GDI+.

Recommended action

Migrate code to one of the previously recommended libraries.

TODO: add examples.

Feature area

Other (please put exact area in description textbox)

Affected APIs

Namespace: System.Drawing

  • Bitmap
  • Image
  • Icon
  • Graphics
  • Brush
  • Brushes
  • Pen
  • Pens
  • BufferedGraphics
  • BufferedGraphicsContext
  • Font
  • FontFamily
  • FontConverter
  • IconConverter
  • ImageAnimator
  • Region
  • SolidBrush
  • StringFormat
  • SystemBrushes
  • SystemFonts
  • SystemIcons
  • SystemPens
  • TextureBrush

Namespace: System.Drawing.Drawing2D

  • AdjustableArrowCap
  • CustomLineCap
  • GraphicsPath
  • GraphicsPathIterator
  • GraphicsState
  • HatchBrush
  • LinearGradientBrush
  • Matrix
  • PathGradientBrush

Namespace: System.Drawing.Imaging

  • Encoder
  • EncoderParameter
  • EncoderParameters
  • ImageAttributes
  • ImageCodecInfo
  • ImageFormat
  • Metafile
  • MetafileHeader
  • PlayRecordCallback

Namespace: System.Drawing.Printing

  • PageSettings
  • PreviewPageInfo
  • PrintController
  • PrintDocument
  • PrinterSettings
  • PrintEventArgs
  • PrintPageEventArgs
  • PrintEventHandler
  • PrintPageEventHandler

Namespace: System.Drawing.Text

  • FontCollection
  • InstalledFontCollection
  • PrivateFontCollection

cc: @ericstj @terrajobst @danmoseley

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

Labels

🏁 Release: .NET 6Issues and PRs for the .NET 6 releaseIssues and PRs for the .NET 6 releasePri1High priority, do before Pri2 and Pri3High priority, do before Pri2 and Pri3binary incompatibleExisting binaries may encounter a breaking change in behavior.Existing binaries may encounter a breaking change in behavior.breaking-changeIndicates a .NET Core breaking changeIndicates a .NET Core breaking changedoc-ideaIndicates issues that are suggestions for new topics [org][type][category]Indicates issues that are suggestions for new topics [org][type][category]source incompatibleSource code may encounter a breaking change in behavior when targeting the new version.Source code may encounter a breaking change in behavior when targeting the new version.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions