From c739fa7c709a1dfd9a7937da025d2a12623272ad Mon Sep 17 00:00:00 2001 From: Immo Landwerth Date: Thu, 15 Jul 2021 12:22:27 -0700 Subject: [PATCH 01/21] Add "Make `System.Drawing.Common` only supported on Windows" --- INDEX.md | 1 + .../system-drawing-win-only.md | 183 ++++++++++++++++++ 2 files changed, 184 insertions(+) create mode 100644 accepted/2021/system-drawing-win-only/system-drawing-win-only.md diff --git a/INDEX.md b/INDEX.md index cc3a086b9..c87886fd7 100644 --- a/INDEX.md +++ b/INDEX.md @@ -72,6 +72,7 @@ Use update-index to regenerate it: | 2021 | [.NET 6.0 Target Frameworks](accepted/2021/net6.0-tfms/net6.0-tfms.md) | [Immo Landwerth](https://github.com/terrajobst) | | 2021 | [Compile-time source generation for strongly-typed logging messages](accepted/2021/logging-generator.md) | [Maryam Ariyan](https://github.com/maryamariyan), [Martin Taillefer](https://github.com/geeknoid) | | 2021 | [Inbox Source Generators](accepted/2021/InboxSourceGenerators.md) | [Eric StJohn](https://github.com/ericstj) | +| 2021 | [Make `System.Drawing.Common` only supported on Windows](accepted/2021/system-drawing-win-only/system-drawing-win-only.md) | [Santiago Fernandez Madero](https://github.com/safern) | | 2021 | [Objective-C interoperability](accepted/2021/objectivec-interop.md) | [Aaron Robinson](https://github.com/AaronRobinsonMSFT) | | 2021 | [Preview Features](accepted/2021/preview-features/preview-features.md) | [Immo Landwerth](https://github.com/terrajobst) | | 2021 | [TFM for .NET nanoFramework](accepted/2021/nano-framework-tfm/nano-framework-tfm.md) | [Immo Landwerth](https://github.com/terrajobst), [Laurent Ellerbach](https://github.com/Ellerbach), [José Simões](https://github.com/josesimoes) | diff --git a/accepted/2021/system-drawing-win-only/system-drawing-win-only.md b/accepted/2021/system-drawing-win-only/system-drawing-win-only.md new file mode 100644 index 000000000..ecdfe629d --- /dev/null +++ b/accepted/2021/system-drawing-win-only/system-drawing-win-only.md @@ -0,0 +1,183 @@ +# Make `System.Drawing.Common` only supported on Windows + +**Owner** [Santiago Fernandez Madero](https://github.com/safern) + +In the .NET Core 2.x days we created the `Microsoft.Windows.Compatibility` +package which exposes many Windows-only APIs so that more people can migrate to +.NET Core. As part of this, we also ported `System.Drawing.Common`. This was +mainly meant for .NET Core users that still target Windows, however since Mono +already had a cross-platform implementation, we decided to bring that over. The +cross-platform functionality is provided via the native library `libgdiplus`. +Sadly, `libgdiplus` is a community supported library and at this point +effectively unmaintained. + +While `libgdiplus` has helped a lot of customers expand to cross-platform it has +also caused some headaches. `System.Drawing.Common` is very Windows driven as it +is mostly a wrapper around GDI+ and is heavily coupled to Windows Forms, which +keeps evolving and diverging from cross-platform graphics. This has caused some +confusion over why some things don't work well on Unix or don't work not at all. + +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). We +have thought about our options, and to support `System.Drawing.Common` properly +on Unix we'd need to make `libgdiplus` a first-class citizen and ship it as part +of the product: + +* `libgdiplus` doesn't ship with all operating systems by default, just like + other native libraries we depend on (icu, openssl). + +* `libgdiplus` is community driven, so a lot of issues/PRs just go stale and are + never looked at. + +* There is no servicing story for bugs and security issues. + +However, making `libgdiplus` a first-class citizen is costly. It's around 30k +lines of pretty old C code, virtually untestable, 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 shipping even more challenging. + +We've also hit some memory leaks or double free'd memory that weren't fixed in +`libgdiplus` and that we had to work around because they were potential security +issues. This makes it harder as we are basically on our “own” for those security +issues. `libgdiplus` is a library we don't own, but that we must spend time +investigating issues and proposing fixes. + +We have noticed 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+. + +## Requirements + +### Goals + +* Consumers of `System.Drawing.Common` will be informed that starting with .NET + 6, it's only supported on Windows, via the platform compatibility analyzer +* Cross-platform consumers have the ability to turn on a compatibility switch to + continue using `System.Drawing.Common` via `libgdiplus` + +### Non-Goals + +* Closing the gap of `System.Drawing.Common` for non-Windows platforms or + bundling `libgdiplus` as part of the .NET 6 installer + +## Stakeholders and Reviewers + +* Libraries team +* ML.NET +* Xamarin team + +## Design + +In the past we decided to include the following disclaimer in our docs: + +> The `System.Drawing.Common` NuGet package works on Windows, Linux, and macOS. +> However, there are some platform differences. On Linux and macOS, the GDI+ +> functionality is implemented by the `libgdiplus` library. This library is not +> installed by default in most Linux distributions and doesn't support all the +> functionality of GDI+ on Windows on macOS. There are also platforms where +> `libgdiplus` is not available at all. To use types from the +> `System.Drawing.Common` package on Linux and macOS, you must install +> `libgdiplus` separately. For more information, see Install .NET on Linux or +> Install .NET on macOS. +> +> If you can't use System.Drawing with your application, recommended +> alternatives include ImageSharp, SkiaSharp, and Windows Imaging Components. + +However, this disclaimer doesn't feel clear enough to steer people towards using +other graphics libraries. + +The proposal is to do the following for .NET 6: + +1. **Mark the assembly as only being supported on Windows**. That will cause + the platform compatibility analyzer to warn when consumed from a project + that isn't targeting net6.0-windows (or marked as Windows-specific). + +2. Throw `PlatformNotSupportedException` when trying to load `libgdiplus` + pointing to an aka.ms link with the reasons behind it and recommending + stable, well-maintained open-source library alternatives + +3. Add an AppContext switch customers can set in their apps or at runtime to + re-enable `System.Drawing.Common` via `libgdiplus` on non-Windows platforms. + +4. Add targets to the package that when it is restored using a non-windows RID, + it warns that we no longer support it on non-windows and point to the aka.ms + link with more info. + +The challenge is that `System.Drawing.Common` is used by 1st party consumers +such as ML.NET, which uses it for image manipulation and even exposes an API +that returns a Bitmap. At the same time, `System.Devices.Iot` is in the process +of moving to use ImageSharp and so far they had a great migration experience. We +need to engage with 1st party customers to see what impact this proposal will +have on them. + +***Note:** This only affect `System.Drawing.Common` and would leave +`System.Drawing.Primitives` as-is. That assembly on contains primitive types +that don't depend on GDI+, such `Rectangle`, `Point`, and `Size`.* + +# Q & A + +## What does the usage data of `System.Drawing.Common` reveal? + +In order to assess how `System.Drawing.Common` we looked at the API usage from +libraries published to nuget.org. + +We looked at member refs to types that begin with `System.Drawing.` and +aggregated the hits by type and member name. We also pulled in the TFM of the +assemblies in question to help categorize the hits. There's a lot of data (there +are a lot of members * TFMs), so instead of just huge raw tables of nonsense, +we'll provide a summary of what we observed. + +If we look at .NET Core family of TFMs, the top APIs are: + +* `System.Drawing.Bitmap` (constructor) +* `System.Drawing.Font` (constructor) +* `System.Drawing.Graphics.DrawImage()`/`DrawString()`/`FillRectangle()` +* `System.Drawing.Point(F)` +* `System.Drawing.Rectangle(F)` +* `System.Drawing.Size(F)` + +The hits here are in the 40k range, and quickly fall off as we get to +`System.Drawing.Brush` at ~15k + +These usages are consistent with drawing/augmenting images scenarios. +Interestingly, `set_SmoothingMode` has fewer than 1k hits, which suggests that +most people are getting less than stellar results from their current usage, and +they're likely to be much happier moving to our suggested solutions, which have +better quality by default. + +.NET Standard TFMs have similar usage, but `System.Drawing.Color` shows up at +the top of the hits, along with operations that indicate color calculations are +a top scenario, and the bulk of other auxillary types like point, rectangle, +size, etc. have reduced usage. Overall, .NET Standard usage is slightly less +than .NET Core, which was a surprise to us, and we're not exactly sure what to +make of it. It could suggest that .NET Core usage overall is beginning to +eclipse .NET Standard. Or, it could mean something else entirely, like .NET +Standard libraries tend to be used in different scenarios that are doing less +image manipulation, and more raw color calculations. Finding out, is a lot more +work, and we don't think it helps us here. + +Other interesting takeaways: + +* These types are used by Xamarin.iOS and MonoAndroid targets, particularly the + `Rectangle`/`Size`/`Point` types/APIs, although overall usage is in the 13k + range, and falls off quickly. This suggests a usage pattern other than drawing + things on images, but it's not clear that this decision has any effect on that + part of the ecosystem. + +* For comparison, the .NET Framework usage of these types is in the 531k range, + which very similar usage patterns to .NET Core. If you combine "no TFM" + assemblies, you get an extra almost 200k of hits, so this dwarfs .NET Core + usage, but that's no surprise. From da064c53e444e355d4445fad34673c5be71f5f6f Mon Sep 17 00:00:00 2001 From: Immo Landwerth Date: Thu, 15 Jul 2021 13:09:28 -0700 Subject: [PATCH 02/21] Update accepted/2021/system-drawing-win-only/system-drawing-win-only.md Co-authored-by: Jan Kotas --- .../2021/system-drawing-win-only/system-drawing-win-only.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accepted/2021/system-drawing-win-only/system-drawing-win-only.md b/accepted/2021/system-drawing-win-only/system-drawing-win-only.md index ecdfe629d..b1f9ec9af 100644 --- a/accepted/2021/system-drawing-win-only/system-drawing-win-only.md +++ b/accepted/2021/system-drawing-win-only/system-drawing-win-only.md @@ -15,7 +15,7 @@ While `libgdiplus` has helped a lot of customers expand to cross-platform it has also caused some headaches. `System.Drawing.Common` is very Windows driven as it is mostly a wrapper around GDI+ and is heavily coupled to Windows Forms, which keeps evolving and diverging from cross-platform graphics. This has caused some -confusion over why some things don't work well on Unix or don't work not at all. +confusion over why some things don't work well on Unix or don't work at all. 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 From 8130d82a1605537cf2e7d141752913817a4992ac Mon Sep 17 00:00:00 2001 From: Immo Landwerth Date: Thu, 15 Jul 2021 13:09:40 -0700 Subject: [PATCH 03/21] Update accepted/2021/system-drawing-win-only/system-drawing-win-only.md Co-authored-by: Jan Kotas --- .../2021/system-drawing-win-only/system-drawing-win-only.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accepted/2021/system-drawing-win-only/system-drawing-win-only.md b/accepted/2021/system-drawing-win-only/system-drawing-win-only.md index b1f9ec9af..c02bf7253 100644 --- a/accepted/2021/system-drawing-win-only/system-drawing-win-only.md +++ b/accepted/2021/system-drawing-win-only/system-drawing-win-only.md @@ -33,7 +33,7 @@ of the product: * There is no servicing story for bugs and security issues. However, making `libgdiplus` a first-class citizen is costly. It's around 30k -lines of pretty old C code, virtually untestable, and lacks a lot of +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 shipping even more challenging. From 6f9ebd766d8cdbd1f66fd44ab8c3695003bac4b8 Mon Sep 17 00:00:00 2001 From: Immo Landwerth Date: Thu, 15 Jul 2021 13:11:46 -0700 Subject: [PATCH 04/21] Update accepted/2021/system-drawing-win-only/system-drawing-win-only.md Co-authored-by: Jan Kotas --- .../2021/system-drawing-win-only/system-drawing-win-only.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accepted/2021/system-drawing-win-only/system-drawing-win-only.md b/accepted/2021/system-drawing-win-only/system-drawing-win-only.md index c02bf7253..b8210063a 100644 --- a/accepted/2021/system-drawing-win-only/system-drawing-win-only.md +++ b/accepted/2021/system-drawing-win-only/system-drawing-win-only.md @@ -118,7 +118,7 @@ The proposal is to do the following for .NET 6: The challenge is that `System.Drawing.Common` is used by 1st party consumers such as ML.NET, which uses it for image manipulation and even exposes an API -that returns a Bitmap. At the same time, `System.Devices.Iot` is in the process +that returns a Bitmap. At the same time, https://github.com/dotnet/iot is in the process of moving to use ImageSharp and so far they had a great migration experience. We need to engage with 1st party customers to see what impact this proposal will have on them. From b6bffe56a9dfabdf26f24bd5cc8f01aadc964042 Mon Sep 17 00:00:00 2001 From: Immo Landwerth Date: Thu, 15 Jul 2021 13:13:15 -0700 Subject: [PATCH 05/21] Update accepted/2021/system-drawing-win-only/system-drawing-win-only.md Co-authored-by: Jan Kotas --- .../2021/system-drawing-win-only/system-drawing-win-only.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accepted/2021/system-drawing-win-only/system-drawing-win-only.md b/accepted/2021/system-drawing-win-only/system-drawing-win-only.md index b8210063a..2b5aeff96 100644 --- a/accepted/2021/system-drawing-win-only/system-drawing-win-only.md +++ b/accepted/2021/system-drawing-win-only/system-drawing-win-only.md @@ -125,7 +125,7 @@ have on them. ***Note:** This only affect `System.Drawing.Common` and would leave `System.Drawing.Primitives` as-is. That assembly on contains primitive types -that don't depend on GDI+, such `Rectangle`, `Point`, and `Size`.* +that don't depend on GDI+, such `Rectangle`, `Point`, and `Size`. # Q & A From bc72fb199984db994bda2b217105185068b71e8b Mon Sep 17 00:00:00 2001 From: Santiago Fernandez Madero Date: Thu, 15 Jul 2021 15:09:36 -0700 Subject: [PATCH 06/21] PR Feedback --- .../system-drawing-win-only.md | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/accepted/2021/system-drawing-win-only/system-drawing-win-only.md b/accepted/2021/system-drawing-win-only/system-drawing-win-only.md index 2b5aeff96..4f2a0b01d 100644 --- a/accepted/2021/system-drawing-win-only/system-drawing-win-only.md +++ b/accepted/2021/system-drawing-win-only/system-drawing-win-only.md @@ -65,7 +65,7 @@ context of Windows Forms and GDI+. * Consumers of `System.Drawing.Common` will be informed that starting with .NET 6, it's only supported on Windows, via the platform compatibility analyzer -* Cross-platform consumers have the ability to turn on a compatibility switch to +* Cross-platform consumers can reference older versions of the package to continue using `System.Drawing.Common` via `libgdiplus` ### Non-Goals @@ -109,10 +109,7 @@ The proposal is to do the following for .NET 6: pointing to an aka.ms link with the reasons behind it and recommending stable, well-maintained open-source library alternatives -3. Add an AppContext switch customers can set in their apps or at runtime to - re-enable `System.Drawing.Common` via `libgdiplus` on non-Windows platforms. - -4. Add targets to the package that when it is restored using a non-windows RID, +3. Add targets to the package that when it is restored using a non-windows RID, it warns that we no longer support it on non-windows and point to the aka.ms link with more info. @@ -125,10 +122,23 @@ have on them. ***Note:** This only affect `System.Drawing.Common` and would leave `System.Drawing.Primitives` as-is. That assembly on contains primitive types -that don't depend on GDI+, such `Rectangle`, `Point`, and `Size`. +that don't depend on GDI+, such `Rectangle`, `Point`, and `Size`. Any type in `System.Drawing.Common` +that don't depend on GDI+, will be moved to `System.Drawing.Primitives`. # Q & A +## Will this prevent applications to move to .NET 6? + +No, `System.Drawing.Common` is a standalone package that does not ship as part +of the shared framework. For that reason if an application wants to keep using +`System.Drawing.Common` on `Unix` and move to .NET 6, they can reference the +`5.0.x` version of the package. + +## How will applications migrate to recommended libraries? + +We will provide with the right documentation via a breaking change notice and a document +that will contain guidance and samples. + ## What does the usage data of `System.Drawing.Common` reveal? In order to assess how `System.Drawing.Common` we looked at the API usage from From 6be82b6045417263c54f7e668a80e8ab52b0e7da Mon Sep 17 00:00:00 2001 From: Immo Landwerth Date: Thu, 15 Jul 2021 15:37:15 -0700 Subject: [PATCH 07/21] Update accepted/2021/system-drawing-win-only/system-drawing-win-only.md Co-authored-by: Jan Kotas --- .../2021/system-drawing-win-only/system-drawing-win-only.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accepted/2021/system-drawing-win-only/system-drawing-win-only.md b/accepted/2021/system-drawing-win-only/system-drawing-win-only.md index 4f2a0b01d..1bc0ac9f0 100644 --- a/accepted/2021/system-drawing-win-only/system-drawing-win-only.md +++ b/accepted/2021/system-drawing-win-only/system-drawing-win-only.md @@ -121,7 +121,7 @@ need to engage with 1st party customers to see what impact this proposal will have on them. ***Note:** This only affect `System.Drawing.Common` and would leave -`System.Drawing.Primitives` as-is. That assembly on contains primitive types +`System.Drawing.Primitives` as-is. That assembly contains primitive types that don't depend on GDI+, such `Rectangle`, `Point`, and `Size`. Any type in `System.Drawing.Common` that don't depend on GDI+, will be moved to `System.Drawing.Primitives`. From e74a7cb32f4d1145a83f1dc4a41f4507322eb98a Mon Sep 17 00:00:00 2001 From: Immo Landwerth Date: Thu, 15 Jul 2021 15:37:21 -0700 Subject: [PATCH 08/21] Update accepted/2021/system-drawing-win-only/system-drawing-win-only.md Co-authored-by: Jan Kotas --- .../2021/system-drawing-win-only/system-drawing-win-only.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accepted/2021/system-drawing-win-only/system-drawing-win-only.md b/accepted/2021/system-drawing-win-only/system-drawing-win-only.md index 1bc0ac9f0..be6e8f56e 100644 --- a/accepted/2021/system-drawing-win-only/system-drawing-win-only.md +++ b/accepted/2021/system-drawing-win-only/system-drawing-win-only.md @@ -122,7 +122,7 @@ have on them. ***Note:** This only affect `System.Drawing.Common` and would leave `System.Drawing.Primitives` as-is. That assembly contains primitive types -that don't depend on GDI+, such `Rectangle`, `Point`, and `Size`. Any type in `System.Drawing.Common` +that don't depend on GDI+, such `Rectangle`, `Point`, and `Size`. Any types in `System.Drawing.Common` that don't depend on GDI+, will be moved to `System.Drawing.Primitives`. # Q & A From a15a8c7a324c482c5e38b73e46c2afe56f6bd504 Mon Sep 17 00:00:00 2001 From: Immo Landwerth Date: Thu, 15 Jul 2021 15:40:15 -0700 Subject: [PATCH 09/21] Update accepted/2021/system-drawing-win-only/system-drawing-win-only.md --- .../2021/system-drawing-win-only/system-drawing-win-only.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accepted/2021/system-drawing-win-only/system-drawing-win-only.md b/accepted/2021/system-drawing-win-only/system-drawing-win-only.md index be6e8f56e..1d7806b56 100644 --- a/accepted/2021/system-drawing-win-only/system-drawing-win-only.md +++ b/accepted/2021/system-drawing-win-only/system-drawing-win-only.md @@ -123,7 +123,7 @@ have on them. ***Note:** This only affect `System.Drawing.Common` and would leave `System.Drawing.Primitives` as-is. That assembly contains primitive types that don't depend on GDI+, such `Rectangle`, `Point`, and `Size`. Any types in `System.Drawing.Common` -that don't depend on GDI+, will be moved to `System.Drawing.Primitives`. +that don't depend on GDI+, will be moved to `System.Drawing.Primitives`.* # Q & A From 948cca935cfab4828566c74380c18e9d257719c9 Mon Sep 17 00:00:00 2001 From: Immo Landwerth Date: Fri, 16 Jul 2021 10:56:54 -0700 Subject: [PATCH 10/21] Update accepted/2021/system-drawing-win-only/system-drawing-win-only.md Co-authored-by: Dan Moseley --- .../2021/system-drawing-win-only/system-drawing-win-only.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accepted/2021/system-drawing-win-only/system-drawing-win-only.md b/accepted/2021/system-drawing-win-only/system-drawing-win-only.md index 1d7806b56..b4851264c 100644 --- a/accepted/2021/system-drawing-win-only/system-drawing-win-only.md +++ b/accepted/2021/system-drawing-win-only/system-drawing-win-only.md @@ -44,7 +44,7 @@ issues. This makes it harder as we are basically on our “own” for those secu issues. `libgdiplus` is a library we don't own, but that we must spend time investigating issues and proposing fixes. -We have noticed that `System.Drawing.Common` is used on cross-platform mostly for +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 From 783c14fb1a4f6c7cb8bcf0967756b223d4c4a6c9 Mon Sep 17 00:00:00 2001 From: Immo Landwerth Date: Fri, 16 Jul 2021 10:57:11 -0700 Subject: [PATCH 11/21] Update accepted/2021/system-drawing-win-only/system-drawing-win-only.md Co-authored-by: Dan Moseley --- .../2021/system-drawing-win-only/system-drawing-win-only.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accepted/2021/system-drawing-win-only/system-drawing-win-only.md b/accepted/2021/system-drawing-win-only/system-drawing-win-only.md index b4851264c..85cb8ea73 100644 --- a/accepted/2021/system-drawing-win-only/system-drawing-win-only.md +++ b/accepted/2021/system-drawing-win-only/system-drawing-win-only.md @@ -24,7 +24,7 @@ have thought about our options, and to support `System.Drawing.Common` properly on Unix we'd need to make `libgdiplus` a first-class citizen and ship it as part of the product: -* `libgdiplus` doesn't ship with all operating systems by default, just like +* `libgdiplus` doesn't ship with all operating systems by default, unlike other native libraries we depend on (icu, openssl). * `libgdiplus` is community driven, so a lot of issues/PRs just go stale and are From 2784ccf14457bb2f0ccaa25170392000f99f8f33 Mon Sep 17 00:00:00 2001 From: Immo Landwerth Date: Fri, 16 Jul 2021 11:00:58 -0700 Subject: [PATCH 12/21] Add link --- .../2021/system-drawing-win-only/system-drawing-win-only.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/accepted/2021/system-drawing-win-only/system-drawing-win-only.md b/accepted/2021/system-drawing-win-only/system-drawing-win-only.md index 85cb8ea73..b37efe77b 100644 --- a/accepted/2021/system-drawing-win-only/system-drawing-win-only.md +++ b/accepted/2021/system-drawing-win-only/system-drawing-win-only.md @@ -64,7 +64,7 @@ context of Windows Forms and GDI+. ### Goals * Consumers of `System.Drawing.Common` will be informed that starting with .NET - 6, it's only supported on Windows, via the platform compatibility analyzer + 6, it's only supported on Windows, via the [platform compatibility analyzer] * Cross-platform consumers can reference older versions of the package to continue using `System.Drawing.Common` via `libgdiplus` @@ -191,3 +191,5 @@ Other interesting takeaways: which very similar usage patterns to .NET Core. If you combine "no TFM" assemblies, you get an extra almost 200k of hits, so this dwarfs .NET Core usage, but that's no surprise. + +[platform compatibility analyzer]: https://docs.microsoft.com/en-us/dotnet/standard/analyzers/platform-compat-analyzer From 6f01cfc3c210c52a96d84da21f4d0b780c7d577f Mon Sep 17 00:00:00 2001 From: Immo Landwerth Date: Fri, 16 Jul 2021 11:01:16 -0700 Subject: [PATCH 13/21] Fix line wrapping --- .../system-drawing-win-only.md | 72 ++++++++++--------- 1 file changed, 37 insertions(+), 35 deletions(-) diff --git a/accepted/2021/system-drawing-win-only/system-drawing-win-only.md b/accepted/2021/system-drawing-win-only/system-drawing-win-only.md index b37efe77b..83fb4d097 100644 --- a/accepted/2021/system-drawing-win-only/system-drawing-win-only.md +++ b/accepted/2021/system-drawing-win-only/system-drawing-win-only.md @@ -24,8 +24,8 @@ have thought about our options, and to support `System.Drawing.Common` properly on Unix we'd need to make `libgdiplus` a first-class citizen and ship it as part of the product: -* `libgdiplus` doesn't ship with all operating systems by default, unlike - other native libraries we depend on (icu, openssl). +* `libgdiplus` doesn't ship with all operating systems by default, unlike other + native libraries we depend on (icu, openssl). * `libgdiplus` is community driven, so a lot of issues/PRs just go stale and are never looked at. @@ -44,20 +44,21 @@ issues. This makes it harder as we are basically on our “own” for those secu issues. `libgdiplus` is a library we don't own, but that we must spend time investigating issues and proposing fixes. -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. +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+. +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+. ## Requirements @@ -83,27 +84,27 @@ context of Windows Forms and GDI+. In the past we decided to include the following disclaimer in our docs: -> The `System.Drawing.Common` NuGet package works on Windows, Linux, and macOS. -> However, there are some platform differences. On Linux and macOS, the GDI+ -> functionality is implemented by the `libgdiplus` library. This library is not -> installed by default in most Linux distributions and doesn't support all the -> functionality of GDI+ on Windows on macOS. There are also platforms where -> `libgdiplus` is not available at all. To use types from the -> `System.Drawing.Common` package on Linux and macOS, you must install -> `libgdiplus` separately. For more information, see Install .NET on Linux or -> Install .NET on macOS. +> The `System.Drawing.Common` NuGet package works on Windows, Linux, and macOS. +> However, there are some platform differences. On Linux and macOS, the GDI+ +> functionality is implemented by the `libgdiplus` library. This library is not +> installed by default in most Linux distributions and doesn't support all the +> functionality of GDI+ on Windows on macOS. There are also platforms where +> `libgdiplus` is not available at all. To use types from the +> `System.Drawing.Common` package on Linux and macOS, you must install +> `libgdiplus` separately. For more information, see Install .NET on Linux or +> Install .NET on macOS. > -> If you can't use System.Drawing with your application, recommended -> alternatives include ImageSharp, SkiaSharp, and Windows Imaging Components. +> If you can't use System.Drawing with your application, recommended +> alternatives include ImageSharp, SkiaSharp, and Windows Imaging Components. However, this disclaimer doesn't feel clear enough to steer people towards using other graphics libraries. The proposal is to do the following for .NET 6: -1. **Mark the assembly as only being supported on Windows**. That will cause - the platform compatibility analyzer to warn when consumed from a project - that isn't targeting net6.0-windows (or marked as Windows-specific). +1. **Mark the assembly as only being supported on Windows**. That will cause the + platform compatibility analyzer to warn when consumed from a project that + isn't targeting net6.0-windows (or marked as Windows-specific). 2. Throw `PlatformNotSupportedException` when trying to load `libgdiplus` pointing to an aka.ms link with the reasons behind it and recommending @@ -115,15 +116,16 @@ The proposal is to do the following for .NET 6: The challenge is that `System.Drawing.Common` is used by 1st party consumers such as ML.NET, which uses it for image manipulation and even exposes an API -that returns a Bitmap. At the same time, https://github.com/dotnet/iot is in the process -of moving to use ImageSharp and so far they had a great migration experience. We -need to engage with 1st party customers to see what impact this proposal will -have on them. +that returns a Bitmap. At the same time, https://github.com/dotnet/iot is in the +process of moving to use ImageSharp and so far they had a great migration +experience. We need to engage with 1st party customers to see what impact this +proposal will have on them. ***Note:** This only affect `System.Drawing.Common` and would leave -`System.Drawing.Primitives` as-is. That assembly contains primitive types -that don't depend on GDI+, such `Rectangle`, `Point`, and `Size`. Any types in `System.Drawing.Common` -that don't depend on GDI+, will be moved to `System.Drawing.Primitives`.* +`System.Drawing.Primitives` as-is. That assembly contains primitive types that +don't depend on GDI+, such `Rectangle`, `Point`, and `Size`. Any types in +`System.Drawing.Common` that don't depend on GDI+, will be moved to +`System.Drawing.Primitives`.* # Q & A @@ -136,8 +138,8 @@ of the shared framework. For that reason if an application wants to keep using ## How will applications migrate to recommended libraries? -We will provide with the right documentation via a breaking change notice and a document -that will contain guidance and samples. +We will provide with the right documentation via a breaking change notice and a +document that will contain guidance and samples. ## What does the usage data of `System.Drawing.Common` reveal? From 8a69ca769be6e9bb8d55cb69f010cd20e7297d08 Mon Sep 17 00:00:00 2001 From: Immo Landwerth Date: Fri, 16 Jul 2021 11:19:22 -0700 Subject: [PATCH 14/21] Replace ".NET 6" with "moving forward" as this package isn't tied to .NET 6 --- .../2021/system-drawing-win-only/system-drawing-win-only.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/accepted/2021/system-drawing-win-only/system-drawing-win-only.md b/accepted/2021/system-drawing-win-only/system-drawing-win-only.md index 83fb4d097..f0bc9e46a 100644 --- a/accepted/2021/system-drawing-win-only/system-drawing-win-only.md +++ b/accepted/2021/system-drawing-win-only/system-drawing-win-only.md @@ -64,8 +64,8 @@ the context of Windows Forms and GDI+. ### Goals -* Consumers of `System.Drawing.Common` will be informed that starting with .NET - 6, it's only supported on Windows, via the [platform compatibility analyzer] +* Consumers of `System.Drawing.Common` will be informed that moving forward, + it's only supported on Windows, via the [platform compatibility analyzer] * Cross-platform consumers can reference older versions of the package to continue using `System.Drawing.Common` via `libgdiplus` From 95816a40f9efe823c10e918d1e4ab536507b122b Mon Sep 17 00:00:00 2001 From: Immo Landwerth Date: Fri, 16 Jul 2021 11:19:45 -0700 Subject: [PATCH 15/21] Clarify support intentions, including Microsoft teams --- .../2021/system-drawing-win-only/system-drawing-win-only.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/accepted/2021/system-drawing-win-only/system-drawing-win-only.md b/accepted/2021/system-drawing-win-only/system-drawing-win-only.md index f0bc9e46a..5d4097bc4 100644 --- a/accepted/2021/system-drawing-win-only/system-drawing-win-only.md +++ b/accepted/2021/system-drawing-win-only/system-drawing-win-only.md @@ -68,6 +68,10 @@ the context of Windows Forms and GDI+. it's only supported on Windows, via the [platform compatibility analyzer] * Cross-platform consumers can reference older versions of the package to continue using `System.Drawing.Common` via `libgdiplus` +* We don't have to support usages of `System.Drawing.Common` on operating + systems other than Windows. We also will not support teams at Microsoft using + this component on other platforms either. Instead, we'll point people to other + libraries. ### Non-Goals From aac3a265e9814fc5894ebc0866c3002aac702ab2 Mon Sep 17 00:00:00 2001 From: Immo Landwerth Date: Fri, 16 Jul 2021 11:20:11 -0700 Subject: [PATCH 16/21] Clarify implementation of System.Drawing.Common --- .../system-drawing-win-only.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/accepted/2021/system-drawing-win-only/system-drawing-win-only.md b/accepted/2021/system-drawing-win-only/system-drawing-win-only.md index 5d4097bc4..b33b9c877 100644 --- a/accepted/2021/system-drawing-win-only/system-drawing-win-only.md +++ b/accepted/2021/system-drawing-win-only/system-drawing-win-only.md @@ -145,6 +145,22 @@ of the shared framework. For that reason if an application wants to keep using We will provide with the right documentation via a breaking change notice and a document that will contain guidance and samples. +## Does this mean .NET is keeping drawing/image processing code to Windows users? + +Not really. The types in `System.Drawing.Common` don't actually implement +drawing, font processing or image parsing. The .NET APIs are merely wrappers +that call into native Windows APIs (namely GDI and GDI+). The cross-platform +implementation of `System.Drawing.Common` is provided by `libgdiplus` which is a +native re-implementation of the underlying Windows APIs. That's why the +experience on other operating systems is subpar and difficult to maintain -- it +amounts to re-implementing parts of Windows. + +`System.Drawing.Common`, just like `System.Windows.Forms`, are very thin +wrappers over Windows technologies and weren't designed for cross-platform use +in mind. This means trying to make these technologies work on other platforms +doesn't always work well. And in case of `System.Drawing.Common` the end result +feels like square peg in a round hole. + ## What does the usage data of `System.Drawing.Common` reveal? In order to assess how `System.Drawing.Common` we looked at the API usage from From e478944aff6814723ca7b5a810ca25e70f771051 Mon Sep 17 00:00:00 2001 From: Immo Landwerth Date: Fri, 16 Jul 2021 11:21:20 -0700 Subject: [PATCH 17/21] Fix headings --- .../system-drawing-win-only/system-drawing-win-only.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/accepted/2021/system-drawing-win-only/system-drawing-win-only.md b/accepted/2021/system-drawing-win-only/system-drawing-win-only.md index b33b9c877..fa9bffae0 100644 --- a/accepted/2021/system-drawing-win-only/system-drawing-win-only.md +++ b/accepted/2021/system-drawing-win-only/system-drawing-win-only.md @@ -131,21 +131,21 @@ don't depend on GDI+, such `Rectangle`, `Point`, and `Size`. Any types in `System.Drawing.Common` that don't depend on GDI+, will be moved to `System.Drawing.Primitives`.* -# Q & A +## Q & A -## Will this prevent applications to move to .NET 6? +### Will this prevent applications to move to .NET 6? No, `System.Drawing.Common` is a standalone package that does not ship as part of the shared framework. For that reason if an application wants to keep using `System.Drawing.Common` on `Unix` and move to .NET 6, they can reference the `5.0.x` version of the package. -## How will applications migrate to recommended libraries? +### How will applications migrate to recommended libraries? We will provide with the right documentation via a breaking change notice and a document that will contain guidance and samples. -## Does this mean .NET is keeping drawing/image processing code to Windows users? +### Does this mean .NET is keeping drawing/image processing code to Windows users? Not really. The types in `System.Drawing.Common` don't actually implement drawing, font processing or image parsing. The .NET APIs are merely wrappers @@ -161,7 +161,7 @@ in mind. This means trying to make these technologies work on other platforms doesn't always work well. And in case of `System.Drawing.Common` the end result feels like square peg in a round hole. -## What does the usage data of `System.Drawing.Common` reveal? +### What does the usage data of `System.Drawing.Common` reveal? In order to assess how `System.Drawing.Common` we looked at the API usage from libraries published to nuget.org. From 4dbc601dc1d9df495094b0afac1e4d8ca16b7a66 Mon Sep 17 00:00:00 2001 From: Immo Landwerth Date: Fri, 16 Jul 2021 11:33:55 -0700 Subject: [PATCH 18/21] Re-word introduction to make it clear why `libgdiplus` isn't a viable path --- .../system-drawing-win-only.md | 40 +++++++++---------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/accepted/2021/system-drawing-win-only/system-drawing-win-only.md b/accepted/2021/system-drawing-win-only/system-drawing-win-only.md index fa9bffae0..a4bf45bdd 100644 --- a/accepted/2021/system-drawing-win-only/system-drawing-win-only.md +++ b/accepted/2021/system-drawing-win-only/system-drawing-win-only.md @@ -17,32 +17,28 @@ is mostly a wrapper around GDI+ and is heavily coupled to Windows Forms, which keeps evolving and diverging from cross-platform graphics. This has caused some confusion over why some things don't work well on Unix or don't work at all. -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). We -have thought about our options, and to support `System.Drawing.Common` properly -on Unix we'd need to make `libgdiplus` a first-class citizen and ship it as part -of the product: - -* `libgdiplus` doesn't ship with all operating systems by default, unlike other - native libraries we depend on (icu, openssl). - -* `libgdiplus` is community driven, so a lot of issues/PRs just go stale and are - never looked at. - -* There is no servicing story for bugs and security issues. - -However, making `libgdiplus` a first-class citizen is costly. It's around 30k +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 shipping even more challenging. +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. -We've also hit some memory leaks or double free'd memory that weren't fixed in -`libgdiplus` and that we had to work around because they were potential security -issues. This makes it harder as we are basically on our “own” for those security -issues. `libgdiplus` is a library we don't own, but that we must spend time -investigating issues and proposing fixes. +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 From cb10282bcb9a9ad5542647d860452c58cd0692e8 Mon Sep 17 00:00:00 2001 From: Santiago Fernandez Madero Date: Fri, 16 Jul 2021 11:53:16 -0700 Subject: [PATCH 19/21] Update accepted/2021/system-drawing-win-only/system-drawing-win-only.md --- .../2021/system-drawing-win-only/system-drawing-win-only.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/accepted/2021/system-drawing-win-only/system-drawing-win-only.md b/accepted/2021/system-drawing-win-only/system-drawing-win-only.md index a4bf45bdd..15cd3e33d 100644 --- a/accepted/2021/system-drawing-win-only/system-drawing-win-only.md +++ b/accepted/2021/system-drawing-win-only/system-drawing-win-only.md @@ -110,9 +110,9 @@ The proposal is to do the following for .NET 6: pointing to an aka.ms link with the reasons behind it and recommending stable, well-maintained open-source library alternatives -3. Add targets to the package that when it is restored using a non-windows RID, - it warns that we no longer support it on non-windows and point to the aka.ms - link with more info. +3. Provide a runtime config switch named `System.Drawing.UnixSupport`, that when is set to `true` we will no longer throw a `PlatformNotSupportedException` when loading `libgdiplus`. + +4. In .NET 7+ all of `Sytem.Drawing.Common` APIs dependent of `libgdiplus` will throw `PlatformNotSupportedException` and the runtime config switch will no longer work. The challenge is that `System.Drawing.Common` is used by 1st party consumers such as ML.NET, which uses it for image manipulation and even exposes an API From 27a6a55fe79a58a7d0b63b057a2d122a1b5ade56 Mon Sep 17 00:00:00 2001 From: Santiago Fernandez Madero Date: Fri, 16 Jul 2021 14:02:24 -0700 Subject: [PATCH 20/21] Update accepted/2021/system-drawing-win-only/system-drawing-win-only.md --- .../2021/system-drawing-win-only/system-drawing-win-only.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/accepted/2021/system-drawing-win-only/system-drawing-win-only.md b/accepted/2021/system-drawing-win-only/system-drawing-win-only.md index 15cd3e33d..6f51df151 100644 --- a/accepted/2021/system-drawing-win-only/system-drawing-win-only.md +++ b/accepted/2021/system-drawing-win-only/system-drawing-win-only.md @@ -133,8 +133,9 @@ don't depend on GDI+, such `Rectangle`, `Point`, and `Size`. Any types in No, `System.Drawing.Common` is a standalone package that does not ship as part of the shared framework. For that reason if an application wants to keep using -`System.Drawing.Common` on `Unix` and move to .NET 6, they can reference the -`5.0.x` version of the package. +`System.Drawing.Common` on `Unix` and move to .NET 6, they can use the `6.0.x` package and set a runtime config switch `System.Drawing.UnixSupport` to `true`. + +However application should be aware that we will not provide any support for Unix issues starting from .NET 6 and that we will be removing Unix implementation entirely on .NET 7+. ### How will applications migrate to recommended libraries? From 9b4520703cfa11ccfbd6e4389ab62730e0cb0de4 Mon Sep 17 00:00:00 2001 From: Santiago Fernandez Madero Date: Mon, 19 Jul 2021 15:30:09 -0700 Subject: [PATCH 21/21] Update accepted/2021/system-drawing-win-only/system-drawing-win-only.md --- .../2021/system-drawing-win-only/system-drawing-win-only.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accepted/2021/system-drawing-win-only/system-drawing-win-only.md b/accepted/2021/system-drawing-win-only/system-drawing-win-only.md index 6f51df151..24379bf0d 100644 --- a/accepted/2021/system-drawing-win-only/system-drawing-win-only.md +++ b/accepted/2021/system-drawing-win-only/system-drawing-win-only.md @@ -110,7 +110,7 @@ The proposal is to do the following for .NET 6: pointing to an aka.ms link with the reasons behind it and recommending stable, well-maintained open-source library alternatives -3. Provide a runtime config switch named `System.Drawing.UnixSupport`, that when is set to `true` we will no longer throw a `PlatformNotSupportedException` when loading `libgdiplus`. +3. Provide a [runtime config switch](https://docs.microsoft.com/dotnet/core/run-time-config/) named `System.Drawing.EnableUnixSupport`, that when is set to `true` we will no longer throw a `PlatformNotSupportedException` when loading `libgdiplus`. 4. In .NET 7+ all of `Sytem.Drawing.Common` APIs dependent of `libgdiplus` will throw `PlatformNotSupportedException` and the runtime config switch will no longer work.