Skip to content

Instantly share code, notes, and snippets.

@kant2002
Last active November 6, 2022 14:54
Show Gist options
  • Save kant2002/ccda367b8e795f37d25ad735b0531b9a to your computer and use it in GitHub Desktop.
Save kant2002/ccda367b8e795f37d25ad735b0531b9a to your computer and use it in GitHub Desktop.
Headless Avalonia
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Avalonia.Headless" Version="11.0.0-preview3" />
<PackageReference Include="Avalonia" Version="11.0.0-preview3" />
<PackageReference Include="Avalonia.Skia" Version="11.0.0-preview3" />
<PackageReference Include="SkiaSharp" Version="2.88.3" />
</ItemGroup>
</Project>
//#r "nuget: Avalonia.Headless, 11.0.0-preview3"
//#r "nuget: Avalonia, 11.0.0-preview3"
//#r "nuget: Avalonia.Skia, 11.0.0-preview3"
//#r "nuget: SkiaSharp, 2.88.3"
using Avalonia.Themes.Fluent;
using SkiaSharp;
var builder = AppBuilder
.Configure<App>()
.UseSkia()
.UseHeadless(new() { UseCompositor = true, UseHeadlessDrawing = false });
// This initialization logic should be part of kernel probably. I canot execute this method just once inside single AppContext
builder.SetupWithoutStarting();
var window = CreateWindow();
window.Show();
// Get render target.
var renderRoot = (IRenderRoot)window;
var renderTarget = renderRoot.CreateRenderTarget();
ImmediateRenderer.Render(window, renderTarget);
var headlessWindow = (IHeadlessWindow)window.PlatformImpl!;
var lastRenderedFrame = headlessWindow.GetLastRenderedFrame();
var lockedFramebuffer = lastRenderedFrame.Item.Lock();
WriteImage(lockedFramebuffer, "test.png");
void WriteImage(ILockedFramebuffer framebuffer, string fileName)
{
var imageInfo = new SKImageInfo(framebuffer.Size.Width, framebuffer.Size.Height, SKColorType.Rgba8888, SKAlphaType.Opaque);
var _bitmap = SKImage.FromPixelCopy(imageInfo, framebuffer.Address);
var data = _bitmap.Encode();
using var file = File.OpenWrite(fileName);
data.SaveTo(file);
file.Flush();
}
Window CreateWindow()
{
var window = new HeadlessWindow();
var grid = new Grid();
grid.HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Center;
grid.VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center;
grid.Children.Add(new Button() { Content = "Hello Headless Avalonia" });
window.Content = grid;
window.Resize(new Size(200, 100));
return window;
}
class HeadlessWindow : Window
{
public void Resize(Size newSize)
{
ClientSize = newSize;
PlatformImpl!.GetType().GetMethod("DoResize", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.InvokeMethod)!
.Invoke(PlatformImpl, new object[] { newSize });
}
}
class App : Application
{
public override void Initialize()
{
var theme = new FluentTheme(new Uri("avares://AvaloniaHeadlessConsoleApp"));
theme.Mode = FluentThemeMode.Light;
Styles.Add(theme);
base.Initialize();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment