Dunfey · Hotel WWDC as data, est. 1983
Front desk everything
Years
Topics

2025 App Services

WWDC25 · 12 min · App Services

Meet PaperKit

Discover how to bring PaperKit to your iOS, iPadOS, macOS, and visionOS apps. We’ll cover how to seamlessly integrate PencilKit drawing with markup features like shapes and images, and how to customize the user interface. Learn best practices for forward compatibility, and discover advanced customization options to create truly unique markup experiences in your apps.

Watch at developer.apple.com ↗

Transcript all transcripts

Chapters

  • 0:00 — Introduction
  • 1:36 — Getting to know PaperKit
  • 3:35 — Getting started 
with PaperKit
  • 8:37 — Customizing the 
feature set

Code shown on screen · 6 snippets

Adopt PaperKit in iOS swift · at 3:47 ↗
// Adopt PaperKit in iOS

override func viewDidLoad() {
    super.viewDidLoad()
    
    let markupModel = PaperMarkup(bounds: view.bounds)
    let paperViewController = PaperMarkupViewController(markup: markupModel, supportedFeatureSet: .latest)
    view.addSubview(paperViewController.view)
    addChild(paperViewController)
    paperViewController.didMove(toParent: self)
    becomeFirstResponder()    

    let toolPicker = PKToolPicker()
    toolPicker.addObserver(paperViewController)
    
    pencilKitResponderState.activeToolPicker = toolPicker
    pencilKitResponderState.toolPickerVisibility = .visible
    
    toolPicker.accessoryItem = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(plusButtonPressed(_:)))
}

@objc func plusButtonPressed(_ button: UIBarButtonItem) {
    let markupEditViewController = MarkupEditViewController(supportedFeatureSet: .latest)    
    markupEditViewController.delegate = paperViewController
    markupEditViewController.modalPresentationStyle = .popover
    markupEditViewController.popoverPresentationController?.barButtonItem = button
    present(markupEditViewController, animated: true)
}
Adopt PaperKit in macOS swift · at 6:11 ↗
// Adopt PaperKit in macOS

override func viewDidLoad() {
    super.viewDidLoad()
    
    let markupModel = PaperMarkup(bounds: view.bounds)
    let paperViewController = PaperMarkupViewController(markup: markupModel, supportedFeatureSet: .latest)
    view.addSubview(paperViewController.view)
    addChild(paperViewController)

    // Create toolbar for macOS
    let toolbarViewController = MarkupToolbarViewController(supportedFeatureSet: .latest)
    toolbarViewController.delegate = paperViewController
    view.addSubview(toolbarViewController.view)
    
    // Set layout
    setupLayoutConstraints()
}
Auto-save markup changes swift · at 7:18 ↗
// Auto-save markup changes
    
func paperMarkupViewControllerDidChangeMarkup(_ paperMarkupViewController: PaperMarkupViewController) {
    let markupModel = paperMarkupViewController.markup
    Task {
        // Create a data blob and save it
        let data = try await markupModel.dataRepresentation()
        try data.write(toFile: paperKitDataURL)
    }
}
Thumbnail for forward compatibility swift · at 8:02 ↗
// Thumbnail for forward compatibility

func updateThumbnail(_ markupModel: PaperMarkup) async throws {
    // Set up CGContext to render thumbnail in
    let thumbnailSize = CGSize(width: 200, height: 200)
    let context = makeCGContext(size: thumbnailSize)
    context.setFillColor(gray: 1, alpha: 1)
    context.fill(renderer.format.bounds)            

    // Render the PaperKit markup
    await markupModel.draw(in: context, frame: CGRect(origin: .zero, size: thumbnailSize))
    
    thumbnail = context.makeImage()
}
Customized markup FeatureSet swift · at 9:02 ↗
// Customized markup FeatureSet
    
var featureSet: FeatureSet = .latest

featureSet.remove(.text)
featureSet.insert(.stickers)

// HDR support
featureSet.colorMaximumLinearExposure = 4
toolPicker.colorMaximumLinearExposure = 4

let paperViewController = PaperMarkupViewController(supportedFeatureSet: featureSet)
let markupEditViewController = MarkupEditViewController(supportedFeatureSet: featureSet)
Custom background on markup controller swift · at 10:50 ↗
// Custom background on markup controller

let template = UIImage(named: "MyTemplate.jpg")
let templateView = UIImageView(image: template)
paperViewController.contentView = templateView

Resources