| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119 | 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<double> LineThicknessProperty =        AvaloniaProperty.Register<InkCanvas, double>(nameof(LineThickness), 3.0);    public static readonly StyledProperty<Color> LineColourProperty =        AvaloniaProperty.Register<InkCanvas, Color>(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<Polyline> 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<Point>(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());        }    }}
 |