What's New / App UI: SwiftUI, AppKit & UIKit

What's new in PencilKit

+41 NewiOS · macOS

PencilKit captures Apple Pencil and touch input into strokes and renders them in a canvas view. Apps use it for handwriting, sketching, and annotation surfaces.

The 27 SDK adds 41 APIs with no deprecations or removals. New types include struct RenderState, struct ConvertedBezierPoint, and actor PKStrokeRecognizer. New members include selection, PKContentVersion.version5, erasingStrokePath, strokeID, renderGroupID, renderState, and substroke, plus several new init entry points.

New

41
var

bezierRepresentation

NewiOSmacOS
open var bezierRepresentation: CGPath { get }

A Bézier path representation of the path's curve, computed in linear time.

func

erasingStrokePath

NewiOS
open func erasingStrokePath(_ eraserPath: PKStrokePath, mask: UIBezierPath?, transform: CGAffineTransform) -> PKDrawing
func

erasingStrokePath

NewmacOS
open func erasingStrokePath(_ eraserPath: PKStrokePath, mask: NSBezierPath?, transform: CGAffineTransform) -> PKDrawing
init

init

NewiOS
public init(ink: PKInk, strokePath: PKStrokePath, transform: CGAffineTransform, mask: UIBezierPath?, randomSeed: UInt32, strokeID: UUID, renderGroupID: UUID?, renderState: __PKStrokeRenderState?)
init

init

NewiOSmacOS
public convenience init(controlPoints: [PKStrokePoint], creationDate: Date, strokePathID: UUID)

Creates a stroke path with the specified control points and a unique identifier.

@param controlPoints An array of control points for a cubic B-spline. @param creationDate The start time of this path. @param strokePathID The unique identity of the stroke path.

Warning: Using multiple stroke paths with identical IDs but different control points

will result in undefined rendering behavior. Ensure each stroke path has a unique identifier.

init

init

NewiOSmacOS
public convenience init(bezierPath: CGPath, creationDate: Date, pointProvider: (PKConvertedBezierPointReference) -> PKStrokePoint)

Creates a stroke path recreating the specified Bézier path as a cubic uniform B-Spline.

@param bezierPath The Bézier path to convert to a cubic uniform B-Spline. @param creationDate The start time of this path. @param pointProvider Block to initialize the PKStrokePoints of the path. A single PKConvertedBezierPoint instance is shared across all converted points.

The count of control points of the generated spline is not guaranteed to be a specific value except when the provided path is the output of bezierRepresentation->CGPathRef, where it will match the original curve.

The output B-Spline will have continuous curvature and 0 curvature at the endpoints. In cases where the B-Spline cannot fully recreate the Bézier path, it will be an approximation. For example, if the given Bézier path includes line to elements, these will produce straight line segments in the resulting B-Spline, but if a line to element is adjacent to a curve to element, the resulting curve may not match the original.

Warning: For a Bézier path with multiple subpaths, only the first will be converted.

init

init

NewiOSmacOS
public init(location: CGPoint, timeOffset: TimeInterval, size: CGSize, opacity: CGFloat, force: CGFloat, azimuth: CGFloat, altitude: CGFloat, secondaryScale: CGFloat, threshold: CGFloat, lateralJitter: CGFloat)

Creates a stroke point with the specified properties, including lateral jitter.

init

init

NewmacOS
public init(ink: PKInk, strokePath: PKStrokePath, transform: CGAffineTransform, mask: NSBezierPath?, randomSeed: UInt32, strokeID: UUID, renderGroupID: UUID?, renderState: __PKStrokeRenderState?)
var

lateralJitter

NewiOSmacOS
open var lateralJitter: CGFloat { get }

The amount of lateral particle jitter at the stroke edge for supported inks.

Lateral jitter applies only to some inks, such as PKInkIdentifierPencil.

extension

PKStroke

NewiOSmacOS
extension PKStroke : Identifiable
Declaration
extension PKStroke : Identifiable {

