using Avalonia; using Avalonia.Controls; using Avalonia.Controls.Shapes; using Avalonia.Input; using Avalonia.Markup.Xaml; using Avalonia.Media; using Avalonia.Media.Imaging; using System.Collections.ObjectModel; namespace InABox.Avalonia.Components; public partial class InkCanvas : UserControl { public static readonly StyledProperty LineThicknessProperty = AvaloniaProperty.Register(nameof(LineThickness), 3.0); public static readonly StyledProperty LineColourProperty = AvaloniaProperty.Register(nameof(LineColour), Colors.Black); public double LineThickness { get => GetValue(LineThicknessProperty); set => SetValue(LineThicknessProperty, value); } public Color LineColour { get => GetValue(LineColourProperty); set => SetValue(LineColourProperty, value); } private ObservableCollection Lines = new(); private Polyline? CurrentLine; public event EventHandler? Changed; public InkCanvas() { InitializeComponent(); Lines.CollectionChanged += Lines_CollectionChanged; } public void Clear() { Canvas.Children.Clear(); Lines.Clear(); Changed?.Invoke(this, EventArgs.Empty); } public byte[] SaveImage() { var width = (int)Math.Floor(Canvas.Bounds.Width); var height = (int)Math.Floor(Canvas.Bounds.Height); var renderBitmap = new RenderTargetBitmap(new PixelSize(width, height)); using var context = renderBitmap.CreateDrawingContext(); foreach(var line in Lines) { line.Render(context); } using var stream = new MemoryStream(); renderBitmap.Save(stream); return stream.ToArray(); } private void Lines_CollectionChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) { Canvas.Children.Clear(); foreach(var line in Lines) { if (!Canvas.Children.Contains(line)) { Canvas.Children.Add(line); } } } Point ConvertToImageCoordinates(Point canvasCoordinates) { return canvasCoordinates; } private void Canvas_PointerPressed(object? sender, PointerPressedEventArgs e) { var position = ConvertToImageCoordinates(e.GetPosition(Canvas)); CurrentLine = new Polyline { Points = new ObservableCollection(new Point[] { position }), StrokeThickness = LineThickness, Stroke = new SolidColorBrush(LineColour), StrokeJoin = PenLineJoin.Round, StrokeLineCap = PenLineCap.Round }; Lines.Add(CurrentLine); } private void Canvas_PointerMoved(object? sender, PointerEventArgs e) { if(CurrentLine is not null) { var position = ConvertToImageCoordinates(e.GetPosition(Canvas)); CurrentLine.Points.Add(position); } } private void Canvas_PointerReleased(object? sender, PointerReleasedEventArgs e) { if(CurrentLine is not null) { var position = ConvertToImageCoordinates(e.GetPosition(Canvas)); CurrentLine.Points.Add(position); CurrentLine = null; Changed?.Invoke(this, new()); } } }