Description
openedon Jul 21, 2021
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
- Compile time warnings emitted by the Platform analyzer as the assembly is now marked as windows specific.
- 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