PencilKit

RSS for tag

Capture touch input as an opaque drawing and turn it into high-quality images that can be displayed on iOS and macOS using PencilKit.

PencilKit Documentation

Posts under PencilKit tag

33 Posts
Sort by:
Post not yet marked as solved
6 Replies
1.1k Views
Since updating to iOS17, lasso no longer works in Pencilkit with SwiftUI support using UIViewRepresentable. It works in PKToolPicker, but the programmatically created PKLassoTool does not work. How can I get lasso to work?
Posted
by
Post marked as solved
9 Replies
2.9k Views
Running my app in iOS 17 has a weird bug. I can draw as usual on my canvas, but only when I open the color picker from the toolPicker a bunch of weird errors and warnings are posted to the console (I am assuming they are related to it.) Closing the color picker and leaving the screen would normally dismiss the toolbar, but now it stays forever and on every screen. Interestingly the canvas, the tool picker and the viewController are all getting deinitialized, which means there is a second/new toolPicker on screen and I have no reference to it. Here are the mentioned warnings and errors: Error acquiring assertion: <Error Domain=RBSServiceErrorDomain Code=1 "(originator doesn't have entitlement com.apple.runningboard.primitiveattribute AND originator doesn't have entitlement com.apple.runningboard.assertions.frontboard AND target is not running or doesn't have entitlement com.apple.runningboard.trustedtarget AND Target not hosted by originator)" UserInfo={NSLocalizedFailureReason=(originator doesn't have entitlement com.apple.runningboard.primitiveattribute AND originator doesn't have entitlement com.apple.runningboard.assertions.frontboard AND target is not running or doesn't have entitlement com.apple.runningboard.trustedtarget AND Target not hosted by originator)}> Received port for identifier response: <> with error:Error Domain=RBSServiceErrorDomain Code=1 "Client not entitled" UserInfo={RBSEntitlement=com.apple.runningboard.process-state, NSLocalizedFailureReason=Client not entitled, RBSPermanent=false} elapsedCPUTimeForFrontBoard couldn't generate a task port Received port for identifier response: <> with error:Error Domain=RBSServiceErrorDomain Code=1 "Client not entitled" UserInfo={RBSEntitlement=com.apple.runningboard.process-state, NSLocalizedFailureReason=Client not entitled, RBSPermanent=false} elapsedCPUTimeForFrontBoard couldn't generate a task port Received port for identifier response: <> with error:Error Domain=RBSServiceErrorDomain Code=1 "Client not entitled" UserInfo={RBSEntitlement=com.apple.runningboard.process-state, NSLocalizedFailureReason=Client not entitled, RBSPermanent=false} elapsedCPUTimeForFrontBoard couldn't generate a task port No setting found for property named "_UISceneHostingClientSettingsExtension" No setting found for property named "_UISceneHostingClientSettingsExtension" No setting found for property named "_UISceneHostingClientSettingsExtension" A code snippet, but nothing fancy: private var imageCanvasView = ImageCanvasView() private var toolPicker = ToolPicker() override func viewDidLoad() { super.viewDidLoad() self.toolPicker.setVisible(true, forFirstResponder: self.imageCanvasView) self.toolPicker.addObserver(self.imageCanvasView) self.imageCanvasView.becomeFirstResponder() } Any ideas on how to prevent that or at least access/hide the permanent tool picker?
Posted
by
Post not yet marked as solved
1 Replies
775 Views
I am using Xcode 15 beta 5 with iOS 17 beta 4 SDK. By building with the iOS 17 SDK my app got all the new inks which work great. Saving/encoding the PKDrawing to Data also works fine. However if I want to load the same PKDrawing again, on the same simulator or device (i.e., same iOS version) it fails with "Apple Drawing Format is from a future version that is too new.". From my understanding, reading https://developer.apple.com/documentation/pencilkit/supporting_backward_compatibility_for_ink_types?changes=_2 this is the expected behaviour when trying to load such a PKDrawing on an older iOS version which doesn't support the new ink types. Here is a short example, which prints the error: var drawing = PKDrawing() let strokePoints = [ PKStrokePoint(location: CGPoint(x: 0, y: 0), timeOffset: 0, size: CGSize(width: 3.0, height: 3.0), opacity: 2, force: 1, azimuth: 1, altitude: 1) ] let strokePath = PKStrokePath(controlPoints: strokePoints, creationDate: Date()) drawing.strokes.append(PKStroke(ink: .init(.watercolor), path: strokePath)) do { let data = drawing.dataRepresentation() let drawing2 = try PKDrawing(data: data) print("success") } catch { print(error) } } Saving & loading a PKDrawing which does not use any of the new ink types works fine.
Posted
by
Post not yet marked as solved
1 Replies
532 Views
Hi, I'm trying to use PencilKit over PDFKit as described in https://developer.apple.com/videos/play/wwdc2022/10089/. The thing is I open my custom UIDocument and initialize all its content to feed PDFView. Everything seems to work, I Input sketches in the canvas, PDFPageOverlayViewProvider's overlayView(for:) generates canvas correctly (it seems) but when editing finishes : willEndDisplayingOverlayView never gets called, and when I save the UIDocument (I use document.close(completionHandler:)) contents(forType:) never sees my custom PDFPages and I get no content for sketches. Does anyone of you have an idea of the lifecycle we should follow to get the methods called ? Sincerely yours
Posted
by
Post marked as solved
1 Replies
564 Views
Hello, I have a issue that's PKCanvasView's delegate method (canvasViewDrawingDidChange) is automatically called when the view present with .popover setting. In my case, I want to show some popup view on PKCanvasView and that's happening. viewController.modalPresentationStyle = .popover When I comment out this line the delegate method not getting called and everything is fine. The biggest problem was all previous ink on PKCanvas deleted somehow if this delegate being called automatically. Is this PencilKit bugs? Note: this trigger only with Apple Pencil, finger touch is fine.
Posted
by
Post marked as solved
1 Replies
874 Views
I've been trying to disable the "Smart Selection" feature introduced in https://developer.apple.com/wwdc20/10107 from a PKCanvasView. This feature could be very useful for some apps but if you want to start from a clean state canvas it might get in your way as you add gestures and interactions. Is there any way to opt out from it? The #WWDC20-10107 video demonstrates the "Smart Selection" feature at around 1:27.
Posted
by
Post not yet marked as solved
0 Replies
727 Views
Hi everyone! I was wondering if anyone has tips or resources to help me make a view (ideally in swiftUI) that works the same as a board in the Freeform app from Apple? I search online but I couldn't find anything that would help me I would like to be able to add views that I can drag around and interact with plus I would need to have pencilKit support and be able to move around the parent view (the Freeform board like view) Thanks
Posted
by
Post not yet marked as solved
1 Replies
763 Views
We're noticing some odd behaviour using PencilKit in our app. Most of the time, the response it quite fluid. But at intervals (and depending on what kind of strokes we create), PencilKit freezes the whole app for up to several seconds. It will come to life again and continue as normal, but eventually repeat that behaviour. When it happens, it's usually accompanied by one or two lines of console output, e.g.: 2023-05-12 15:52:29.101996+0100 Spaces[51229:3635610] [] Did not have live interaction lock at end of stroke 2023-05-12 15:52:29.556467+0100 Spaces[51229:3630745] [] Drawing did change that is not in text. I can't find any reference to these messages. They may have no bearing on the observed problem, but it might be a clue. Has anyone seen this behaviour or have any information about their meaning?
Posted
by
Post not yet marked as solved
3 Replies
1.3k Views
DemoCode: import SwiftUI import UIKit import PencilKit class PencilKitViewController: UIViewController, PKCanvasViewDelegate, PKToolPickerObserver {       lazy var canvasView: PKCanvasView = {     let canvasView = PKCanvasView()      canvasView.drawingPolicy = .anyInput      canvasView.translatesAutoresizingMaskIntoConstraints = false      return canvasView    }()       lazy var toolPicker: PKToolPicker = {     let toolPicker = PKToolPicker()     toolPicker.showsDrawingPolicyControls = true     toolPicker.addObserver(self)     return toolPicker   }()       let drawing = PKDrawing()       override func viewDidLoad() {     super.viewDidLoad()     canvasView.drawing = drawing     canvasView.delegate = self     view.addSubview(canvasView)   }       override func viewDidLayoutSubviews() {     super.viewDidLayoutSubviews()     canvasView.frame = view.bounds   }       override func viewDidAppear(_ animated: Bool) {     super.viewDidAppear(animated)     toolPicker.setVisible(true, forFirstResponder: canvasView)     toolPicker.addObserver(canvasView)     canvasView.becomeFirstResponder()   }       // canvas   func canvasViewDrawingDidChange(_ canvasView: PKCanvasView) {     print("drawing")   }       func canvasViewDidFinishRendering(_ canvasView: PKCanvasView) {         }       func canvasViewDidEndUsingTool(_ canvasView: PKCanvasView) {         }       func canvasViewDidBeginUsingTool(_ canvasView: PKCanvasView) {         } } // UIRepresentable for SwiftUI struct PencilKitView: UIViewControllerRepresentable {       class Coordinator {     var parentObserver: NSKeyValueObservation?   }       var onSubmit: ((UIImage?, Error?) -> Void)? = .none       func makeUIViewController(context: Context) -> PencilKitViewController {     let pencilKitViewController = PencilKitViewController()     context.coordinator.parentObserver = pencilKitViewController.observe(\.parent, changeHandler: { vc, _ in      })     return pencilKitViewController   }       func updateUIViewController(_ uiViewController: PencilKitViewController, context: Context) {   }       func makeCoordinator() -> Self.Coordinator { Coordinator() } } struct ContentView: View {       var onSubmit: ((UIImage?, Error?) -> Void)? = .none       var body: some View {       PencilKitView()   } } struct ContentView_Previews: PreviewProvider {   static var previews: some View {     ContentView()   } } iOS: macCatalyst:
Posted
by
Post not yet marked as solved
7 Replies
2k Views
You used to be able to select a drawing, long press to show the edit menu (copy, duplicate, delete, ...), copy the item and paste it after another long press on the canvas. However, since iOS / iPadOS 16.1 long pressing the canvas does not show any menu. The action still works if you connect an external mouse to your iPad, activate the secondary click functionality and use the right mouse button to click on the canvas. This shows the menu and you can paste the copied drawing. It seems to be broken in all PencilKit-based apps, including Apple's sample apps. Is there any workaround? This is a major problem for my app and used to work fine since the introduction of PencilKit with iOS 13.
Posted
by
Post not yet marked as solved
4 Replies
4.2k Views
It seems PKCanvasView overrides the property UIScrollViewDelegate which inherits from the UIScrollView to PKCanvasViewDelegate. And does not provide access to UIScrollViewDelegate. In order to implement zooming, so I added a PKCanvasView into my own UIScrollView. And implemented delegate method viewForZooming in which return PKCanvasView. But all drawing in PKCanvasView was blurred when zooming or scale. How to re-render drawing after zoom to make it has reasonable stroke width and clear ? Some related code: let canvasView = PKCanvasView() let scrollView = UIScrollView() override func viewDidLoad() {     super.viewDidLoad()     self.view.addSubview(scrollView)     scrollView.addSubview(canvasView)     scrollView.delegate = self     scrollView.minimumZoomScale = 0.5     scrollView.maximumZoomScale = 2.5 } func viewForZooming(in scrollView: UIScrollView) -> UIView? {     return canvasView } Some solutions I had tried: 1: Reset PKCanvasView contentScaleFactor func scrollViewDidEndZooming(_ scrollView: UIScrollView, with view: UIView?, atScale scale: CGFloat) {     if let canvas = view {       let contentScale = scale * UIScreen.main.scale       canvas.contentScaleFactor = contentScale     }   } Not worked! 2: Re-render PKStroke: func reRender(_ scale: CGFloat) {     let newStrokeWidth = strokeWidth * scale     var newDrawingStrokes: [PKStroke] = []     for stroke in canvasView.drawing.strokes {       canvasView.tool = PKInkingTool(.pen, color: .red, width: newStrokeWidth)       var newPoints = [PKStrokePoint]()       stroke.path.forEach { (point) in         let newPoint = PKStrokePoint(location: point.location,                        timeOffset: point.timeOffset,                        size: CGSize(width: newStrokeWidth, height: newStrokeWidth),                        opacity: CGFloat(1), force: point.force,                        azimuth: point.azimuth, altitude: point.altitude)         newPoints.append(newPoint)       }       let newPath = PKStrokePath(controlPoints: newPoints, creationDate: Date())       let newStroke = PKStroke(ink: PKInk(.pen, color: UIColor.red), path: newPath)       newDrawingStrokes.append(newStroke)     }     let newDrawing = PKDrawing(strokes: newDrawingStrokes)     canvasView.drawing = newDrawing   } Not worked! Still blurred, just changed strokeWidth by multiply scale. 3: I try to reset PKDrawing or PKStroke transform by using scrollView scale. Then PKDrawing position disordered and it was still blurred. Please help me.
Posted
by
Post not yet marked as solved
2 Replies
2k Views
My problem I have a SwiftUI app that uses PKCanvasView to allow drawing. The PKCanvasView is transparent and there are SwiftUI views (e.g. an Image) behind which can be dragged and opened. I want the user to be able to draw on the PKCanvasView with their apple pencil and interact with the views below with their finger... I can't figure out how to enable simultaneous interaction with the PKCanvasView (i.e. if using apple pencil draw) and the swiftUI views behind (i.e. if using finger, drag and move views). The context Here is my PKCanvasView wrapped in a UIViewRepresentable struct: struct CanvasView: UIViewRepresentable { @Binding var canvasView: PKCanvasView @State var toolPicker = PKToolPicker() func makeUIView(context: Context) - PKCanvasView { canvasView.drawingPolicy = .pencilOnly canvasView.backgroundColor = .clear canvasView.isOpaque = false canvasView.alwaysBounceVertical = true canvasView.alwaysBounceHorizontal = true toolPicker.setVisible(true, forFirstResponder: canvasView) toolPicker.addObserver(canvasView) return canvasView } func updateUIView(_ uiView: PKCanvasView, context: Context) { } } The structure of my content view is as follows: swift ZStack(alignment: .topLeading){                 CanvasView(canvasView: $canvasView)                     .zIndex(0)                 ForEach(canvas.subCanvases.indices, id: \.self){ index in                         CanvasCardView(                             canvas: $canvas.subCanvases[index],                             animationNamespace: animationNamespace,                             onReorder: {                                 reorderCard(at: canvas.subCanvases[index].zOrder)                         })                 }             } The CanvasCardView are the background SwiftUI views which can be dragged and opened. The view attaches a negative zIndex to them which orders them behind the CanvasView (PKCanvasView). My attempts I've tried two approaches so far which don't work: Subclassing PKCanvasView to override point(inside:with:). Passing false when I want to touches to be passed through. Problem with this is that the swiftUI views never recognise the touches through the UIView. I assume as there are no UITouchs behind the scenes. Adding a @State property to my contentView that can update an allowsHitTesting() modifier dynamically when required. The issue with this is that without allowing the PKCanvasView to be "hit" I can't determine whether it is a pencil touch or not. So i can't properly interact with PKCanvasView simultaneously. Any other ideas if this is possible? That is, passing touches through a UIViewRepresentable dynamically? I really want to avoid shoving the SwiftUI views into a UIView (with UIHostingController) and then turning them back into SwiftUI. Many thanks!
Posted
by
Post not yet marked as solved
2 Replies
1k Views
I'm using PkCanvasView one of my app for drawing purpose. When I use lasso tool for selection and tap on selected area, menu controller appear with options "Cut, Copy, Delete, Duplicate, Insert Space Above". As per my app requirement, I want to remove "Insert Space Above" from menu controller. Is it doable?
Posted
by