Painting
What are the painting building blocks?
Pathdescribes a sequence of potentially disjoint movements on a plane. Paths tracks a current point as well as one or more subpaths (created viaPath.moveTo). Subpaths may be closed (i.e., the first and last points are coincident), open (i.e., the first and last points are distinct), or self intersecting (i.e., movements within the path intersect). Paths incorporate lines, arcs, beziers, and more; each operation begins at the current point and, once complete, defines the new current point. The current point begins at the origin. Paths can be queried (viaPath.contains), transformed (viaPath.transform), and merged (viaPath.combine, which accepts aPathOperation).PathFillTypedefines the criteria determining whether a point is contained by the path.PathFillType.evenOddcasts a ray from the point outward, summing the number of edge crossings; an odd count indicates that the point is internal.PathFillType.nonZeroconsiders the path’s directionality. Again casting a ray from the point outward, this method sums the number of clockwise and counterclockwise crossings. If the counts aren’t equal, the point is considered to be internal.
Canvasrepresents a graphical context supporting a number of drawing operations. These operations are captured by an associatedPictureRecorderand, once finalized, transformed into aPicture. TheCanvasis associated with a clip region (i.e., an area within which painting will be visible), and a current transform (i.e., a matrix to be applied to any drawing), both managed using a stack (i.e., clip regions and transforms can be pushed and popped as drawing proceeds). Any drawing outside of the canvas’s culling box (“cullRect”) may be discarded; by default, however, affected pixels are retained. Many operations accept aPaintparameter which describes how the drawing will be composited (e.g., the fill, stroke, blending, etc).Canvasexposes a rich API for drawing. The majority of these operations are implemented within the engine.Canvas.clipPath,Canvas.clipRect, etc., refine (i.e., reduce) the clip region. These operations compute the intersection of the current clip region and the provided geometry to define a new clip region. The clip region can be anti-aliased to provide a gradual blending.Canvas.translate,Canvas.scale,Canvas.transform, etc., alter the current transformation matrix (i.e., by multiplying it by an additional transform). The former methods apply standard transformations, whereas the latter applies an arbitrary 4x4 matrix (specified in column-major order).Canvas.drawRect,Canvas.drawLine,Canvas.drawPath, etc., perform fundamental drawing operations.Canvas.drawImage,Canvas.drawAtlas,Canvas.drawPicture, etc., copy pixels from a rendered image or recorded picture into the current canvas.Canvas.drawParagraphpaints text into the canvas (viaParagraph._paint).Canvas.drawVertices,Canvas.drawPoints, etc., describe solids using a collection of points. The former constructs triangles from a set of vertices (Vertices) and a vertex mode (VertexMode); this mode describes how vertices are composed into triangles (e.g.,VertexMode.trianglesspecifies that each sequence of three points defines a new triangle). The resulting triangles are filled and composited using the providedPaintandBlendMode. The latter paints a set of points using aPointModedescribing how the collection of points is to be interpreted (e.g., as defining line segments or disconnected points).
The save stack tracks the current transformation and clip region. New entries can be pushed (via
Canvas.saveorCanvas.saveLayer) and popped (viaCanvas.restore). The number of items in this stack can also be queried (viaCanvas.getSaveCount); there is always at least one item on the stack. All drawing operations are subject to the transform and clip at the top of the stack.All drawing operations are performed sequentially (by default or when using
Canvas.save/Canvas.restore). If the operation utilizes blending, it will be blended immediately after completing.Canvas.saveLayerallows drawing operations to be grouped together and composited as a whole. Each individual operation will still be blended within the saved layer; however, once the layer is completed, the composite drawing will be blended as a whole using the providedPaintand bounds.For example, an arbitrary drawing can be made consistently translucent by first painting it using an opaque fill, and then blending the resulting layer with the canvas. If instead each component of the drawing were individually blended, overlapping regions would appear darker.
This is particularly useful for antialiased clip regions (i.e., regions that aren’t pixel aligned). Without layers, any operations intersecting the clip would needed to be antialiased (i.e., blended with the background). If a subsequent operation intersects the clip at this same point, it would be blended with both the background and the previous operation; this produces visual artifacts (e.g., color bleed). If both operations were combined into a layer and composited as a whole, only the final operation would be blended.
Note that though this doesn’t introduce a new framework layer, it does cause the engine to switch to a new rendering target. This is fairly expensive as it flushes the
GPU’s command buffer and requires data to be shuffled.
Paintdescribes how a drawing operation is to be applied to the canvas. In particular, it specifies a number of graphical parameters including the color to use when filling or stroking lines (Paint.color,Paint.colorFilter,Paint.shader), how new painting is to be blended with old painting (Paint.blendMode,Paint.isAntiAlias,Paint.maskFilter), and how edges are to be drawn (Paint.strokeWidth,Paint.strokeJoin,Paint.strokeCap). Fundamental to most drawing is whether the result is to be stroked (e.g., drawn as an outline) or filled;Paint.styleexposes aPaintingStyleinstance specifying the mode to be used.If stroking,
Paint.strokeWidthis measured in logical pixels orthogonal to the path being painted. A value of0.0will cause the line to be rendered as thin as possible (“hairline rendering”).Any lines that are drawn will be capped at their endpoints according to a
StrokeCapvalue (viaPaint.strokeCap;StrokeCap.buttis the default and does not paint a cap). Caps extend the overall length of lines in proportion to the stroke width.Discrete segments are joined according to a
StrokeJoinvalue (viaPaint.strokeJoin;StrokeJoin.miteris the default and extends the original line such that the next can be drawn directly from it). A limit may be specified to prevent the original line from extending too far (viaPaint.strokeMiterLimit; once exceeded, the join reverts toStrokeJoin.bevel).
ColorFilterdescribes a function mapping from two input colors (e.g., the paint’s color and the destination’s color) to a final output color (e.g., the final composited color). If aColorFilteris provided, it overrides both the paint color and shader; otherwise, the shader overrides the color.MaskFilterapplies a filter (e.g., a blur) to the drawing once it is complete but before it is composited. Currently, this is limited to a Gaussian blur.
Shaderis a handle to a Skia shader utilized by the engine. Several are exposed within the framework, includingGradientandImageShader. These are analogous, with the former generating pixels by smoothly blending colors and the latter reading them directly from an image. Both support tiling so that the original pixels can be extended beyond their bounds (a differentTileModemay be specified in either direction);ImageShaderalso supports an arbitrary matrix to be applied to the source image.
Last updated
Was this helpful?