    /// The unique identity of the stroke.
    @available(iOS 27.0, macOS 27.0, *)
    public var id: UUID

    /// A type representing the stable identity of the entity associated with
    /// an instance.
    @available(macOS 27.0, iOS 27.0, *)
    public typealias ID = UUID
}
extension

PKStrokePath

NewiOSmacOS
extension PKStrokePath : Identifiable
Declaration
extension PKStrokePath : Identifiable {

    /// Creates a stroke path with the specified cubic B-spline control points and a unique identifier.
    ///
    /// - Parameters:
    ///   - controlPoints: An array of control points for a cubic B-spline.
    ///   - creationDate: The start time of this path.
    ///   - id: The unique identity of the path.
    ///
    /// > Warning: Using multiple stroke paths with identical IDs but different control points
    /// will result in undefined rendering behavior. Ensure each stroke path has a unique identifier.
    @available(iOS 27.0, macOS 27.0, *)
    public init<T>(controlPoints: T, creationDate: Date, id: UUID) where T : Sequence, T.Element == PKStrokePoint

    /// The unique identity of the stroke path.
    ///
    /// > Warning: Using multiple stroke paths with identical IDs but different control points
    /// will result in undefined rendering behavior. Ensure each stroke path has a unique identifier.
    @available(iOS 27.0, macOS 27.0, *)
    public var id: UUID { get }

    /// A type representing the stable identity of the entity associated with
    /// an instance.
    @available(macOS 27.0, iOS 27.0, *)
    public typealias ID = UUID
}
actor

PKStrokeRecognizer

NewiOSmacOS
final public actor PKStrokeRecognizer

An actor that recognizes handwritten strokes and searches for text in a drawing.

