TL;DR:
System.Drawing.Commonis essentially dead for cross-platform .NET. If you need to generate images, resize photos, or add watermarks on a Linux Docker container, use SkiaSharp. Remember to wrap your bitmaps and canvases inusingblocks to prevent catastrophic memory leaks.
For years, C# developers relied on System.Drawing to manipulate images. However, Microsoft recently restricted System.Drawing.Common to Windows-only due to underlying GDI+ dependencies.
If you want to generate images on a Linux server or inside a Docker container in .NET 9, you need a modern, cross-platform graphics library. Enter SkiaSharp.
What is SkiaSharp?
SkiaSharp is a cross-platform 2D graphics API for .NET based on Google's Skia Graphics Engine (the same engine that powers Google Chrome and Android). It is ridiculously fast and works flawlessly on Linux, macOS, iOS, Android, and Windows.
Example: Generating a Dynamic Watermarked Image
Here is a production-ready example of how to load an image, draw text over it, and save it back out.
✅ The Good Way (Memory Safe)
using SkiaSharp;
using System.IO;
public class ImageService
{
public void AddWatermark(string inputPath, string outputPath, string watermarkText)
{
// 1. ALWAYS use 'using' blocks for SkiaSharp objects!
// They wrap native C++ memory that the GC struggles to clean up automatically.
using var inputStream = File.OpenRead(inputPath);
using var originalBitmap = SKBitmap.Decode(inputStream);
// 2. Create the drawing surface
using var surface = SKSurface.Create(new SKImageInfo(originalBitmap.Width, originalBitmap.Height));
using var canvas = surface.Canvas;
// 3. Draw the original image onto the canvas
canvas.DrawBitmap(originalBitmap, 0, 0);
// 4. Configure the font/paint for the watermark
using var paint = new SKPaint
{
Color = SKColors.White.WithAlpha(128), // 50% transparency
IsAntialias = true,
TextSize = 48,
Typeface = SKTypeface.FromFamilyName("Arial", SKFontStyleWeight.Bold, SKFontStyleWidth.Normal, SKFontStyleSlant.Upright)
};
// 5. Draw the text in the bottom right corner
canvas.DrawText(watermarkText, originalBitmap.Width - 300, originalBitmap.Height - 50, paint);
// 6. Save the final image
using var image = surface.Snapshot();
using var data = image.Encode(SKEncodedImageFormat.Jpeg, 90); // 90% Quality
using var outputStream = File.OpenWrite(outputPath);
data.SaveTo(outputStream);
}
}
Critical SkiaSharp Rules
- The
usingKeyword is Mandatory:SKBitmap,SKSurface,SKCanvas, andSKPaintall implementIDisposable. If you don't dispose of them, your server will run out of RAM in minutes under heavy load. - Quality vs Size: When encoding JPEGs, setting the quality to
100exponentially increases file size for virtually no visible benefit. A quality setting between80and90is the sweet spot for web delivery.
Summary
SkiaSharp is the undisputed king of cross-platform 2D graphics in modern .NET. It's powerful enough to build entire rendering engines and simple enough to add a quick watermark to an uploaded avatar.