Search Docs
Loading...
Skip to content

Stroke Effect

Draw a brush stroke along the masks of a block with the stroke effect.

6 mins
estimated time
GitHub

The stroke effect draws a brush stroke along the path of a mask. It uses the same effect API as all other effects: createEffect, the property setters and appendEffect. Scenes that use this effect do not open in earlier versions of CE.SDK. The example draws three strokes along an ellipse mask: over the image, on a transparent block, and along half of the path. For the general effect API, see Apply a Filter or Effect.

Adding a Mask#

The stroke follows a mask, so each block needs a mask first. createMask creates the mask, setShape gives it an ellipse shape and appendMask attaches it to the block. A mask normally cuts the block to its shape. The "None" mode keeps the whole block and only gives the stroke its path. For more about masks, see Masks and Mattes.

// An ellipse mask in the "None" mode gives the stroke a path without cutting the block
fun addEllipseMask(block: DesignBlock) {
val mask = engine.block.createMask()
engine.block.setShape(block = mask, shape = engine.block.createShape(ShapeType.Ellipse))
engine.block.setEnum(block = mask, property = "mask/mode", value = "None")
engine.block.appendMask(block = block, maskBlock = mask)
}
addEllipseMask(overImageBlock)
addEllipseMask(transparentBlock)
addEllipseMask(halfStrokeBlock)

A mask in the default "Add" mode cuts the block to the ellipse. It also cuts the outer half of the stroke.

Drawing the Stroke#

color sets the stroke color. brushSize is the brush radius in design units, so the line is twice as wide. hardness sets how sharp the edge is, from 0 (soft) to 1 (hard). The stroke draws along the first mask of the block, because maskIndex is 0 by default.

// A hard yellow brush stroke, 12 design units wide, along the first mask
val stroke = engine.block.createEffect(EffectType.Stroke)
engine.block.setColor(block = stroke, property = "effect/stroke/color", value = Color.fromRGBA(r = 1F, g = 0.8F, b = 0.1F))
engine.block.setFloat(block = stroke, property = "effect/stroke/brushSize", value = 6F)
engine.block.setFloat(block = stroke, property = "effect/stroke/hardness", value = 1F)
engine.block.appendEffect(block = overImageBlock, effectBlock = stroke)

Choosing the Mask and the Paint Style#

maskIndex picks the mask to stroke. An index outside the mask list draws no stroke. Set allMasks to true to stroke every mask of the block. paintStyle is "OnOriginalImage" to draw over the fill, or "OnTransparent" to draw only the stroke. Here the second block shows only the yellow ring.

// Stroke every mask of the block, and draw only the stroke without the image
val transparentStroke = engine.block.createEffect(EffectType.Stroke)
engine.block.setBoolean(block = transparentStroke, property = "effect/stroke/allMasks", value = true)
engine.block.setEnum(block = transparentStroke, property = "effect/stroke/paintStyle", value = "OnTransparent")
engine.block.setColor(block = transparentStroke, property = "effect/stroke/color", value = Color.fromRGBA(r = 1F, g = 0.8F, b = 0.1F))
engine.block.setFloat(block = transparentStroke, property = "effect/stroke/brushSize", value = 6F)
engine.block.appendEffect(block = transparentBlock, effectBlock = transparentStroke)

Trimming the Stroke#

start and end draw only a part of each mask path, as fractions of its length from 0 to 1. A start after end swaps the two values. Here the third block gets half a ring.

// Draw only the first half of the mask path
val halfStroke = engine.block.createEffect(EffectType.Stroke)
engine.block.setInt(block = halfStroke, property = "effect/stroke/maskIndex", value = 0)
engine.block.setFloat(block = halfStroke, property = "effect/stroke/start", value = 0F)
engine.block.setFloat(block = halfStroke, property = "effect/stroke/end", value = 0.5F)
engine.block.setColor(block = halfStroke, property = "effect/stroke/color", value = Color.fromRGBA(r = 1F, g = 0.8F, b = 0.1F))
engine.block.setFloat(block = halfStroke, property = "effect/stroke/brushSize", value = 6F)
engine.block.appendEffect(block = halfStrokeBlock, effectBlock = halfStroke)

Exporting the Result#

We export the page as a PNG to see the three strokes.

val previewPng = engine.block.export(block = page, mimeType = MimeType.PNG)

Troubleshooting#

  • The stroke does not show: add a mask to the block, and check that maskIndex points to it. A brushSize of 0 also draws nothing.
  • The block shows only the inside of the mask: set mask/mode to "None".
  • The stroke is half as wide as expected: the mask is in the "Add" mode and cuts the outer half of the stroke. Set mask/mode to "None".

API Reference#

Method Description
engine.block.createMask() Create a mask for the stroke path
engine.block.createShape(type=ShapeType.Ellipse) Create the ellipse shape of the mask
engine.block.setShape(block=_, shape=_) Give the mask its shape
engine.block.setEnum(block=_, property="mask/mode", value=_) Set the mode of the mask
engine.block.appendMask(block=_, maskBlock=_) Attach the mask to a block
engine.block.createEffect(type=EffectType.Stroke) Create a stroke effect
engine.block.setColor(block=_, property="effect/stroke/color", value=_) Set the stroke color
engine.block.setFloat(block=_, property="effect/stroke/brushSize", value=_) Set the brush radius in design units
engine.block.setFloat(block=_, property="effect/stroke/hardness", value=_) Set how sharp the brush edge is
engine.block.setBoolean(block=_, property="effect/stroke/allMasks", value=_) Stroke every mask of the block
engine.block.setEnum(block=_, property="effect/stroke/paintStyle", value=_) Draw over the fill or on transparency
engine.block.setInt(block=_, property="effect/stroke/maskIndex", value=_) Pick the mask to stroke
engine.block.setFloat(block=_, property="effect/stroke/start", value=_) Set where the stroke starts on each mask path
engine.block.setFloat(block=_, property="effect/stroke/end", value=_) Set where the stroke ends on each mask path
engine.block.appendEffect(block=_, effectBlock=_) Add the stroke effect to a block
engine.block.export(block=_, mimeType=_) Export the page with all strokes

Next Steps#