Annotate PDF documents on tablets with pressure sensitive input from a pen [Android / iOS]

Q: We are using the PDFTron library on Android to annotate PDF documents with input from a pen.
We are able to capture these pen events and use the freehand tool to draw on the pdf.

The pen on the device is pressure sensitive, meaning that for each MotionEvent, it is possible to extract a pressure value ( float 0 between 0.0 and 1.0), depending on how hard the pen has been pressed against the device.
This pressure must be reflected in the scribble - ie. the line should be thicker when the pressure is higher.
A primary requirement is that the line does not should not be drawn with sharp edges.
As I read the code, the Ink structure that is applied to the PDF is not able to draw this - so what can be an alternative route ?

I am thinking :

  • As each point is described by (x,y,pressure), the scribble could be drawn by
  • for each point, draw a circle with radius = pressure.
    +between all connected points, draw a polygon that stretches between the end points and cover the two closest halves of each end-point circle
  • OR render as a bitmap and apply
  • OR use some other data structure that would cover this functionality even better

related to this is it possible to render a scribble as a spline instead of a series of lines ? When using a pen as input, hard corners are not natural, and a spline rendering would feel and look much better. Do you have any experience or advice in this respect ? Ideally, it would be a spline drawn with pressure value for each point.

A: Based on the PDF specification, the closest one to your scribble use case is the Ink annotation. An Ink annotation is a sequence of line segments. If you really want it to look smooth, maybe you can try to fit a parametric curve along the scribbled points and sample the curve adaptively (more samples at locations with high curvature value)? Then you can pass these points down to PDFNet.

I recommend that you create a single ink (or polygon) annotation, but that you set a custom appearance on the annotation. For examples of how to do this, search for SetAppearance() in this forum. This way you will have a single logical annotation, but you have the flexibility of defining your own appearance. For example, you could generate a variable width stroke as a collection of filled circles. Instead of drawing each circle separately, you could specify a single point (moveto, lineto at the same point) and assign the line/stroke width corresponding to the pressure value. This way you will not run into self-intersection issue since each circle will be drawn separately on top of each other. Alternatively you can define you own poygon (that can include cubic curves) but with this apprach you are potentially running into poygon intersection issues.