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.

Posts under PencilKit tag

137 Posts

Post

Replies

Boosts

Views

Activity

Disable Scribble in UITextView
There are use cases where someone who's using an Apple Pencil may not want to enter text via Scribble. A simple example is writing "UIViewController" in a text view is unlikely to be successful. I'd like to disable Scribble in this case and let the keyboard become the input mechanism. (Disabling Scribble system-wide in Settings is both cumbersome and overkill.) The closest I can come to making this happen is by adding a UIScribbleInteraction on a UITextView and returning false when scribbleInteraction(shouldBeginAt:) is called. This disables Scribble on the text view, and prevents writing from being converted into text, but the input widget still appears on screen and isn't very useful. Here is a sample project that demonstrates the problem: http://files.iconfactory.net/craig/bugs/Scribbler.zip Hopefully, I'm doing something wrong here. If not, I'm happy to submit this as a FB. -ch
3
0
3.3k
Nov ’24
Changing the color or width of an inking tool on squeeze tool palette causes crash
When a custom tool items set is formed in PKToolPicker with each inking item having non-nil identifier created using PKToolPickerInkingItem(type: ,color:,width:,identifier: ), changing color or width of an inking item (pen, pencil etc) causes an instant crash. I believe it is a bug in PencilKit. It seems that when you change the color or width of an inking item having a identifier in squeeze tool palette, it tries to find a tool item without identifier (the default tool picker has items without identifier) in the tool items set. I guess it cannot find, thus the find function returns either -1 or highest integer number (2^63 -1 ) and it uses this number as index without boundary checking. That's why we observe [__NSArrayM replaceObjectAtIndex:withObject:]: index 9223372036854775807 beyond bounds [0 .. 9] I filed a report on Feedback Assistant with id: FB15519801 too. The corresponding part in crash report is as follows: 0 CoreFoundation 0x183e0908c __exceptionPreprocess + 164 (NSException.m:249) 1 libobjc.A.dylib 0x18110b2e4 objc_exception_throw + 88 (objc-exception.mm:356) 2 CoreFoundation 0x183de4048 -[__NSArrayM replaceObjectAtIndex:withObject:] + 1020 (NSArrayM.m:180) 3 PencilKit 0x1c44f73c8 -[PKToolPicker _setSelectedTool:saveState:updateUI:updateLastSelectedTool:] + 800 (PKToolPicker.m:587) 4 PencilKit 0x1c45a5684 -[PKPencilSqueezeControllerPaletteViewDelegateProxy paletteView:didSelectTool:atIndex:] + 200 (PKPencilSqueezeControllerPaletteViewDelegateProxy.m:227) 5 PencilKit 0x1c460906c -[PKSqueezePaletteView _didSelectTool:atIndex:] + 196 (PKSqueezePaletteView.m:441) 6 PencilKit 0x1c462203c -[PKSqueezePaletteViewExpandedInkingToolLayout _didTapStrokeWeightButton:] + 336 (PKSqueezePaletteViewExpandedInkingToolLayout.m:224) 7 UIKitCore 0x18691edd8 -[UIApplication sendAction:to:from:forEvent:] + 100 (UIApplication.m:5797) 8 UIKitCore 0x18691ecb0 -[UIControl sendAction:to:forEvent:] + 112 (UIControl.m:942) 9 UIKitCore 0x18691eb00 -[UIControl _sendActionsForEvents:withEvent:] + 324 (UIControl.m:1013) 10 UIKitCore 0x187080568 -[UIButton _sendActionsForEvents:withEvent:] + 124 (UIButton.m:4192) 11 UIKitCore 0x187081d7c -[UIControl touchesEnded:withEvent:] + 400 (UIControl.m:692) 12 UIKitCore 0x1868675b0 -[UIWindow _sendTouchesForEvent:] + 852 (UIWindow.m:3313) and the exception reason is *** -[__NSArrayM replaceObjectAtIndex:withObject:]: index 9223372036854775807 beyond bounds [0 .. 9]
1
0
532
Oct ’24
In PKCanvasview of IOS18, UIPanGestureRecognizer cannot be added
I am creating an application using PKCanvasview. One function of that app is the ability to trace and retrieve a UITextView that has been addSubviewed to a PKCanvasView. We have confirmed that this functionality works correctly in the simulator and on the actual device on IOS 17.4. This feature did not work correctly on the IOS18 simulator and the actual device. Is this a bug? And if it is normal behavior, is there an alternative?
0
0
494
Oct ’24
Critical Rendering Bug in PencilKit on iPad with "More Space" Display Mode & Apple Pencil Hover Interaction
There is a significant rendering issue in PencilKit when using an iPad set to "More Space" display mode, combined with an Apple Pencil that supports hover functionality (e.g., Apple Pencil 2). This problem affects all applications that use PencilKit, including Apple's own Notes and Quick Note. The issue results in flickering black borders and subtle jittering while drawing, which is especially noticeable during tasks requiring precise handwriting, such as writing mathematical expressions. Due to the short strokes and frequent lifts and drops of the pencil, the jitter is much more pronounced, leading to visual discomfort and even dizziness after extended use. Steps to Reproduce: Open Settings on your iPad. Navigate to Display & Brightness > Display Zoom > More Space. Switch to the More Space display mode. Open the Notes app or trigger Quick Note from any application by swiping from the bottom-right corner. Start drawing or writing using the Apple Pencil (with hover functionality) in the writing area. Observe the display anomalies as you hover and write: Flickering black borders appear intermittently around the writing area. The strokes show subtle jittering whenever you lift and lower the pencil. This is particularly disruptive when writing short, precise strokes, such as those in mathematical expressions, where the frequent up-and-down motion makes the jitter more apparent. Expected Results: Smooth and stable drawing experience with no visual artifacts or jittering during interactions with the Apple Pencil, regardless of the display zoom settings. Actual Results: Flickering black borders intermittently appear during drawing. Jittering of strokes is noticeable, particularly when lifting and lowering the Apple Pencil for short strokes. This disrupts precise writing tasks, especially in cases like mathematical notation, where frequent pen lifts and short strokes make the jitter much more apparent. This can lead to discomfort (e.g., dizziness) after extended use. System-Wide Impact: This issue affects all apps that utilize PencilKit, including third-party apps such as Doodle Draw (link). Since PencilKit is a core framework, the rendering bug significantly degrades the user experience across multiple productivity and note-taking applications. Similar Reports: There are numerous discussions about this issue online, indicating that many users are experiencing the same problem. Reddit Discussion: https://www.reddit.com/r/ipad/comments/1f042ol/comment/ljvilv6/ Apple Support Thread Additionally, a feedback report (ID: FB15166022) related to this issue with Notes has been previously filed, but the bug remains unresolved. This bug severely impacts the usability of PencilKit-enabled apps, especially during tasks that involve frequent, precise pencil strokes, such as writing mathematical expressions. We kindly request the development team investigate this issue promptly to ensure a smooth, stable experience with the iPad's "More Space" display mode and Apple Pencil hover interaction.
1
0
740
Sep ’24
PKStroke with inkType == .pencil cannot be consistently restored
Attempting to recreate PKDrawing point-by-point using an existing drawing instance results in .pencil strokes being displayed with different (thinner) width than the original. Strokes with all other inks are restored fully visually identically to the original. This can be observed from iOS 15.2 to iOS 18 beta 5. Code used to remake the drawing: let restoredDrawing = PKDrawing(strokes: drawing.strokes.map { stroke in PKStroke( ink: stroke.ink, path: PKStrokePath(controlPoints: (0..<stroke.path.count).map { controlIndex in // This could be replaced with stroke.path.map { point in } let point = Array(stroke.path)[controlIndex] // This does not result in the same presentation as the point let restoredPoint: PKStrokePoint if #available(iOS 17.0, *) { restoredPoint = PKStrokePoint( location: point.location, timeOffset: point.timeOffset, size: point.size, opacity: point.opacity, force: point.force, azimuth: point.azimuth, altitude: point.altitude, secondaryScale: point.secondaryScale ) } else { restoredPoint = PKStrokePoint( location: point.location, timeOffset: point.timeOffset, size: point.size, opacity: point.opacity, force: point.force, azimuth: point.azimuth, altitude: point.altitude ) } // Even this produces correct result: // let restoredPoint = stroke.path.interpolatedPoint(at: CGFloat(controlIndex)) compare(point, restoredPoint) return restoredPoint }, creationDate: stroke.path.creationDate), transform: stroke.transform, mask: stroke.mask ) }) Gist with ViewController with side-by-side to paste into new project: https://gist.github.com/ilevIO/a1dea60ab6cb16047de2b421897d30f1
0
0
589
Aug ’24
how to change overlay View in PDFPageOverlayViewProvider
I’m using PDFPageOverlayViewProvider with pdfview. I want to control the visibility of the overlay view using a button. However, the view updates only when it disappears and reappears. I would like the changes to be reflected immediately. How can I achieve this? struct PDFKitView: View { let bookId: UUID let bookTitle: String @State private var currentPage = "1" @State private var isSideTab = false @State private var selectedNote: [SelectedNote] = [] var body: some View { let pdfDocument = openPDF(at: bookId.uuidString) ZStack(alignment: .trailing) { HStack(spacing: 0) { PDFKitRepresentableView( bookId: bookId, selectedNote: $selectedNote, currentPage: $currentPage, pdfDocument: pdfDocument ) if isSideTab { SideView() .transition(.move(edge: .trailing)) .zIndex(1) .frame(maxWidth: 260) } } .padding(.top, 73) } .onAppear { getAllNote(bookId: bookId) } .customNavigationBar(back: true) { Text("\(currentPage)/\(pdfDocument.pageCount)") .pretendard(.CaptionRegular) .foregroundStyle(Color.Text.primary) } TrailingView: { Button(action: { withAnimation { isSideTab.toggle() } }) { Image(systemName: SFSymbol.squareStack3dDownForwardFill.icon) .sfPro(.IconMedium) .foregroundStyle(Color.Text.primary) } } } @ViewBuilder func SideView() -> some View { VStack(spacing: 16) { HStack(spacing: 4) { Image(systemName: SFSymbol.squareStack3dDownForwardFill.icon) .sfPro(.IconSmall) .foregroundStyle(Color.Text.primary) Text(Literals.sideTabTitle) .pretendard(.P2Bold) .foregroundStyle(Color.Text.primary) Spacer() } .padding(16) .background { Color.Background.white } ScrollView { ForEach($selectedNote, id: \.noteId) { note in NoteCellView(note: note) } } .background { Color.Fill.white } } .background { Color.Background.blueGray } } @ViewBuilder func NoteCellView(note: Binding<SelectedNote>) -> some View { HStack(alignment: .top, spacing: 16) { Image(.writingNote) .resizable() .scaledToFit() .frame(width: 42, height: 60) VStack(alignment: .leading, spacing: 8) { Text(note.wrappedValue.noteId == bookId.uuidString ? "345" : "123") .foregroundStyle(Color.Text.secondary) .padding(.horizontal, 8) .background { Rectangle() .strokeBorder(Color.Layout.secondary) } Text(bookTitle) .lineLimit(2) Toggle("", isOn: note.selected) .labelsHidden() .tint(Color.Fill.activePrimary) } } .padding(EdgeInsets(top: 20, leading: 16, bottom: 16, trailing: 16)) } } struct PDFKitRepresentableView: UIViewRepresentable { let bookId: UUID @Binding var selectedNote: [SelectedNote] @Binding var currentPage: String let pdfDocument: PDFDocument let pdfView = PDFView() let toolPicker = PKToolPicker() func makeUIView(context: Context) -> PDFView { pdfView.displayMode = .singlePageContinuous pdfView.usePageViewController(false) pdfView.displayDirection = .vertical pdfView.pageOverlayViewProvider = context.coordinator pdfView.autoScales = true pdfDocument.delegate = context.coordinator pdfView.document = pdfDocument return pdfView } func updateUIView(_ uiView: PDFView, context: Context) { if let localNote = selectedNote.first(where: {$0.noteId == bookId.uuidString}), !localNote.selected { toolPicker.setVisible(false, forFirstResponder: uiView) } else { toolPicker.setVisible(true, forFirstResponder: uiView) } uiView.becomeFirstResponder() } func makeCoordinator() -> CanvasProvider { return CanvasProvider(parent: self) } } final class CanvasProvider: NSObject, PDFPageOverlayViewProvider, PDFDocumentDelegate { var localNotes = [PDFPage: PKCanvasView]() var passNotes = [PDFPage: Image]() let parent: PDFKitRepresentableView init(parent: PDFKitRepresentableView) { self.parent = parent super.init() getDrawingDatas( bookId: parent.bookId.uuidString, selectedNote: parent.selectedNote, document: parent.pdfDocument ) } func pdfView(_ view: PDFView, overlayViewFor page: PDFPage) -> UIView? { var coverView: PKCanvasView? = PKCanvasView() if let view = localNotes[page], parent.selectedNote.first(where: { $0.noteId == parent.bookId.uuidString })?.selected ?? false { view.backgroundColor = .clear view.isOpaque = true view.drawingPolicy = .anyInput view.delegate = self parent.toolPicker.addObserver(view) coverView = view (page as? CanvasPDFPage)?.canvasView = view } else { coverView = nil } for subView in view.documentView?.subviews ?? [] { if subView.theClassName == "PDFPageView" { subView.isUserInteractionEnabled = true } } return coverView } func pdfView(_ pdfView: PDFView, willDisplayOverlayView overlayView: UIView, for page: PDFPage) { } func pdfView(_ pdfView: PDFView, willEndDisplayingOverlayView overlayView: UIView, for page: PDFPage) { } }
0
0
774
Aug ’24
iOS 17 Opening the color picker results in an permanently visible PKToolBar
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?
11
3
6.1k
Aug ’24
Disable Smart Selection feature on PKCanvasView
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.
2
2
1.7k
Jul ’24
PKCanvasView working on preview, but not on simulator or app
Hey, so I am working on a note taking part of my app and I have been working on allowing different inputs. I got the PKCanvas to work on the preview and on the simulator when it is the only thing on the window group. But when I use this View as part of the tool selection in my app, when the user selects the Canvas view it loads but scribbles don't work, only in the preview in Xcode. I don't know why this behavior is happening. The flow in which the PKCanvasView appears is, user taps NavLink to see their notes, in the NotesView they tap to show the toolbar, toolbar has 4 types of input, text, images, audio, scribbles (all other inputs work accordingly), user taps scribbles the view loads correctly but doesn't allow them to draw. I have set the drawingPolicy to anyInput
0
0
592
Jun ’24
PencilKit custom tool
Hi, can i create custom tool for PKToolPicker? On documentation page on PKTool says "Don’t adopt this protocol in your own objects. Instead, create a tool object to provide users with the desired the tool behavior." Best regards, Matej Klemen
1
1
1.3k
Jun ’24
PKToolPicker not appearing in iPad compatibility mode on Vision Pro
Has anyone got PKToolPicker appearing in an iPad app running in compatibility mode on Vision Pro? In our app, it appears fine on iPad, but not in the Vision Pro simulator. Even though the tools do not appear, I am able to draw in the canvas (...though not change the pen, of course). I did not read anywhere that it was not supported on Vision Pro. I only saw that interactions with pencil do not work, but that other forms of interaction (eg drawing with touch) should work. Anyone seen it working on Vision Pro?
1
1
1k
Jun ’24
PKToolPicker Available Tools
When I display the PKToolPicker in my app it looks similar to the image below If you use one of the apps from Apple like Pages or Freeform you see a picker similar to this one. Notice that the PKToolPicker from the Apple app has 6 tools not including the ruler. With the tool all the way to the left being the writing tool. How do you get the picker to display with the writing tool? I have looked over the API and I can see where you can set if the ruler is displayed or not but I can't find anything for the writing tool
1
0
1.2k
Jun ’24
PKCanvasView won't react to updates of its contentScaleFactor
Dear All, I am currently facing a challenge with updating the contentScaleFactor of my PKCanvasView, which is embedded within a custom UIScrollView. I have configured the PKCanvasView to have both its maximum and minimum zoomScale set to 1.0, ensuring that users can only zoom into the UIScrollView and not directly into the PKCanvasView. Upon the completion of a zoom action in my UIScrollView, a notification is published and received by the PKCanvasView. This triggers a function intended to update the contentScaleFactor. However, this process is not functioning as expected. Despite consulting with several engineers at WWDC24 and exploring multiple potential solutions, the issue remains unresolved. Interestingly, when zooming into a PDF in the Documents app on iOS 17, the strokes are re-rendered perfectly, while in previous iOS versions, this bug persists in the Documents app. I would greatly appreciate any insights or solutions from those who might have encountered and resolved this issue. Thank you in advance for your assistance. Best regards, Timon
0
1
713
Jun ’24
Retrieve Apple Pencil Pro Orientation, Roll outside of HoverPose?
I'm attempting to retrieve the values of the Pencil Pro using the new PencilHoverPose, however according to the documentation it appears these can only be accessed while in a hover state (0 to ~0.5" from the screen). Is there a way to get the orientation or roll values of the Apple Pencil Pro outside of a hover? I'm attempting to use the pencil as an input device, necessitating it be farther from the screen than 0.5" Below is a simple view I'm using to display the available values: import SwiftUI import UIKit struct PencilSqueezeView: View { @State private var squeezeText: String = "Squeeze the Apple Pencil Pro" @State private var hoverDistance: CGFloat = 0.0 @State private var anchor: UnitPoint = .center @State private var location: CGPoint = .zero @State private var altitude: Angle = .degrees(0) @State private var azimuth: Angle = .degrees(0) @State private var roll: Angle = .degrees(0) var body: some View { VStack { Text(squeezeText) .font(.largeTitle) .padding() Text("Hover Distance: \(String(format: "%.2f", hoverDistance))") .font(.title2) .padding() Text("Anchor: \(anchor)") .font(.title2) .padding() Text("Location: \(location.x), \(location.y)") .font(.title2) .padding() Text("Altitude: \(altitude.degrees)°") .font(.title2) .padding() Text("Azimuth: \(azimuth.degrees)°") .font(.title2) .padding() Text("Roll: \(roll.degrees)°") .font(.title2) .padding() Spacer() } .onPencilSqueeze { phase in handlePencilSqueeze(phase: phase) if case let .ended(value) = phase { if let hoverPose = value.hoverPose { updateHoverPose(hoverPose) } else { print("hoverPose is nil") } } } .padding() } private func handlePencilSqueeze(phase: PencilSqueezeGesturePhase) { switch phase { case .active: squeezeText = "Squeeze began" case .ended: squeezeText = "Squeeze ended" case .failed: squeezeText = "Squeeze failed" } } private func updateHoverPose(_ hoverPose: PencilHoverPose) { hoverDistance = hoverPose.zDistance anchor = hoverPose.anchor location = hoverPose.location altitude = hoverPose.altitude azimuth = hoverPose.azimuth roll = hoverPose.roll print("zDistance: \(hoverPose.zDistance)") print("anchor: \(hoverPose.anchor)") print("location: \(hoverPose.location)") print("altitude: \(hoverPose.altitude)") print("azimuth: \(hoverPose.azimuth)") print("roll: \(hoverPose.roll)") } }
1
0
819
Jun ’24
Disable Scribble in UITextView
There are use cases where someone who's using an Apple Pencil may not want to enter text via Scribble. A simple example is writing "UIViewController" in a text view is unlikely to be successful. I'd like to disable Scribble in this case and let the keyboard become the input mechanism. (Disabling Scribble system-wide in Settings is both cumbersome and overkill.) The closest I can come to making this happen is by adding a UIScribbleInteraction on a UITextView and returning false when scribbleInteraction(shouldBeginAt:) is called. This disables Scribble on the text view, and prevents writing from being converted into text, but the input widget still appears on screen and isn't very useful. Here is a sample project that demonstrates the problem: http://files.iconfactory.net/craig/bugs/Scribbler.zip Hopefully, I'm doing something wrong here. If not, I'm happy to submit this as a FB. -ch
Replies
3
Boosts
0
Views
3.3k
Activity
Nov ’24
Changing the color or width of an inking tool on squeeze tool palette causes crash
When a custom tool items set is formed in PKToolPicker with each inking item having non-nil identifier created using PKToolPickerInkingItem(type: ,color:,width:,identifier: ), changing color or width of an inking item (pen, pencil etc) causes an instant crash. I believe it is a bug in PencilKit. It seems that when you change the color or width of an inking item having a identifier in squeeze tool palette, it tries to find a tool item without identifier (the default tool picker has items without identifier) in the tool items set. I guess it cannot find, thus the find function returns either -1 or highest integer number (2^63 -1 ) and it uses this number as index without boundary checking. That's why we observe [__NSArrayM replaceObjectAtIndex:withObject:]: index 9223372036854775807 beyond bounds [0 .. 9] I filed a report on Feedback Assistant with id: FB15519801 too. The corresponding part in crash report is as follows: 0 CoreFoundation 0x183e0908c __exceptionPreprocess + 164 (NSException.m:249) 1 libobjc.A.dylib 0x18110b2e4 objc_exception_throw + 88 (objc-exception.mm:356) 2 CoreFoundation 0x183de4048 -[__NSArrayM replaceObjectAtIndex:withObject:] + 1020 (NSArrayM.m:180) 3 PencilKit 0x1c44f73c8 -[PKToolPicker _setSelectedTool:saveState:updateUI:updateLastSelectedTool:] + 800 (PKToolPicker.m:587) 4 PencilKit 0x1c45a5684 -[PKPencilSqueezeControllerPaletteViewDelegateProxy paletteView:didSelectTool:atIndex:] + 200 (PKPencilSqueezeControllerPaletteViewDelegateProxy.m:227) 5 PencilKit 0x1c460906c -[PKSqueezePaletteView _didSelectTool:atIndex:] + 196 (PKSqueezePaletteView.m:441) 6 PencilKit 0x1c462203c -[PKSqueezePaletteViewExpandedInkingToolLayout _didTapStrokeWeightButton:] + 336 (PKSqueezePaletteViewExpandedInkingToolLayout.m:224) 7 UIKitCore 0x18691edd8 -[UIApplication sendAction:to:from:forEvent:] + 100 (UIApplication.m:5797) 8 UIKitCore 0x18691ecb0 -[UIControl sendAction:to:forEvent:] + 112 (UIControl.m:942) 9 UIKitCore 0x18691eb00 -[UIControl _sendActionsForEvents:withEvent:] + 324 (UIControl.m:1013) 10 UIKitCore 0x187080568 -[UIButton _sendActionsForEvents:withEvent:] + 124 (UIButton.m:4192) 11 UIKitCore 0x187081d7c -[UIControl touchesEnded:withEvent:] + 400 (UIControl.m:692) 12 UIKitCore 0x1868675b0 -[UIWindow _sendTouchesForEvent:] + 852 (UIWindow.m:3313) and the exception reason is *** -[__NSArrayM replaceObjectAtIndex:withObject:]: index 9223372036854775807 beyond bounds [0 .. 9]
Replies
1
Boosts
0
Views
532
Activity
Oct ’24
In PKCanvasview of IOS18, UIPanGestureRecognizer cannot be added
I am creating an application using PKCanvasview. One function of that app is the ability to trace and retrieve a UITextView that has been addSubviewed to a PKCanvasView. We have confirmed that this functionality works correctly in the simulator and on the actual device on IOS 17.4. This feature did not work correctly on the IOS18 simulator and the actual device. Is this a bug? And if it is normal behavior, is there an alternative?
Replies
0
Boosts
0
Views
494
Activity
Oct ’24
Critical Rendering Bug in PencilKit on iPad with "More Space" Display Mode & Apple Pencil Hover Interaction
There is a significant rendering issue in PencilKit when using an iPad set to "More Space" display mode, combined with an Apple Pencil that supports hover functionality (e.g., Apple Pencil 2). This problem affects all applications that use PencilKit, including Apple's own Notes and Quick Note. The issue results in flickering black borders and subtle jittering while drawing, which is especially noticeable during tasks requiring precise handwriting, such as writing mathematical expressions. Due to the short strokes and frequent lifts and drops of the pencil, the jitter is much more pronounced, leading to visual discomfort and even dizziness after extended use. Steps to Reproduce: Open Settings on your iPad. Navigate to Display & Brightness > Display Zoom > More Space. Switch to the More Space display mode. Open the Notes app or trigger Quick Note from any application by swiping from the bottom-right corner. Start drawing or writing using the Apple Pencil (with hover functionality) in the writing area. Observe the display anomalies as you hover and write: Flickering black borders appear intermittently around the writing area. The strokes show subtle jittering whenever you lift and lower the pencil. This is particularly disruptive when writing short, precise strokes, such as those in mathematical expressions, where the frequent up-and-down motion makes the jitter more apparent. Expected Results: Smooth and stable drawing experience with no visual artifacts or jittering during interactions with the Apple Pencil, regardless of the display zoom settings. Actual Results: Flickering black borders intermittently appear during drawing. Jittering of strokes is noticeable, particularly when lifting and lowering the Apple Pencil for short strokes. This disrupts precise writing tasks, especially in cases like mathematical notation, where frequent pen lifts and short strokes make the jitter much more apparent. This can lead to discomfort (e.g., dizziness) after extended use. System-Wide Impact: This issue affects all apps that utilize PencilKit, including third-party apps such as Doodle Draw (link). Since PencilKit is a core framework, the rendering bug significantly degrades the user experience across multiple productivity and note-taking applications. Similar Reports: There are numerous discussions about this issue online, indicating that many users are experiencing the same problem. Reddit Discussion: https://www.reddit.com/r/ipad/comments/1f042ol/comment/ljvilv6/ Apple Support Thread Additionally, a feedback report (ID: FB15166022) related to this issue with Notes has been previously filed, but the bug remains unresolved. This bug severely impacts the usability of PencilKit-enabled apps, especially during tasks that involve frequent, precise pencil strokes, such as writing mathematical expressions. We kindly request the development team investigate this issue promptly to ensure a smooth, stable experience with the iPad's "More Space" display mode and Apple Pencil hover interaction.
Replies
1
Boosts
0
Views
740
Activity
Sep ’24
I want to add image and textfield to pkcanvasview.
I want to add a pkcanvasview image and change its position and size by dragging. And I want to draw a picture using a pencil on top. The image must be able to change its position at any time, and a picture must be added on top. If I add it to the subview of pkcanvasview, I cannot do what I want. How can I do this?
Replies
0
Boosts
0
Views
550
Activity
Sep ’24
PKStroke with inkType == .pencil cannot be consistently restored
Attempting to recreate PKDrawing point-by-point using an existing drawing instance results in .pencil strokes being displayed with different (thinner) width than the original. Strokes with all other inks are restored fully visually identically to the original. This can be observed from iOS 15.2 to iOS 18 beta 5. Code used to remake the drawing: let restoredDrawing = PKDrawing(strokes: drawing.strokes.map { stroke in PKStroke( ink: stroke.ink, path: PKStrokePath(controlPoints: (0..<stroke.path.count).map { controlIndex in // This could be replaced with stroke.path.map { point in } let point = Array(stroke.path)[controlIndex] // This does not result in the same presentation as the point let restoredPoint: PKStrokePoint if #available(iOS 17.0, *) { restoredPoint = PKStrokePoint( location: point.location, timeOffset: point.timeOffset, size: point.size, opacity: point.opacity, force: point.force, azimuth: point.azimuth, altitude: point.altitude, secondaryScale: point.secondaryScale ) } else { restoredPoint = PKStrokePoint( location: point.location, timeOffset: point.timeOffset, size: point.size, opacity: point.opacity, force: point.force, azimuth: point.azimuth, altitude: point.altitude ) } // Even this produces correct result: // let restoredPoint = stroke.path.interpolatedPoint(at: CGFloat(controlIndex)) compare(point, restoredPoint) return restoredPoint }, creationDate: stroke.path.creationDate), transform: stroke.transform, mask: stroke.mask ) }) Gist with ViewController with side-by-side to paste into new project: https://gist.github.com/ilevIO/a1dea60ab6cb16047de2b421897d30f1
Replies
0
Boosts
0
Views
589
Activity
Aug ’24
Configuring the PencilKit tool picker - Build Failure
The sample code project PencilKitCustomToolPicker found at this article Configuring the PencilKit tool picker here fails to compile with the following errors in Xcode 16 beta 6
Replies
2
Boosts
0
Views
825
Activity
Aug ’24
how to change overlay View in PDFPageOverlayViewProvider
I’m using PDFPageOverlayViewProvider with pdfview. I want to control the visibility of the overlay view using a button. However, the view updates only when it disappears and reappears. I would like the changes to be reflected immediately. How can I achieve this? struct PDFKitView: View { let bookId: UUID let bookTitle: String @State private var currentPage = "1" @State private var isSideTab = false @State private var selectedNote: [SelectedNote] = [] var body: some View { let pdfDocument = openPDF(at: bookId.uuidString) ZStack(alignment: .trailing) { HStack(spacing: 0) { PDFKitRepresentableView( bookId: bookId, selectedNote: $selectedNote, currentPage: $currentPage, pdfDocument: pdfDocument ) if isSideTab { SideView() .transition(.move(edge: .trailing)) .zIndex(1) .frame(maxWidth: 260) } } .padding(.top, 73) } .onAppear { getAllNote(bookId: bookId) } .customNavigationBar(back: true) { Text("\(currentPage)/\(pdfDocument.pageCount)") .pretendard(.CaptionRegular) .foregroundStyle(Color.Text.primary) } TrailingView: { Button(action: { withAnimation { isSideTab.toggle() } }) { Image(systemName: SFSymbol.squareStack3dDownForwardFill.icon) .sfPro(.IconMedium) .foregroundStyle(Color.Text.primary) } } } @ViewBuilder func SideView() -> some View { VStack(spacing: 16) { HStack(spacing: 4) { Image(systemName: SFSymbol.squareStack3dDownForwardFill.icon) .sfPro(.IconSmall) .foregroundStyle(Color.Text.primary) Text(Literals.sideTabTitle) .pretendard(.P2Bold) .foregroundStyle(Color.Text.primary) Spacer() } .padding(16) .background { Color.Background.white } ScrollView { ForEach($selectedNote, id: \.noteId) { note in NoteCellView(note: note) } } .background { Color.Fill.white } } .background { Color.Background.blueGray } } @ViewBuilder func NoteCellView(note: Binding<SelectedNote>) -> some View { HStack(alignment: .top, spacing: 16) { Image(.writingNote) .resizable() .scaledToFit() .frame(width: 42, height: 60) VStack(alignment: .leading, spacing: 8) { Text(note.wrappedValue.noteId == bookId.uuidString ? "345" : "123") .foregroundStyle(Color.Text.secondary) .padding(.horizontal, 8) .background { Rectangle() .strokeBorder(Color.Layout.secondary) } Text(bookTitle) .lineLimit(2) Toggle("", isOn: note.selected) .labelsHidden() .tint(Color.Fill.activePrimary) } } .padding(EdgeInsets(top: 20, leading: 16, bottom: 16, trailing: 16)) } } struct PDFKitRepresentableView: UIViewRepresentable { let bookId: UUID @Binding var selectedNote: [SelectedNote] @Binding var currentPage: String let pdfDocument: PDFDocument let pdfView = PDFView() let toolPicker = PKToolPicker() func makeUIView(context: Context) -> PDFView { pdfView.displayMode = .singlePageContinuous pdfView.usePageViewController(false) pdfView.displayDirection = .vertical pdfView.pageOverlayViewProvider = context.coordinator pdfView.autoScales = true pdfDocument.delegate = context.coordinator pdfView.document = pdfDocument return pdfView } func updateUIView(_ uiView: PDFView, context: Context) { if let localNote = selectedNote.first(where: {$0.noteId == bookId.uuidString}), !localNote.selected { toolPicker.setVisible(false, forFirstResponder: uiView) } else { toolPicker.setVisible(true, forFirstResponder: uiView) } uiView.becomeFirstResponder() } func makeCoordinator() -> CanvasProvider { return CanvasProvider(parent: self) } } final class CanvasProvider: NSObject, PDFPageOverlayViewProvider, PDFDocumentDelegate { var localNotes = [PDFPage: PKCanvasView]() var passNotes = [PDFPage: Image]() let parent: PDFKitRepresentableView init(parent: PDFKitRepresentableView) { self.parent = parent super.init() getDrawingDatas( bookId: parent.bookId.uuidString, selectedNote: parent.selectedNote, document: parent.pdfDocument ) } func pdfView(_ view: PDFView, overlayViewFor page: PDFPage) -> UIView? { var coverView: PKCanvasView? = PKCanvasView() if let view = localNotes[page], parent.selectedNote.first(where: { $0.noteId == parent.bookId.uuidString })?.selected ?? false { view.backgroundColor = .clear view.isOpaque = true view.drawingPolicy = .anyInput view.delegate = self parent.toolPicker.addObserver(view) coverView = view (page as? CanvasPDFPage)?.canvasView = view } else { coverView = nil } for subView in view.documentView?.subviews ?? [] { if subView.theClassName == "PDFPageView" { subView.isUserInteractionEnabled = true } } return coverView } func pdfView(_ pdfView: PDFView, willDisplayOverlayView overlayView: UIView, for page: PDFPage) { } func pdfView(_ pdfView: PDFView, willEndDisplayingOverlayView overlayView: UIView, for page: PDFPage) { } }
Replies
0
Boosts
0
Views
774
Activity
Aug ’24
PKStrokePath to CoreGraphics path
Hey guys, Is there a native bridge between a PKStrokePath and other path objects like CGPath, UIBezierPath or even SwiftUI Path ?
Replies
2
Boosts
1
Views
1.5k
Activity
Aug ’24
iOS 17 Opening the color picker results in an permanently visible PKToolBar
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?
Replies
11
Boosts
3
Views
6.1k
Activity
Aug ’24
Disable Smart Selection feature on PKCanvasView
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.
Replies
2
Boosts
2
Views
1.7k
Activity
Jul ’24
PDFKit and PencilKit
Does anybody knows how to implement draw on pdf function for iOS? Approach is the same as Files app. Telegram and Whatsapp using the same technique.
Replies
0
Boosts
0
Views
740
Activity
Jul ’24
PKCanvasView working on preview, but not on simulator or app
Hey, so I am working on a note taking part of my app and I have been working on allowing different inputs. I got the PKCanvas to work on the preview and on the simulator when it is the only thing on the window group. But when I use this View as part of the tool selection in my app, when the user selects the Canvas view it loads but scribbles don't work, only in the preview in Xcode. I don't know why this behavior is happening. The flow in which the PKCanvasView appears is, user taps NavLink to see their notes, in the NotesView they tap to show the toolbar, toolbar has 4 types of input, text, images, audio, scribbles (all other inputs work accordingly), user taps scribbles the view loads correctly but doesn't allow them to draw. I have set the drawingPolicy to anyInput
Replies
0
Boosts
0
Views
592
Activity
Jun ’24
PencilKit custom tool
Hi, can i create custom tool for PKToolPicker? On documentation page on PKTool says "Don’t adopt this protocol in your own objects. Instead, create a tool object to provide users with the desired the tool behavior." Best regards, Matej Klemen
Replies
1
Boosts
1
Views
1.3k
Activity
Jun ’24
PencilKit PKToolPicker add tools or get height
on iOS, I want to add up undo/redo and a close button. On ipadOS, I only need to add a close button What’s your experience in adding a close button to the ToolPicker? Or at least have the position of the window so I can add an overlapping box (even on floating).
Replies
1
Boosts
0
Views
1.6k
Activity
Jun ’24
PKToolPicker not appearing in iPad compatibility mode on Vision Pro
Has anyone got PKToolPicker appearing in an iPad app running in compatibility mode on Vision Pro? In our app, it appears fine on iPad, but not in the Vision Pro simulator. Even though the tools do not appear, I am able to draw in the canvas (...though not change the pen, of course). I did not read anywhere that it was not supported on Vision Pro. I only saw that interactions with pencil do not work, but that other forms of interaction (eg drawing with touch) should work. Anyone seen it working on Vision Pro?
Replies
1
Boosts
1
Views
1k
Activity
Jun ’24
Fill Tool for PencilKit PKToolPicker
In the recent WWDC 2022, FreeForm app was introduced and in that app in the tool picker there was a Fill Tool. I want to put that fill tool (or any similar filling tool) in my xcode app that I am building. But when I use pencilkit PKToolPicker, there is not Fill Tool. So how to get this fill tool in my app. Any leads would be helpful. Thanks.
Replies
4
Boosts
5
Views
2.6k
Activity
Jun ’24
PKToolPicker Available Tools
When I display the PKToolPicker in my app it looks similar to the image below If you use one of the apps from Apple like Pages or Freeform you see a picker similar to this one. Notice that the PKToolPicker from the Apple app has 6 tools not including the ruler. With the tool all the way to the left being the writing tool. How do you get the picker to display with the writing tool? I have looked over the API and I can see where you can set if the ruler is displayed or not but I can't find anything for the writing tool
Replies
1
Boosts
0
Views
1.2k
Activity
Jun ’24
PKCanvasView won't react to updates of its contentScaleFactor
Dear All, I am currently facing a challenge with updating the contentScaleFactor of my PKCanvasView, which is embedded within a custom UIScrollView. I have configured the PKCanvasView to have both its maximum and minimum zoomScale set to 1.0, ensuring that users can only zoom into the UIScrollView and not directly into the PKCanvasView. Upon the completion of a zoom action in my UIScrollView, a notification is published and received by the PKCanvasView. This triggers a function intended to update the contentScaleFactor. However, this process is not functioning as expected. Despite consulting with several engineers at WWDC24 and exploring multiple potential solutions, the issue remains unresolved. Interestingly, when zooming into a PDF in the Documents app on iOS 17, the strokes are re-rendered perfectly, while in previous iOS versions, this bug persists in the Documents app. I would greatly appreciate any insights or solutions from those who might have encountered and resolved this issue. Thank you in advance for your assistance. Best regards, Timon
Replies
0
Boosts
1
Views
713
Activity
Jun ’24
Retrieve Apple Pencil Pro Orientation, Roll outside of HoverPose?
I'm attempting to retrieve the values of the Pencil Pro using the new PencilHoverPose, however according to the documentation it appears these can only be accessed while in a hover state (0 to ~0.5" from the screen). Is there a way to get the orientation or roll values of the Apple Pencil Pro outside of a hover? I'm attempting to use the pencil as an input device, necessitating it be farther from the screen than 0.5" Below is a simple view I'm using to display the available values: import SwiftUI import UIKit struct PencilSqueezeView: View { @State private var squeezeText: String = "Squeeze the Apple Pencil Pro" @State private var hoverDistance: CGFloat = 0.0 @State private var anchor: UnitPoint = .center @State private var location: CGPoint = .zero @State private var altitude: Angle = .degrees(0) @State private var azimuth: Angle = .degrees(0) @State private var roll: Angle = .degrees(0) var body: some View { VStack { Text(squeezeText) .font(.largeTitle) .padding() Text("Hover Distance: \(String(format: "%.2f", hoverDistance))") .font(.title2) .padding() Text("Anchor: \(anchor)") .font(.title2) .padding() Text("Location: \(location.x), \(location.y)") .font(.title2) .padding() Text("Altitude: \(altitude.degrees)°") .font(.title2) .padding() Text("Azimuth: \(azimuth.degrees)°") .font(.title2) .padding() Text("Roll: \(roll.degrees)°") .font(.title2) .padding() Spacer() } .onPencilSqueeze { phase in handlePencilSqueeze(phase: phase) if case let .ended(value) = phase { if let hoverPose = value.hoverPose { updateHoverPose(hoverPose) } else { print("hoverPose is nil") } } } .padding() } private func handlePencilSqueeze(phase: PencilSqueezeGesturePhase) { switch phase { case .active: squeezeText = "Squeeze began" case .ended: squeezeText = "Squeeze ended" case .failed: squeezeText = "Squeeze failed" } } private func updateHoverPose(_ hoverPose: PencilHoverPose) { hoverDistance = hoverPose.zDistance anchor = hoverPose.anchor location = hoverPose.location altitude = hoverPose.altitude azimuth = hoverPose.azimuth roll = hoverPose.roll print("zDistance: \(hoverPose.zDistance)") print("anchor: \(hoverPose.anchor)") print("location: \(hoverPose.location)") print("altitude: \(hoverPose.altitude)") print("azimuth: \(hoverPose.azimuth)") print("roll: \(hoverPose.roll)") } }
Replies
1
Boosts
0
Views
819
Activity
Jun ’24