---
title: "Fix the System.Drawing “not supported on this platform” error"
url: https://recursiveai.org/oneimage/articles/system-drawing-common-not-supported/
description: "Why System.Drawing.Common throws on Linux, macOS and Docker since .NET 6, why libgdiplus no longer helps, and how to port Bitmap image code to cross-platform .NET."
date: 2026-10-23
author: OneImage team
---

# Fix the System.Drawing “not supported on this platform” error

Why System.Drawing.Common throws on Linux, macOS and Docker since .NET 6, why libgdiplus no longer helps, and how to port Bitmap image code to cross-platform .NET.

October 23, 2026 · OneImage team

“System.Drawing.Common is not supported on this platform” means your code, or a package it uses, called `System.Drawing` (`Bitmap`, `Graphics`, `Image`) on Linux, macOS or in a Linux container. Since .NET 6, Microsoft supports System.Drawing.Common only on Windows. The .NET 6 opt-out switch was removed in .NET 7, so installing libgdiplus or changing a setting won’t bring it back. The fix is to keep that code on Windows or replace it with a cross-platform library. For image work (loading, resizing, cropping, converting, watermarking), that is a small port, shown below with OneImage. Every OneImage sample was run against version 1.6.0 on .NET 10.

## The errors you may see

The message depends on the System.Drawing.Common version your app ends up with. We ran `new Bitmap("photo.jpg")` on Ubuntu 26.04 x64 with the .NET 10.0.11 runtime and no libgdiplus installed, against five versions of the package:

| System.Drawing.Common | What is thrown |
|---|---|
| 6.0.0, 8.0.22 | `TypeInitializationException`: “The type initializer for 'Gdip' threw an exception”, with an inner `PlatformNotSupportedException`: “System.Drawing.Common is not supported on non-Windows platforms. See `https://aka.ms/systemdrawingnonwindows` for more information.” |
| 7.0.0 | `PlatformNotSupportedException`: “System.Drawing.Common is not supported on this platform.” |
| 9.0.11 | A chain of `TypeInitializationException`s (“The type initializer for 'Windows.Win32.PInvoke' threw an exception”) ending in `DllNotFoundException`: “Unable to load shared library 'gdiplus.dll' or one of its dependencies.” |
| 10.0.13 | `TypeInitializationException`: “The type initializer for 'Windows.Win32.PInvokeGdiPlus' threw an exception”, with an inner `DllNotFoundException` for `gdiplus.dll`. |

On 9.x and 10.x, the message no longer mentions the platform at all, which is why “Unable to load shared library 'gdiplus.dll'” also leads here. The build warns first, though: every System.Drawing call compiled for all platforms raises [CA1416](https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1416), “This call site is reachable on all platforms. 'Bitmap' is only supported on: 'windows' 6.1 and later.” If you see CA1416 warnings in a project that runs on Linux, this exception is coming.

## Why System.Drawing.Common is Windows-only

