Working with ink annotation in Xamarin.Android PDF Viewer

17 Mar 202221 minutes to read

PDF viewer allows you to include ink annotation in the PDF document and provides options to edit or remove the existing ink annotation in the PDF document.

Inclusion of ink annotation

This section describes how to include ink annotation in PDF viewer control Xamarin.Android.

Enabling ink annotation mode

Set the AnnotationMode property of the PDF viewer object to ink to enable the ink annotation. By setting this, zooming and scrolling will be disabled and touch interactions will be converted into inks on the PDF pages. Refer to the following code.

SfPdfViewer pdfViewer = new SfPdfViewer();
pdfViewer.AnnotationMode = AnnotationMode.Ink;

Use the following code to reset the annotation mode to none.

SfPdfViewer pdfViewer = new SfPdfViewer();
pdfViewer.AnnotationMode = AnnotationMode.None;

Adding ink annotation using toolbar

Steps involved in adding ink annotation to the PDF document:

  1. Switch to ink annotation mode.
  2. Add inks to the pages of the PDF document, this will be recorded as a session.
  3. You can perform undo and redo operations for every stroke made in the session.
  4. You can also choose the color and thickness of the ink, here color and thickness are restricted to the complete ink and not individual strokes.
  5. After adding ink annotation, you can either accept or discard the changes.

How to accept and include the ink annotation on to the PDF viewer?

The following code can be used to accept and include the drawn ink annotation to the PDF viewer control.

pdfViewer.EndInkSession(true);

How to ignore/discard drawn ink annotation from the PDF viewer before inclusion?

The following code can be used to ignore or discard the drawn ink annotation to the PDF viewer control.

pdfViewer.EndInkSession(false);

Adding ink annotation programmatically

By AddAnnotation method, You can add the ink annotations programmatically. The created ink annotation object passed as a parameter. The InkAnnotation instance acquires the InkPointsCollection, page number and position as the parameters.

The following code sample illustrates the same.

var inkPointsCollection = new List<List<float>>();

inkPointsCollection.Add(new List<float> { 53f, 525f, 53f, 527f, 53f, 528f, 53f, 531f, 53f, 549f, 54f, 570f, 56f, 597f, 57f, 623f, 59f, 652f, 60f, 679f, 62f, 705f, 64f, 726f, 65f, 744f, 66f, 758f, 66f, 768f, 65f, 777f, 65f, 782f, 65f, 784f, 64f, 786f, 64f, 786f, 63f, 786f, 63f, 786f, 63f, 784f, 66f, 774f, 71f, 757f, 79f, 734f, 88f, 708f, 99f, 681f, 112f, 652f, 126f, 627f, 140f, 606f, 150f, 591f, 158f, 582f, 162f, 578f, 164f, 577f, 165f, 576f, 166f, 576f, 165f, 578f, 155f, 592f, 143f, 605f, 121f, 621f, 99f, 631f, 77f, 639f, 54f, 644f, 35f, 645f, 20f, 644f, 10f, 642f, 4f, 642f, 2f, 641f, 1f, 640f, 0f, 639f, 0f, 639f, 2f, 639f, 20f, 645f, 47f, 657f, 75f, 672f, 106f, 688f, 137f, 704f, 168f, 718f, 197f, 732f, 221f, 741f, 240f, 748f, 254f, 753f, 254f, 753f });

Android.Graphics.Point position = new Android.Graphics.Point(100, 100);
InkAnnotation inkAnnotation = new InkAnnotation(inkPointsCollection, 1, position);
inkAnnotation.Settings.Color = Android.Graphics.Color.Red;     
      
//Adds the ink annotation to the specified page 
pdfViewer.AddAnnotation(inkAnnotation);

How to identify whether the ink annotation is included?

You can identify whether the drawn ink annotation has been added to the PDF viewer control or not by using the InkAdded event. This event will be raised once the annotation is added.

