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
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
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
TypeInitializerExceptionwith aPlatformNotSupportedExceptionas the inner exception, unless a runtime config switch is set. The exception looks like this one:To enable Unix support, the runtime config switch,
System.Drawing.EnableUnixSupport, needs to be set totrue.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
Type of breaking change
Reason for change
The cross-platform implementation of
System.Drawing.Commonis mainly providedon the native side, via
libgdiplus. It's effectively a re-implementation ofthe parts of Windows that
System.Drawing.Commonis depending on. As you canimagine, that makes
libgdiplusa very non-trivial component. It's around 30klines of pretty old C code, virtually untested, and lacks a lot of
functionality.
libgdiplusalso has a lot of external dependencies for all theimage processing and text rendering, such as
cairo,pango, and other nativelibraries, which makes maintaining and shipping it even more challenging.
Since
System.Drawing.Commonwas really designed to be a thin wrapper overWindows 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
libgdiplusthat never got fixed, or helping peopleinstall
libgdipluscorrectly (because it's not part of .NET Core proper). Thisis very different from other external dependencies we have taken, for example,
icuoropenssl, which are high-quality libraries, rather than poorlymaintained re-implementation of Windows components. Thus, we have come to
believe that it's not viable to get
libgdiplusto the point where its featureset 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.Commonis used on cross-platform mostly for image manipulationlike 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.Commontrim compatible.The usages we see of
System.Drawing.Commonin non-Windows environments aretypically well supported with SkiaSharp and ImageSharp.
Thus, we believe it is not worth investing in making
System.Drawing.Commonwork 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.DrawingNamespace:
System.Drawing.Drawing2DNamespace:
System.Drawing.ImagingNamespace:
System.Drawing.PrintingNamespace:
System.Drawing.Textcc: @ericstj @terrajobst @danmoseley