The InkCanvas control for .NET applications, such as Avalonia, providing a versatile canvas for handwriting and drawing.
书写笔迹画板
| Build | NuGet |
|---|---|
This project originated from: AvaloniaUI/Avalonia#1477
-
Install the NuGet package
DotNetCampus.AvaloniaInkCanvas<ItemGroup> <PackageReference Include="DotNetCampus.AvaloniaInkCanvas" Version="1.0.0-alpha.2" /> </ItemGroup>
-
Use the
InkCanvascontrol in XAML:xmlns:inking="using:DotNetCampus.Inking" <inking:InkCanvas x:Name="InkCanvas"/>
-
Switch input modes in code:
// Switch to ink mode InkCanvas.EditingMode = InkCanvasEditingMode.Ink; // Switch to eraser mode InkCanvas.EditingMode = InkCanvasEditingMode.EraseByPoint;
Q: Does this library support AOT (Ahead-Of-Time) compilation?
A: Yes, this library supports AOT compilation. It has been tested and confirmed to work correctly in AOT environments.
Q: Can this library be used in Linux environments?
A: Yes, this library can be used in Linux environments. It is built on Avalonia and SkiaSharp, which are cross-platform frameworks that support Linux.
Q: Can I directly use this library to create a high-performance handwriting whiteboard application?
A: No, due to the rendering performance limitations of Avalonia, this library cannot currently be used to create high-performance handwriting whiteboard applications. If you need a high-performance handwriting whiteboard application, it is recommended to add a WPF acceleration layer on the Windows platform to use WPF for rendering strokes to improve performance; on the Linux platform, use native X11 rendering to enhance performance. For related discussions, please refer to AvaloniaUI/Avalonia#18702
The library includes the following stroke renderers by default:
SimpleInkRender: A simple and fast stroke renderer suitable for most scenarios. It uses a straightforward algorithm and performs well, but in some input cases strokes may showaliasing.WpfForSkiaInkStrokeRenderer: A renderer that uses WPF's stroke rendering algorithm adapted for Skia. It provides higher-quality strokes at the cost of performance. Its implementation is based on the WPF open-source codebase and is more complex.
Example of switching the stroke renderer:
AvaloniaSkiaInkCanvasSettings settings = InkCanvas.SkiaInkCanvas.Settings;
// Use the WPF-based stroke renderer
settings.InkStrokeRenderer = new WpfForSkiaInkStrokeRenderer();
// Revert to the default (simple) stroke renderer
settings.InkStrokeRenderer = null;Note: Using WpfForSkiaInkStrokeRenderer only utilizes the stroke rendering algorithm from the WPF open-source repository and does not depend on the WPF framework itself.
InkCanvas.StrokeCollected += (o, args) =>
{
var addedStroke = args.SkiaStroke; // Use addedStroke as needed
}; InkCanvas.StrokeErased += (o, args) =>
{
foreach (ErasedSkiaStroke erasedSkiaStroke in args.ErasingSkiaStrokeList)
{
if (erasedSkiaStroke.IsErased)
{
// The stroke was erased; it may be split into multiple new strokes,
// or it may be fully erased resulting in 0 new strokes.
IReadOnlyList<SkiaStroke> newStrokes = erasedSkiaStroke.NewStrokeList;
foreach (var skiaStroke in newStrokes)
{
// Process each resulting stroke segment
}
}
else
{
// The stroke was not erased; it remains unchanged
SkiaStroke originalStroke = erasedSkiaStroke.OriginStroke;
}
}
};Control eraser behavior via AvaloniaSkiaInkCanvasSettings, for example:
AvaloniaSkiaInkCanvasSettings settings = InkCanvas.SkiaInkCanvas.Settings;
settings.EraserSize = new Size(100, 200);- Create a custom eraser control by inheriting from
Controland implementing theIEraserViewinterface. - Assign a delegate that creates an instance of your custom eraser control to the
EraserViewCreatorproperty ofInkCanvas.AvaloniaSkiaInkCanvas.Settings.
Example code:
internal class CustomEraserView : Control, IEraserView
{
...
}
var settings = InkCanvas.AvaloniaSkiaInkCanvas.Settings;
settings.EraserViewCreator = new DelegateEraserViewCreator(() => new CustomEraserView());Note: You cannot dynamically change the EraserViewCreator property during usage; it should only be set during initialization. Ensure to set this property before any eraser views are created.
You can export the strokes drawn on the InkCanvas to an SVG image format. Here's an example of how to do this:
private void SaveStrokeAsSvgButton_OnClick(object? sender, RoutedEventArgs e)
{
var saveFolder = Path.Join(AppContext.BaseDirectory, $"{DateTime.Now:yyyy-MM-dd_HH-mm-ss}");
Directory.CreateDirectory(saveFolder);
using var skPaint = new SKPaint();
skPaint.IsAntialias = true;
skPaint.Style = SKPaintStyle.Fill;
for (var i = 0; i < InkCanvas.Strokes.Count; i++)
{
var saveSvgFile = Path.Join(saveFolder, $"{i}.svg");
using var fileStream = File.Create(saveSvgFile);
var stroke = InkCanvas.Strokes[i];
var bounds = InkCanvas.Bounds.ToSKRect();
using var skCanvas = SKSvgCanvas.Create(bounds, fileStream);
skPaint.Color = stroke.Color;
skCanvas.DrawPath(stroke.Path, skPaint);
}
}If you would like to contribute, feel free to create a Pull Request, or give us Bug Report.