SfPdfViewer pdfViewer = new SfPdfViewer();
pdfViewer.InkAdded`+= pdfViewer_InkAdded;
private void pdfViewer_InkAdded(object sender, InkAddedEventArgs args)
{
    //Retrieves the bounds of the deselected annotation.
    Rectangle bounds = args.Bounds;

    //Retrieves the page number where the deselected annotation resides.
    int pageNumber = args.PageNumber;

    //Retrieves the color of the deselected annotation.
    Color color = args.Color;

    //Retrieves the thickness of the deselected annotation.
    float thickness = args.Thickness;

    //Retrieves the opacity of the deselected annotation.
    float opacity = args.Opacity;

}

How to perform undo and redo operation during inking session?

You can perform undo and redo operations on the drawn ink annotations during the pre-conformance session.

The following code can be used to perform undo operation on the ink annotations drawn over the PDF viewer control.

pdfViewer.UndoInk();

You can identify the undo operation in this session using the following event.

SfPdfViewer pdfViewer = new SfPdfViewer();
pdfViewer.CanUndoInkModified += PdfViewer_CanUndoInkModified;
private void PdfViewer_CanUndoInkModified(object sender, CanUndoInkModifiedEventArgs args)
{
    bool canUndoInk = args.CanUndoInk;
}

The following code can be used to perform redo operation on the ink annotations drawn over the PDF viewer control.

pdfViewer.RedoInk();

You can identify the redo operation in this session using the following event.

SfPdfViewer pdfViewer = new SfPdfViewer();
pdfViewer.CanRedoInkModified += PdfViewer_CanRedoInkModified;
private void PdfViewer_CanRedoInkModified(object sender, CanRedoInkModifiedEventArgs args)
{
   bool CanRedoInk = args.CanRedoInk;
}

Deleting ink annotation

The PDF viewer can remove a selected annotation or all the annotations in the PDF document.

Removing a selected annotation.

The following code snippet illustrates removing a selected annotation from the PDF document.

SfPdfViewer pdfViewer = new SfPdfViewer();
pdfViewer.InkSelected	+= PdfViewer_InkSelected;
private void PdfViewer_InkSelected(object sender, InkSelectedEventArgs args)
{
    //Casts the sender object as Ink annotation.
    InkAnnotation selectedInkAnnotation = sender as InkAnnotation;

    //Removes the selected annotation from the PDF viewer.
    pdfViewer.RemoveAnnotation(selectedInkAnnotation);
}

How to identify the removal of ink annotation?

You can identify removal of ink annotation using the InkRemoved event, which is available in the PDF viewer control. This event will be raised when you remove the ink annotation from the PDF viewer control.

The following C# code shows how to acquire bounds, page number, color, thickness, and opacity of the removed ink annotation.

SfPdfViewer pdfViewer = new SfPdfViewer();
pdfViewer.InkRemoved+=PdfViewer_InkRemoved;
private void PdfViewer_InkRemoved(object sender, InkRemovedEventArgs args)
{

    //Retrieves the bounds of the deselected annotation.
    Rectangle bounds = args.Bounds;

    //Retrieves the page number where the deselected annotation resides.
    int pageNumber = args.PageNumber;

    //Retrieves the color of the deselected annotation.
    Color color = args.Color;

    //Retrieves the thickness of the deselected annotation.
    float thickness = args.Thickness;

    //Retrieves the opacity of the deselected annotation.
    float opacity = args.Opacity;
}

Working with ink annotation settings

You can customize the color, opacity, and thickness of the ink annotation.

Changing the color

You can set the color of the ink annotation by using the AnnotationSettings.Ink.Color property. Refer to the following code sample.

SfPdfViewer pdfViewer = new SfPdfViewer();

pdfViewer.AnnotationMode = AnnotationMode.Ink;

pdfViewer.AnnotationSettings.Ink.Color = Color.Red;

Changing the opacity

You can set the opacity of the ink annotation by using the AnnotationSettings.Ink.Opacity property. Opacity value ranges from 0 to 1. Refer to the following code example.

SfPdfViewer pdfViewer = new SfPdfViewer();

pdfViewer.AnnotationMode = AnnotationMode.Ink;

pdfViewer.AnnotationSettings.Ink.Opacity = 0.5f;

Changing the thickness

You can set the thickness of the ink annotation by using the AnnotationSettings.Ink.Thickness property. Refer to the following code example.

SfPdfViewer pdfViewer = new SfPdfViewer();

pdfViewer.AnnotationMode = AnnotationMode.Ink;

pdfViewer.AnnotationSettings.Ink.Thickness = 5;

Changing the minimum size

By the AnnotationSettings.Ink.MinimumSize property, You can set the minimum size to which the ink annotations could be resized.

Refer the following code example:

//Sets the minimum size for the ink annotations
pdfViewer.AnnotationSettings.Ink.MinimumSize = new Size(10, 10);

How to select the ink annotation?

You can select the ink annotation by tapping the annotation.

Select the ink annotation programmatically

By SelectAnnotation method, You can select the ink annotation programmatically. The specified ink annotation object passed as a parameter. The following code example explains the same.

//Selects the specified ink annotation
pdfViewer.SelectAnnotation(inkAnnotation);

NOTE

Once SelectAnnotation method is called and as long as the annotation stays selected, the SelectedAnnotation property will return the same instance as the parameter of this method.

How to change the properties of ink annotation after selection?

You can select and change the properties of the ink annotation using the InkSelected event. This event will be raised when you select the ink annotation. This is illustrated in the following code sample.

SfPdfViewer pdfViewer = new SfPdfViewer();
pdfViewer.InkSelected += PdfViewer_InkSelected;

You can change the properties of the selected annotation using the InkSelectedEventArgs object. The following code shows how to change the properties of the selected annotation in the InkSelectedEventHandler.

private void PdfViewer_InkSelected(object sender, InkSelectedEventArgs args)
{
    //Casts the sender object as Ink annotation.
    InkAnnotation selectedInkAnnotation = sender as InkAnnotation;

    //Sets the color of the selected annotation using ink annotation settings.
    selectedInkAnnotation.Settings.Color = Color.Blue;

    //Sets the opacity of the selected annotation using ink annotation settings.
    selectedInkAnnotation.Settings.Opacity = 0.3f;

    //Sets the thickness of the selected annotation using ink annotation settings.
    selectedInkAnnotation.Settings.Thickness = 3;
}

You can identify whether the ink annotation is tapped or not using theInkTapped event. This event will be triggered if you tap the ink annotation whether to select or deselect the annotation.

SfPdfViewer pdfViewer = new SfPdfViewer();
pdfViewer.InkTapped += PdfViewer_InkTapped;
private void PdfViewer_InkTapped(object sender, InkTappedEventArgs args)
{
    //Retrieves the bounds of the deselected annotation.
    Rectangle bounds = args.Bounds;

    //Retrieves the page number where the deselected annotation resides.
    int pageNumber = args.PageNumber;

    //Retrieves the color of the deselected annotation.
    Color color = args.Color;

    //Retrieves the thickness of the deselected annotation.
    float thickness = args.Thickness;

    //Retrieves the opacity of the deselected annotation.
    float opacity = args.Opacity;
}

How to deselect the ink annotation?

You can deselect the ink annotation by tapping on the selected annotation or on the PDF page. Deselection can be identified using the InkDeselected event.

SfPdfViewer pdfViewer = new SfPdfViewer();
pdfViewer.InkDeselected += PdfViewer_InkDeselected;

The following code shows how to identify the deselected annotation from the raised event.

private void PdfViewer_InkDeselected(object sender, InkDeselectedEventArgs args)
{ 
   //Retrieves the bounds of the deselected annotation.
   Rectangle bounds = args.Bounds;

   //Retrieves the page number where the deselected annotation resides.
   int page = args.PageNumber;

   //Retrieves the color of the deselected annotation.
   Color color = args.Color;

   //Retrieves the thickness of the deselected annotation.
   float thickness = args.Thickness;

   //Retrieves the opacity of the deselected annotation.
   float opacity = args.Opacity;
 
 }

Deselect the ink annotation programmatically

By DeselectAnnotation method, You can deselect the ink annotation programmatically. The specified ink annotation object passed as a parameter.

The following code Sample illustrates the same.

//Deselects the specified ink annotation
pdfViewer.DeselectAnnotation(inkAnnotation);

NOTE

There is no effect in calling DeselectAnnotation method if the given annotation is not selected. Once this method is called, the SelectedAnnotation property will return null until any other annotation gets selected.

How to move or resize the selected ink annotation?

Select and drag the annotation to move or resize the ink annotation.

How to identify whether the ink annotation is moved or resized?

The event AnnotationMovedOrResized will be raised when you move or resize the selected annotation.

SfPdfViewer pdfViewer = new SfPdfViewer();
pdfViewer.AnnotationMovedOrResized += PdfViewer_AnnotationMovedOrResized;
private void PdfViewer_AnnotationMovedOrResized(object sender, AnnotationMovedOrResizedEventArgs args) 
{
     //Retrieves the old bounds of the annotation
     Rectangle oldBounds = args.OldBounds;

     //Retrieves the new bounds of the annotation
     Rectangle newBounds = args.NewBounds;
}

How to lock or unlock the ink annotations?

To lock or unlock all the ink annotation, set the IsLocked API to true or false respectively, and the following sample explains the same. But other annotation types can be moved, resized, removed or their attributes can be changed.

//Disable the ink annotation interaction such as move, resize, remove, and attributes changes.
pdfViewerControl.AnnotationSettings.Ink.IsLocked = true;

Interactions with ink annotation types such as move, resize, remove or attribute changes will be allowed only if the SfPdfViewer.AnnotationSettings.IsLocked API is set to false. The following code prevents the unlocking of the ink annotations, although the IsLocked property of the ink annotation is set to false.

//Disable the ink annotation interaction, though its 'IsLocked' property is set to ‘false’ .
pdfViewerControl.AnnotationSettings.IsLocked = true;
pdfViewerControl.AnnotationSettings.Ink.IsLocked = false;

How to enable or disable the ink annotation selection?

To enable or disable the ink annotation selection, set the Constraints API to AnnotationConstraints.Selectable or ~AnnotationConstraints.Selectable respectively, and the following sample explains the same. But other annotation types can be selected, moved, resized, removed or their attributes can be changed.

//Disable the selection of ink annotations.
pdfViewerControl.AnnotationSettings.Ink.Constraints = ~AnnotationConstraints.Selectable;

Ink annotation selection will be allowed only if the SfPdfViewer.AnnotationSettings.Constraints API is set to AnnotationConstraints.Selectable. The following code prevents the ink annotations selection, even though the Constraints property of the ink annotation is set to AnnotationConstraints.Selectable.

//Disable the ink annotation selection, though its 'Constraints' property is set to ‘AnnotationConstraints.Selectable’ 
pdfViewerControl.AnnotationSettings.Constraints= ~AnnotationConstraints.Selectable;
pdfViewerControl.AnnotationSettings.Ink.Constraints = AnnotationConstraints.Selectable;

How to render Ink strokes using custom ink points?

By default, ink strokes are drawn by recording the points on the screen traversed by the input device (stylus or finger). The quality of the strokes thus drawn may not be satisfactory as it considers only raw points. If needed, the points can be modified using any algorithms to smoothen the strokes.

When the ink session ends after drawing the strokes, the InkAdded event will be raised. The InkAnnotation instance that is drawn on the page is exposed as sender argument of the InkAdded event. We can get the Ink points which we drew on the page from InkAnnotation.InkPointsCollection. The InkPointsCollection is of a type List<List>. Each List in this collection represents each stroke of the ink annotation we drew. There are as many List instances in the [InkPointsCollection](https://help.syncfusion.com/cr/xamarin-android/Syncfusion.SfPdfViewer.Android.InkAnnotation.html#Syncfusion_SfPdfViewer_Android_InkAnnotation_InkPointsCollection) as the number of strokes in the ink annotation.

The List in turn, has the series of alternate X and Y coordinates of the ink stroke. i.e. the values at the odd position are X coordinates and at the even position are Y coordinates.

We can modify or add new stroke points in the InkAnnotation.InkPointsCollection. As soon as the InkAdded event handler completes execution, the modified points will be reflected in the ink annotation on the UI.

private void PdfViewerControl_InkAdded(object sender, InkAddedEventArgs args) 
{     
     InkAnnotation inkAnnotation = sender as InkAnnotation;         
 
     List<List<float>> drawnPoints = inkAnnotation.InkPointsCollection; 
 
     //Modify the drawn ink points 
     List<List<float>> modifiedPoints = PerformModification(drawnPoints); 
 
     inkAnnotation.InkPointsCollection = modifiedPoints; 
}

NOTE

The strokes cannot be smoothened when the user is drawing the strokes as the points are still being recorded. They can be smoothened only after the user confirms the end of the ink session.

How to get and set the name of the ink annotations?

The PDF Viewer allows the users to get and set the name of ink annotations through the Name API.

The following code sample explains modifying the name of the ink annotation in the InkAdded event.

private void PdfViewerControl_InkAdded(object sender, InkAddedEventArgs args)
{
   if(sender is InkAnnotation)
    {
    (sender as InkAnnotation).Name = "Ink1";
    }
}

NOTE

For illustration purposes, we have only provided the sample for modifying the name of the ink annotation in the InkAdded event. But this can be done in all other events as well.

How to change properties of each ink stroke separately

By default, when the ink annotation is drawn, all strokes that are drawn in the ink annotation mode before clicking the done button will be considered as a single ink annotation. All these strokes will be selected and their properties changed as a whole since they represent a single ink annotation.

You can change the properties of each ink stoke separately by setting the SfPdfViewer.AnnotationSettings.Ink.EnableSeparateAttributesForEachStroke API to true.

The following code sample explains the same.

pdfViewerControl.AnnotationSettings.Ink.EnableSeparateAttributesForEachStroke = true;