Declaration
final public actor PKStrokeRecognizer {

    /// A result containing the matched strokes and their bounds from a search query.
    public struct SearchResult {

        /// The identifiers of the strokes the result contains.
        public let strokes: Set<UUID>

        /// The bounds of the matched strokes in the coordinate space of their drawing.
        public let bounds: CGRect
    }

    /// The languages the recognizer supports.
    public static var supportedLanguages: Set<Locale.Language> { get }

    /// The version number of the recognition engine.
    ///
    /// If you persist results this recognizer returns, store this value alongside them
    /// and regenerate the results when running on an OS with a higher version number.
    public static var recognitionVersion: Int { get }

    /// Creates a recognizer with the specified preferred languages.
    ///
    /// Languages are respected on a best-effort basis. Factors such as feature support
    /// may affect which languages the recognizer uses.
    ///
    /// - Parameters:
    ///   - preferredLanguages: A list of languages to recognize ordered by descending priority.
    ///     Pass nil to use the system languages.
    ///     The system languages may be used if no listed language is available for recognition.
    public init(preferredLanguages: [Locale.Language]? = nil)

    /// The drawing the recognizer analyzes.
    final public var drawing: PKDrawing { get }

    /// Updates the drawing the recognizer analyzes.
    ///
    /// Recognition expects handwriting and strokes scaled as if written on standard paper
    /// sizes in points, such as US-letter or A4.
    /// - Parameter drawing: The new drawing.
    final public func updateDrawing(_ drawing: PKDrawing) async

    /// The languages the recognizer uses, ordered by descending priority.
    final public var languages: [Locale.Language] { get }

    /// A string suitable for indexing the drawing's recognized text in search systems such as Spotlight.
    ///
    /// The string may contain multiple concatenated candidate matches for recognized text in the drawing.
    final public var indexableContent: String? { get async }

    /// Returns the recognized text from the specified strokes in the drawing.
    /// - Parameter strokeIDs: The `id`s of the `PKStrokes` in `drawing` to analyze.
    ///   Pass `nil` to return the recognized text from the whole drawing.
    final public func recognizedText(strokeIDs: Set<UUID>? = nil) async -> String?

    /// Searches the drawing for strokes whose recognized text matches the query.
    /// - Parameters:
    ///   - query: The query string to search for.
    ///   - fullWordsOnly: Restricts matches to whole words only.
    ///   - caseMatchingOnly: Restricts matches to exact case.
    /// - Returns: An array of all results found.
    final public func search(_ query: String, fullWordsOnly: Bool = false, caseMatchingOnly: Bool = false) async -> [PKStrokeRecognizer.SearchResult]

    @objc deinit

    /// Retrieve the executor for this actor as an optimized, unowned
    /// reference.
    ///
    /// This property must always evaluate to the same executor for a
    /// given actor instance, and holding on to the actor must keep the
    /// executor alive.
    ///
    /// This property will be implicitly accessed when work needs to be
    /// scheduled onto this actor.  These accesses may be merged,
    /// eliminated, and rearranged with other work, and they may even
    /// be introduced when not strictly required.  Visible side effects
    /// are therefore strongly discouraged within this property.
    ///
    /// - SeeAlso: ``SerialExecutor``
    /// - SeeAlso: ``TaskExecutor``

Truncated.

var

renderGroupID

NewiOSmacOS
open var renderGroupID: UUID? { get }

A UUID that groups strokes for wet-ink compositing with compatible inks such as marker.

Set this to the same value for a run of strokes to render them as if drawn while the previous stroke with the same ink was still wet.

var

renderState

NewiOSmacOS
open var renderState: __PKStrokeRenderState? { get }

The render details of the stroke, such as particle positioning. Uses default rendering when nil.

This may be set on substrokes returned by -substrokeWithRange:.

var

selection

NewiOS
open var selection: Set<UUID>

The identifiers of the strokes selected on the canvas.

var

strokeID

NewiOSmacOS
open var strokeID: UUID { get }

The unique identity of the stroke.

var

strokePathID

NewiOSmacOS
open var strokePathID: UUID { get }

The unique identity of the stroke path.

Warning: Using multiple stroke paths with identical IDs but different control points

will result in undefined rendering behavior. Ensure each stroke path has a unique identifier.

func

subpath

NewiOSmacOS
open func subpath(with range: __PKFloatRange) -> PKStrokePath

Returns a copy of the path containing the control points in the specified parametric range.

@param range The parametric range to copy. Values must be within [0, count-1]. @return A new stroke path containing the portion within the specified parametric range.

func

substroke

NewiOSmacOS
open func substroke(with range: __PKFloatRange) -> PKStroke

Returns a copy of the stroke containing the control points in the specified range.

Maintains rendering information so the returned substroke renders the same as the corresponding portion of the receiver. The returned stroke may have a renderState set to maintain this information.

@param range The range of control points in the receiver to copy to the returned stroke. @returns A new stroke containing only the control points within the specified range.

case

PKContentVersion.version5

NewiOSmacOS
case version5 = 5

The version that adds stroke render state support.

func

PKDrawing.erasePath

NewiOS
public mutating func erasePath(_ eraserPath: PKStrokePath, mask: UIBezierPath? = nil, transform: CGAffineTransform = .identity)
func

PKDrawing.erasePath

NewmacOS
public mutating func erasePath(_ eraserPath: PKStrokePath, mask: NSBezierPath? = nil, transform: CGAffineTransform = .identity)
func

PKDrawing.erasingPath

NewiOS
public func erasingPath(_ eraserPath: PKStrokePath, mask: UIBezierPath? = nil, transform: CGAffineTransform = .identity) -> PKDrawing
func

PKDrawing.erasingPath

NewmacOS
public func erasingPath(_ eraserPath: PKStrokePath, mask: NSBezierPath? = nil, transform: CGAffineTransform = .identity) -> PKDrawing
var

PKStroke.id

NewiOSmacOS
public var id: UUID

The unique identity of the stroke.

typealias

PKStroke.ID

NewiOSmacOS
public typealias ID = UUID

A type representing the stable identity of the entity associated with an instance.

init

PKStroke.init

NewiOS
public init(ink: PKInk, path: PKStrokePath, transform: CGAffineTransform = .identity, mask: UIBezierPath? = nil, randomSeed: UInt32 = UInt32.random(in: 0...UInt32.max), id: UUID = UUID(), renderGroupID: UUID? = nil, renderState: PKStroke.RenderState? = nil)
init

PKStroke.init

NewmacOS
public init(ink: PKInk, path: PKStrokePath, transform: CGAffineTransform = .identity, mask: NSBezierPath? = nil, randomSeed: UInt32 = UInt32.random(in: 0...UInt32.max), id: UUID = UUID(), renderGroupID: UUID? = nil, renderState: PKStroke.RenderState? = nil)
var

PKStroke.renderGroupID

NewiOSmacOS
public var renderGroupID: UUID?

Strokes with certain inks (such as marker) can composite to look as if they were drawn while the previous stroke with the same ink was still wet. This UUID may be set to a single value for a run of strokes which should be rendered together in this manner.

var

PKStroke.renderState

NewiOSmacOS
public var renderState: PKStroke.RenderState?

Contains information about the render details (such as particle positioning) of this stroke, which can be useful when manipulating the model in certain ways. For example, this may be set on substrokes returned by substroke(range:). nil uses default rendering.

struct

PKStroke.RenderState

NewiOSmacOS
public struct RenderState : Sendable, Codable, Equatable

The render details of a stroke, including particle positioning and grain texture offset.

Some state is exposed, but other state is opaque. Encode using Codable to persist all stored information.

Declaration
public struct RenderState : Sendable, Codable, Equatable {

    /// The pre-transform position of the grain texture for strokes with a backing grain texture such as crayon.
    public var grainOffset: CGPoint?

    /// Creates a render state with the specified grain offset.
    ///
    /// - Parameter grainOffset: The grain texture offset. Defaults to nil.
    public init(grainOffset: CGPoint? = nil)

    /// Creates a `RenderState` from its Objective-C counterpart `PKStrokeRenderState`.
    ///
    /// - Parameter objcValue: The Objective-C `PKStrokeRenderState` to convert from.
    public init(_ objcValue: __PKStrokeRenderState)

    /// Returns the Objective-C `PKStrokeRenderState` representation of this render state.
    public func asObjCRenderState() -> __PKStrokeRenderState

    /// Creates a new instance by decoding from the given decoder.
    ///
    /// This initializer throws an error if reading from the decoder fails, or
    /// if the data read is corrupted or otherwise invalid.
    ///
    /// - Parameter decoder: The decoder to read data from.
    public init(from decoder: any Decoder) throws

    /// Encodes this value into the given encoder.
    ///
    /// If the value fails to encode anything, `encoder` will encode an empty
    /// keyed container in its place.
    ///
    /// This function throws an error if any values are invalid for the given
    /// encoder's format.
    ///
    /// - Parameter encoder: The encoder to write data to.
    public func encode(to encoder: any Encoder) throws

    /// Returns a Boolean value indicating whether two values are equal.
    ///
    /// Equality is the inverse of inequality. For any values `a` and `b`,
    /// `a == b` implies that `a != b` is `false`.
    ///
    /// - Parameters:
    ///   - lhs: A value to compare.
    ///   - rhs: Another value to compare.
    public static func == (a: PKStroke.RenderState, b: PKStroke.RenderState) -> Bool
}
func

PKStroke.substroke

NewiOSmacOS
public func substroke(range: ClosedRange<CGFloat>) -> PKStroke

Returns a copy of this stroke containing the control points in the given range.

Maintains information for PencilKit rendering to make the copied part of the stroke render the same as the receiver. The returned stroke may have a renderState set to maintain this information.

Parameters

range
The range of control points in the receiver to copy to the returned stroke.

ReturnsA new stroke containing only the control points within the specified range.

var

PKStrokePath.bezierRepresentation

NewiOSmacOS
public var bezierRepresentation: CGPath { get }

A Bézier path representation of the path's curve, computed in linear time.

struct

PKStrokePath.ConvertedBezierPoint

NewiOSmacOS
public struct ConvertedBezierPoint

Information about a B-spline control point converted from a Bézier path.

Provided to the pointProvider closure of init(bezierPath:creationDate:pointProvider:)->Self to initialize each PKStrokePoint-struct of the resulting path.

Declaration
public struct ConvertedBezierPoint {

    /// The index of the point along the path.
    public let index: Int

    /// The total number of B-Spline control points in the path.
    public let pointCount: Int

    /// The location of the cubic uniform B-Spline control point.
    public let location: CGPoint

    /// The index of the Bézier segment the point originates from, not including `move to` elements.
    public let bezierSegmentIndex: Int
}
var

PKStrokePath.id

NewiOSmacOS
public var id: UUID { get }

The unique identity of the stroke path.

Warning: Using multiple stroke paths with identical IDs but different control points

will result in undefined rendering behavior. Ensure each stroke path has a unique identifier.

typealias

PKStrokePath.ID

NewiOSmacOS
public typealias ID = UUID

A type representing the stable identity of the entity associated with an instance.

init

PKStrokePath.init

NewiOSmacOS
public init(bezierPath: CGPath, creationDate: Date, pointProvider: (_ convertedPoint: PKStrokePath.ConvertedBezierPoint) -> PKStrokePoint)

Creates a stroke path recreating the specified Bézier path as a cubic uniform B-Spline.

The count of control points of the generated spline is not guaranteed to be a specific value except when the provided path is the output of bezierRepresentation->CGPath, where it will match the original curve.

The output B-Spline will have continuous curvature and 0 curvature at the endpoints. In cases where the B-Spline cannot fully recreate the Bézier path, it will be an approximation. For example, if the given Bézier path includes line to elements, these will produce straight line segments in the resulting B-Spline, but if a line to element is adjacent to a curve to element, the resulting curve may not match the original.

Warning: For a Bézier path with multiple subpaths, only the first will be converted.

Parameters

bezierPath
The Bézier path to convert to a cubic uniform B-Spline
creationDate
The start time of this path.
pointProvider
Closure to initialize the PKStrokePoints of the path with specific values.
init

PKStrokePath.init

NewiOSmacOS
public init<T>(controlPoints: T, creationDate: Date, id: UUID) where T : Sequence, T.Element == PKStrokePoint

Creates a stroke path with the specified cubic B-spline control points and a unique identifier.

Warning: Using multiple stroke paths with identical IDs but different control points

will result in undefined rendering behavior. Ensure each stroke path has a unique identifier.

Parameters

controlPoints
An array of control points for a cubic B-spline.
creationDate
The start time of this path.
id
The unique identity of the path.
subscript

PKStrokePath.subscript

NewiOSmacOS
public subscript(range: ClosedRange<CGFloat>) -> PKStrokePath { get }

Returns a copy of the path containing the control points in the specified parametric range.

Important: This subscript returns a new stroke path with points always starting at index zero. This differs from the Range<Int> subscript, which returns a Slice with points at their original index.

Parameters

range
The parametric range to copy. Values must be within [0, count-1].

ReturnsA new stroke path containing the portion within the specified parametric range.

init

PKStrokePoint.init

NewiOSmacOS
public init(location: CGPoint, timeOffset: TimeInterval, size: CGSize, opacity: CGFloat, force: CGFloat, azimuth: CGFloat, altitude: CGFloat, secondaryScale: CGFloat, threshold: CGFloat, lateralJitter: CGFloat)

Creates a stroke point with the specified properties, including lateral jitter.

var

PKStrokePoint.lateralJitter

NewiOSmacOS
public var lateralJitter: CGFloat { get }

The amount of lateral particle jitter at the stroke edge for supported inks.

Lateral jitter applies only to some inks, such as .pencil.

No APIs match your filter.

← More in App UI: SwiftUI, AppKit & UIKit