Draw with Maui.Graphics and Skia in a C# Console Application
Microsoft’s System.Drawing.Common
package is commonly used for cross-platform graphics in .NET Framework and .NET Core applications, but according to the dotnet roadmap System.Drawing will soon only support Windows. As Microsoft sunsets cross-platform support for System.Drawing
they will be simultaneously developing Microsoft.Maui.Graphics
, a cross-platform graphics library for iOS, Android, Windows, macOS, Tizen and Linux completely in C#.
The Maui.Graphics
library can be used in any .NET application (not just MAUI applications). This page documents how I used the Maui.Drawing package to render graphics in memory (using a Skia back-end) and save them as static images from a console application.
I predict Maui.Graphics
will eventually evolve to overtake System.Drawing
in utilization. It has many advantages for performance and memory management (discussed extensively elsewhere on the internet), but it is still early in development. As of today (July 2021) the Maui.Graphics GitHub page warns “This is an experimental library … There is no official support. Use at your own Risk.”
Microsoft.Maui.Graphics
was still in preview. See Drawing with Maui Graphics (blog post) and C# Data Visualization (website) for updated code examples and information about using this library.
Maui Graphics Skia Console Quickstart
This program will create an image, fill it with blue, add 1,000 random lines, then draw some text. It is written as a .NET 5 top-level console application and requires the Microsoft.Maui.Graphics and Microsoft.Maui.Graphics.Skia NuGet packages (both are currently in preview).
We use SkiaSharp to create a canvas, but importantly that canvas implements Microsoft.Maui.Graphics.ICanvas
(it’s not Skia-specific) so all the methods that draw on it can be agnostic to which rendering system was used. This makes it easy to write generic rendering methods now and have the option to switch the rendering system later.
Program.cs
using System;
using System.IO;
using Microsoft.Maui.Graphics;
using Microsoft.Maui.Graphics.Skia;
// Use Skia to create a Maui graphics context and canvas
BitmapExportContext bmpContext = SkiaGraphicsService.Instance.CreateBitmapExportContext(600, 400);
SizeF bmpSize = new(bmpContext.Width, bmpContext.Height);
ICanvas canvas = bmpContext.Canvas;
// Draw on the canvas with abstract methods that are agnostic to the renderer
ClearBackground(canvas, bmpSize, Colors.Navy);
DrawRandomLines(canvas, bmpSize, 1000);
DrawBigTextWithShadow(canvas, "This is Maui.Graphics with Skia");
SaveFig(bmpContext, Path.GetFullPath("quickstart.jpg"));
static void ClearBackground(ICanvas canvas, SizeF bmpSize, Color bgColor)
{
canvas.FillColor = Colors.Navy;
canvas.FillRectangle(0, 0, bmpSize.Width, bmpSize.Height);
}
static void DrawRandomLines(ICanvas canvas, SizeF bmpSize, int count = 1000)
{
Random rand = new();
for (int i = 0; i < count; i++)
{
canvas.StrokeSize = (float)rand.NextDouble() * 10;
canvas.StrokeColor = new Color(
red: (float)rand.NextDouble(),
green: (float)rand.NextDouble(),
blue: (float)rand.NextDouble(),
alpha: .2f);
canvas.DrawLine(
x1: (float)rand.NextDouble() * bmpSize.Width,
y1: (float)rand.NextDouble() * bmpSize.Height,
x2: (float)rand.NextDouble() * bmpSize.Width,
y2: (float)rand.NextDouble() * bmpSize.Height);
}
}
static void DrawBigTextWithShadow(ICanvas canvas, string text)
{
canvas.FontSize = 36;
canvas.FontColor = Colors.White;
canvas.SetShadow(offset: new SizeF(2, 2), blur: 1, color: Colors.Black);
canvas.DrawString(text, 20, 50, HorizontalAlignment.Left);
}
static void SaveFig(BitmapExportContext bmp, string filePath)
{
bmp.WriteToFile(filePath);
Console.WriteLine($"WROTE: {filePath}");
}
MauiGraphicsDemo.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Maui.Graphics" Version="6.0.100-preview.6.299" />
<PackageReference Include="Microsoft.Maui.Graphics.Skia" Version="6.0.100-preview.6.299" />
</ItemGroup>
</Project>