System.Drawing was designed as a thin wrapper over Windows technologies (GDI+). Off Windows it relied on libgdiplus, a reimplementation of those parts of Windows that came from the Mono project. Microsoft’s [.NET 6 breaking-change notice](https://learn.microsoft.com/en-us/dotnet/core/compatibility/core-libraries/6.0/system-drawing-common-windows-only) (last updated July 21, 2023) gives the reason. It describes libgdiplus as “around 30,000 lines of C code that’s largely untested” that “lacks a lot of functionality” and depends on native libraries such as cairo and pango. It concludes: “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.”

- **.NET 6** made the package Windows-only. The `System.Drawing.EnableUnixSupport` runtime switch let apps turn non-Windows support back on temporarily, with the note that “non-Windows bugs will not be fixed.”
- **.NET 7** removed that switch. Per Microsoft’s [.NET 7 notice](https://learn.microsoft.com/en-us/dotnet/core/compatibility/core-libraries/7.0/system-drawing), “you can no longer use the System.Drawing.Common package on non-Windows operating systems.”

The .NET 6 notice adds that System.Drawing.Common “will continue to evolve only in the context of Windows Forms and GDI+.” It still works on Windows.

## Why installing libgdiplus doesn’t fix it

Older answers say to run `apt-get install libgdiplus` or `brew install mono-libgdiplus`. That worked before .NET 6, and on .NET 6 together with the switch above. With the switch gone since .NET 7, Microsoft says the package can no longer be used on non-Windows systems, so the install changes nothing. Look for the code that uses System.Drawing instead.

## Find what uses System.Drawing

If your own code doesn’t reference `System.Drawing`, a dependency does. The .NET SDK shows the path to it:

*Terminal · .NET SDK*

```
dotnet nuget why MyApp.csproj System.Drawing.Common
```

It prints the dependency graph down to System.Drawing.Common, for each target framework ([docs](https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-nuget-why)). If a library pulls it in, check whether a newer version of that library has dropped it or offers a cross-platform build. If it’s your code, read on.

## Your options

- **Keep it on Windows.** If the code only ever runs on Windows (a Windows Forms app, a Windows service), System.Drawing.Common is still supported there. Deploying to Windows containers or hosts is a valid fix.
- **Move to a cross-platform library.** Microsoft’s notices list [SkiaSharp](https://github.com/mono/SkiaSharp), [ImageSharp](https://sixlabors.com/products/imagesharp) (“tiered license”), [Aspose.Drawing](https://products.aspose.com/drawing/net/) (“commercial license”) and [Microsoft.Maui.Graphics](https://learn.microsoft.com/en-us/dotnet/maui/user-interface/graphics/). Our [comparison of .NET image libraries](https://recursiveai.org/oneimage/articles/imagesharp-alternatives/) covers SkiaSharp, ImageSharp, Magick.NET, NetVips and OneImage, with licenses and native dependencies from each project’s own pages. If you choose SkiaSharp, see [SkiaSharp on Linux and Docker](https://recursiveai.org/oneimage/articles/skiasharp-linux-docker/) for the native package it needs there.

Most System.Drawing code on servers is image processing. Microsoft’s .NET 6 notice says its analysis of NuGet packages found cross-platform use was “mostly for image manipulation”. For that, OneImage is a direct replacement. It is pure C# with no native binaries, licensed MIT OR Apache-2.0, and needs .NET 10.

*Terminal · NuGet*

```
dotnet add package RecursiveAI.OneImage
```

## Port Bitmap and Graphics code

A typical System.Drawing resize-and-save, here making a 300 px wide JPEG at quality 85:

*Before: System.Drawing · Windows only*

```
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
 
using var src = new Bitmap("photo.jpg");
int height = src.Height * 300 / src.Width;
 
using var dst = new Bitmap(300, height);
using (var g = Graphics.FromImage(dst))
{
    g.InterpolationMode = InterpolationMode.HighQualityBicubic;
    g.DrawImage(src, 0, 0, 300, height);
}
 
ImageCodecInfo jpeg = ImageCodecInfo.GetImageEncoders().First(c => c.FormatID == ImageFormat.Jpeg.Guid);
using var parameters = new EncoderParameters(1);
parameters.Param[0] = new EncoderParameter(Encoder.Quality, 85L);
dst.Save("photo-300.jpg", jpeg, parameters);
```

The same with OneImage:

*After: OneImage · .NET 10 · any OS*

```
using OneImage;
 
Image.Load("photo.jpg")
     .Resize(width: 300)
     .Save("photo-300.jpg", new SaveOptions
     {
         EncoderOptions = new JpegEncoderOptions { Quality = 85 }
     });
```

We compiled the “before” code against System.Drawing.Common 10.0.13. It builds with CA1416 warnings and throws the 10.0.13 error above on Linux. The “after” code ran on the same machine and wrote a 300×300 JPEG from our 3000×3002 test photo.

A few differences to know when porting:

- **No `Dispose`.** A OneImage `Image` isn’t disposable, so the `using` statements go away. Operations return new immutable images, so you chain them instead of drawing into a `Graphics`.
- **Orientation is applied at load.** If your old code rotated photos by the EXIF orientation tag, remove that, or they will be turned twice.
- **Errors can surface at `Save`.** Loading is lazy, so wrap the save in your `try` as well, or load with `Validate = true`.

## System.Drawing to OneImage cheat sheet

*Program.cs · .NET 10*

```
using OneImage;
 
// new Bitmap(path).Width and .Height, without decoding the pixels
ImageInfo info = Image.Identify("photo.jpg");
Console.WriteLine($"{info.Width}x{info.Height}");
 
Image photo = Image.Load("photo.jpg");
 
// Bitmap.Clone(rectangle, pixelFormat)
photo.Crop(10, 10, 400, 300).Save("crop.png");
 
// Bitmap.RotateFlip(RotateFlipType.Rotate90FlipX)
photo.Rotate(90).Flip(FlipAxis.Horizontal).Save("rotated.png");
 
// Graphics.DrawImage with a ColorMatrix for 80% opacity
photo.Composite(Image.Load("logo.png"), x: 20, y: 20, opacity: 0.8f).Save("watermarked.jpg");
 
// Bitmap.PropertyItems, typed
string? camera = Image.Load("portrait.jpg").Metadata.ReadExif()?.Make;
Console.WriteLine(camera);
 
// new Bitmap(new MemoryStream(bytes)) and bitmap.Save(stream, ImageFormat.Png)
byte[] bytes = File.ReadAllBytes("photo.jpg");
var png = new MemoryStream();
Image.Load(bytes).Resize(width: 300).Save(png, PngFormat.Instance);
Console.WriteLine($"{png.Length} bytes of PNG");
```

| System.Drawing | OneImage |
|---|---|
| `new Bitmap(path)`, `Image.FromStream(stream)` | `Image.Load(path)`, `Image.Load(stream)`, `Image.Load(bytes)` |
| `bitmap.Width`, `bitmap.Height` | `image.Width`, `image.Height`; `Image.Identify` reads only the headers |
| `Graphics.DrawImage` to a smaller `Bitmap` | `Resize(width:, height:, fit:)` or `Image.Thumbnail` |
| `bitmap.Clone(rect, format)` | `Crop(x, y, width, height)` |
| `RotateFlip` | `Rotate(degrees)`, `Flip(FlipAxis)` |
| `Graphics.DrawImage` of an overlay with `ImageAttributes` | `Composite(overlay, x:, y:, opacity:)` |
| `Save(path, ImageFormat.Png)` | `Save("out.png")`: the format follows the extension |
| `EncoderParameters` with `Encoder.Quality` | `SaveOptions { EncoderOptions = new JpegEncoderOptions { Quality = 85 } }` |
| `PropertyItems` | `Metadata.ReadExif()` (orientation, make, model, capture time, GPS); `StripMetadata()` |

The cheat sheet printed `3000x3002`, the camera make of our test photo and the size of the PNG. It wrote a 400×300 crop, a rotated 3002×3000 PNG and the watermarked JPEG. The project’s [migration guide](https://recursiveai.org/oneimage/docs/migrating/) covers more side by side, including pixel access, filters and color adjustments. For resizing in depth, see our guide to [resizing images in C#](https://recursiveai.org/oneimage/articles/resize-image-csharp/), and for crops, [cropping images in C#](https://recursiveai.org/oneimage/articles/crop-image-csharp/).

Code that draws shapes and text with `Graphics` needs more than a rename. OneImage has [vector drawing](https://recursiveai.org/oneimage/docs/drawing/) in the core package, and text in the separate [OneImage.Text](https://recursiveai.org/oneimage/docs/text/) package. Check their docs against what your code draws. Printing (`System.Drawing.Printing`) and Windows Forms UI belong on Windows.

## Run it in Docker without extra packages

The usual Dockerfile fix for System.Drawing, installing libgdiplus and its font dependencies, isn’t needed with OneImage. We published the cheat-sheet program and ran it in the stock `mcr.microsoft.com/dotnet/runtime:10.0` image (Ubuntu 24.04), which has no libgdiplus, Skia or fontconfig libraries. It produced the same output as on the host. `PortDemo.dll` is our test program; use your app’s name:

*Dockerfile · .NET 10*

```
FROM mcr.microsoft.com/dotnet/runtime:10.0
WORKDIR /app
COPY publish/ .
ENTRYPOINT ["dotnet", "PortDemo.dll"]
```

For what else OneImage reads and writes, see the [formats](https://recursiveai.org/oneimage/#formats) on the overview page.
