Clear the drawings in SKCanvas(SkiaSharp) in Xamarin Forms

stezmastezpetstezmastezpet USMember ✭✭
edited July 9 in SkiaSharp

I have created a custom control for capturing the signature in Xamarin forms using SkiaSharp Library. In the Xaml I have added the below code.

<ContentView.Content>
    <Grid BackgroundColor="White">
        <skia:SKCanvasView x:Name="canvasView" PaintSurface="OnCanvasViewPaintSurface" />
        <Grid.Effects>
            <tt:TouchEffect Capture="True" TouchAction="OnTouchEffectAction" />
        </Grid.Effects>
    </Grid>
</ContentView.Content>

And in the implementation I have added the below code.

 public partial class SignaturePad : ContentView
 {
    #region Local Declarations

    readonly Dictionary<long, FingerPaintPolyline> _inProgressPolylines = new Dictionary<long, FingerPaintPolyline>();
    private readonly List<FingerPaintPolyline> _completedPolylines = new List<FingerPaintPolyline>();
    TouchActionType _currentAction = TouchActionType.Pressed;
    private SKCanvas _canvas;
    private readonly SKPaint _paint = new SKPaint
    {
        Style = SKPaintStyle.Stroke,
        Color = SKColors.Blue,
        StrokeWidth = 0.1f,
        StrokeCap = SKStrokeCap.Round,
        StrokeJoin = SKStrokeJoin.Round
    };
    #endregion

    #region Bindable Properties
    public ICommand Command
    {
        get => (ICommand)GetValue(CommandProperty);
        set => SetValue(CommandProperty, value);
    }
    public static readonly BindableProperty CommandProperty =
      BindableProperty.Create("Command", typeof(ICommand), typeof(SignaturePad));

    /// <summary>
    /// Gets or sets a value indicating whether empty field is enabled or disabled.
    /// </summary>
    /// <value><c>true</c> if is expanded; otherwise, <c>false</c>.</value>
    public bool IsEmptyField
    {
        get => (bool)GetValue(IsEmptyFieldProperty);
        set => SetValue(IsEmptyFieldProperty, value);

    }
    public static readonly BindableProperty IsEmptyFieldProperty =
        BindableProperty.Create(nameof(IsEmptyField), typeof(bool), typeof(SignaturePad), false, propertyChanged: OnEpmtyField);
    #endregion

    #region ctor
    public SignaturePad()
    {
        InitializeComponent();
    }
    #endregion

    #region Events
    /// <summary>
    /// Property changed even that clear the signature from the canvas 
    /// </summary>
    /// <param name="bindableObject"></param>
    /// <param name="oldValue"></param>
    /// <param name="newValue"></param>
    private static void OnEpmtyField(BindableObject bindableObject, object oldValue, object newValue)
    {

    }

    void OnTouchEffectAction(object sender, TouchActionEventArgs args)
    {
        _currentAction = args.Type;
        switch (args.Type)
        {
            case TouchActionType.Pressed:
                if (!_inProgressPolylines.ContainsKey(args.Id))
                {
                    var strokeColor = Color.Black;
                    var strokeWidth = ConvertToPixel(1);

                    var polyline = new FingerPaintPolyline
                    {
                        StrokeColor = strokeColor,
                        StrokeWidth = strokeWidth
                    };
                    polyline.Path.MoveTo(ConvertToPixelUsingPoint(new Point { X = args.Location.X, Y = args.Location.Y }));

                    _inProgressPolylines.Add(args.Id, polyline);
                    canvasView.InvalidateSurface();
                }
                break;
            case TouchActionType.Moved:
                if (_inProgressPolylines.ContainsKey(args.Id))
                {
                    var polyline = _inProgressPolylines[args.Id];
                    polyline.Path.LineTo(ConvertToPixelUsingPoint(new Point { X = args.Location.X, Y = args.Location.Y }));
                    canvasView.InvalidateSurface();
                }
                break;
            case TouchActionType.Released:
                if (_inProgressPolylines.ContainsKey(args.Id))
                {
                    _completedPolylines.Add(_inProgressPolylines[args.Id]);
                    _inProgressPolylines.Remove(args.Id);
                    canvasView.InvalidateSurface();
                }
                break;
            case TouchActionType.Cancelled:
                if (_inProgressPolylines.ContainsKey(args.Id))
                {
                    _inProgressPolylines.Remove(args.Id);
                    canvasView.InvalidateSurface();
                }
                break;
        }
    }

    void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
    {

        _canvas = args.Surface.Canvas;
        _canvas.Clear(SKColors.White);

        foreach (var polyline in _completedPolylines)
        {
            _paint.Color = polyline.StrokeColor.ToSKColor();
            _paint.StrokeWidth = polyline.StrokeWidth;
            _canvas.DrawPath(polyline.Path, _paint);
        }

        foreach (var polyline in _inProgressPolylines.Values)
        {
            _paint.Color = polyline.StrokeColor.ToSKColor();
            _paint.StrokeWidth = polyline.StrokeWidth;
            _canvas.DrawPath(polyline.Path, _paint);
        }

        if (_currentAction == TouchActionType.Released)
        {
            var skImage = args.Surface.Snapshot();
            var skData = skImage.Encode(SKEncodedImageFormat.Jpeg, 100);
            var imageStream = skData.AsStream(true);
            var buffer = new byte[16 * 1024];
            var ms = new MemoryStream();
            int read;
            while ((read = imageStream.Read(buffer, 0, buffer.Length)) > 0)
            {
                ms.Write(buffer, 0, read);
            }
            var imageArray = DependencyService.Get<IPicture>().RotateImage(ms.ToArray(), 6);
            Command?.Execute(imageArray);
        }
    }
    #endregion

    #region Private Methods

    float ConvertToPixel(float fl)
    {
        return (float)(canvasView.CanvasSize.Width * fl / canvasView.Width);
    }

    SKPoint ConvertToPixelUsingPoint(Point pt)
    {
        return new SKPoint((float)(canvasView.CanvasSize.Width * pt.X / (canvasView.Width)),
                           (float)(canvasView.CanvasSize.Height * pt.Y / (canvasView.Height)));

    }

    #endregion
}
}

By using this code, I was able to draw and take the print of the signature. But I would like to clear the entire drawing / signature when a button click.
How can I achieve the same using SkiaSharp.

Sign In or Register to comment.