Skip to main content

Manipulation of Digital Ink

Manipulations are handled differently for Vector and Raster Ink. Vector manipulations modify the generated geometry, while the raster eraser only "overdraws" the strokes.

Raster Ink

For Raster Ink so far only partial eraser functionality is offered.

Eraser

The eraser is configured as a tool, similar to the brush. This tool uses a specific blending mode BlendMode.DESTINATION_OUT to erase the strokes by overlapping them.

import com.wacom.ink.Calculator
import com.wacom.ink.PathPoint
import com.wacom.ink.PathPointLayout
import com.wacom.ink.rendering.BlendMode
...

class EraserRasterTool(context: Context) : RasterTool(context) {

companion object {
val uri = URIBuilder.getToolURI("raster", "eraser")
}

override var brush = BrushPalette.eraser(context)

override fun getLayout(): PathPointLayout {
return PathPointLayout(
PathPoint.Property.X,
PathPoint.Property.Y,
PathPoint.Property.SIZE,
PathPoint.Property.RED,
PathPoint.Property.GREEN,
PathPoint.Property.BLUE,
PathPoint.Property.ALPHA
)
}

override val touchCalculator: Calculator = { previous, current, next ->
// Use the following to compute size based on speed:
var size = current.computeValueBasedOnSpeed(
previous,
next,
minValue = 8f,
maxValue = 112f,
minSpeed = 720f,
maxSpeed = 3900f
)
if (size == null) size = 8f

PathPoint(current.x, current.y, size = size,
red = 1f, green = 1f, blue = 1f, alpha = 1f)
}

override val stylusCalculator: Calculator = { previous, current, next ->
// Use the following to compute size based on speed:
var size = current.computeValueBasedOnSpeed(
previous,
next,
minValue = 8f,
maxValue = 112f,
minSpeed = 720f,
maxSpeed = 3900f
)
if (size == null) size = 8f

PathPoint(current.x, current.y, size = size,
red = 1f, green = 1f, blue = 1f, alpha = 1f)
}

override fun getBlendMode(): BlendMode {
return BlendMode.DESTINATION_OUT
}

}

Note: Strokes are not removed from the model, just overdrawn.

Vector Ink

Vector ink offers more capabilities of manipulating strokes with:

  • Partial stroke eraser
  • Whole stroke eraser
  • Manipulation options

Partial Eraser / Splitter

The eraser tool works in a similar way to the brush tools. Thus, you need to define its calculators. Here, you can decide if the width of the eraser changes with more pressure or with more speed. Moreover, you can define a different behavior for finger or stylus input.

class EraserVectorTool : VectorTool() {

companion object {
val uri = "tool@erase_vector"
}

override var brush = BrushPalette.circle()

override fun getLayout(): PathPointLayout {
return PathPointLayout(
PathPoint.Property.X,
PathPoint.Property.Y,
PathPoint.Property.SIZE,
PathPoint.Property.RED,
PathPoint.Property.GREEN,
PathPoint.Property.BLUE
)
}

override var drawingMode = DrawingMode.ERASING_PARTIAL_STROKE

override val touchCalculator: Calculator = { previous, current, next ->
// Use the following to compute size based on speed:
var size = current.computeValueBasedOnSpeed(
previous,
next,
minValue = 8f,
maxValue = 112f,
minSpeed = 720f,
maxSpeed = 3900f
)
if (size == null) size = 1.0f
PathPoint(current.x, current.y, size = size, red = 1f, green = 1f, blue = 1f, alpha = 0.5f)
}

override val stylusCalculator: Calculator = { previous, current, next ->
// Use the following to compute size based on speed:
var size = current.computeValueBasedOnSpeed(
previous,
next,
minValue = 8f,
maxValue = 112f,
minSpeed = 720f,
maxSpeed = 3900f
)
if (size == null) size = 1.0f
PathPoint(current.x, current.y, size = size, red = 1f, green = 1f, blue = 1f)
}
}

Whole Stroke Eraser


class EraserWholeStrokeTool : VectorTool() {

companion object {
val uri = URIBuilder.getToolURI("vector", "eraser_whole_stroke")
}

override var brush = BrushPalette.basic()

override fun getLayout(): PathPointLayout {
return PathPointLayout(
PathPoint.Property.X,
PathPoint.Property.Y,
PathPoint.Property.SIZE
)
}

override var drawingMode = DrawingMode.ERASING_WHOLE_STROKE

override val touchCalculator: Calculator = { previous, current, next ->
//Use the following to compute size based on speed:
PathPoint(current.x, current.y, size = 3f)
}

override val stylusCalculator: Calculator = { previous, current, next ->
//Use the following to compute size based on speed:
PathPoint(current.x, current.y, size = 3f)
}
}

Selection

If you need to manipulate ink strokes with operations such as:

  • Translation
  • Rotation
  • Scale

you mostly use a lasso tool to select either parts of the stroke or whole strokes. With the technology we differentiate between partial selection and whole stroke selection.

Partial Selection

Again we need to define tools.

class SelectorPartialStrokeTool : VectorTool() {

companion object {
val uri = "tool@selector_parcial_stroke"
}

override var brush = BrushPalette.basic()

override fun getLayout(): PathPointLayout {
return PathPointLayout(
PathPoint.Property.X,
PathPoint.Property.Y,
PathPoint.Property.SIZE,
PathPoint.Property.RED,
PathPoint.Property.GREEN,
PathPoint.Property.BLUE
)
}

override var drawingMode = DrawingMode.SELECTING_PARTIAL_STROKE

override val touchCalculator: Calculator = { previous, current, next ->
// Use the following to compute size based on speed:
PathPoint(current.x, current.y, size = 3f, red = 1f, green = 1f, blue = 1f)
}

override val stylusCalculator: Calculator = { previous, current, next ->
// Use the following to compute size based on speed:
PathPoint(current.x, current.y, size = 3f, red = 1f, green = 1f, blue = 1f)
}
}

Whole Stroke Selector

class SelectorWholeStrokeTool : VectorTool() {

companion object {
val uri = "tool@selector_whole_stroke"
}

override var brush = BrushPalette.basic()

override fun getLayout(): PathPointLayout {
return PathPointLayout(
PathPoint.Property.X,
PathPoint.Property.Y,
PathPoint.Property.SIZE,
PathPoint.Property.RED,
PathPoint.Property.GREEN,
PathPoint.Property.BLUE
)
}

override var drawingMode = DrawingMode.SELECTING_WHOLE_STROKE

override val touchCalculator: Calculator = { previous, current, next ->
//Use the following to compute size based on speed:
PathPoint(current.x, current.y, size = 3f, red = 1f, green = 1f, blue = 1f)
}

override val stylusCalculator: Calculator = { previous, current, next ->
//Use the following to compute size based on speed:
PathPoint(current.x, current.y, size = 3f, red = 1f, green = 1f, blue = 1f)
}
}