I'd like to be able to load a PNG file into a PKCanvasView to be able to draw on and erase parts of it. Is there a way to accomplish this?
-
Have you figured out how to do this? – Tom Kraina Aug 07 '19 at 10:59
-
@TomKraina Not yet, trying to work around it. – rawbee Sep 05 '19 at 02:53
-
2Any update yet? I have the same problem. I'm gonna try dragging a `UIImageView` into the `PKCanvas`, as that seems to work – Tometoyou Sep 20 '19 at 09:06
-
1Any solution yet? I want to add u UIImage from the user into the canvas and do some editing with PencilKit – Victor Sanchez Dec 17 '19 at 13:49
4 Answers
First, put your UIImageView behind PKCanvasView, then set the PKCanvasView opaque to false, and color to clear.
Then in PKCanvasViewDelegate:
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return YOUR_IMAGEVIEW
}
func scrollViewDidZoom(_ scrollView: UIScrollView) {
let offsetX: CGFloat = max((scrollView.bounds.size.width - scrollView.contentSize.width) * 0.5, 0.0)
let offsetY: CGFloat = max((scrollView.bounds.size.height - scrollView.contentSize.height) * 0.5, 0.0)
YOUR_IMAGEVIEW.frame.size = CGSize(width: self.view.bounds.width * scrollView.zoomScale, height: self.view.bounds.height * scrollView.zoomScale)
YOUR_IMAGEVIEW.center = CGPoint(x: scrollView.contentSize.width * 0.5 + offsetX, y: scrollView.contentSize.height * 0.5 + offsetY)
}
As apple said, putting your imageView in viewForZooming is enough, but It doesn't work. So I added above codes in scrollViewDidZoom and it just works as it is supposed to be.

- 89
- 10
I can't find any official documentation about this, but I make it work by adding a UIImageView as subview of first subview of PKCanvasView. Zooming is also working perfectly by setting both .maximumZoomScale=1 and .minimumZoomScale=5
But notice this might not work in the future as Apple might change their implementation of PKCanvasView
Here's the sample code for SwiftUI
func makeUIView(context: Context) -> UIView {
let view = PKCanvasView()
...
...
view.backgroundColor = .clear
view.isOpaque = false
view.maximumZoomScale = 5
view.minimumZoomScale = 1
let imageView = UIImageView(image: UIImage(named: "NameOfImage"))
let contentView = Tool.getContentViewFromPkCanvasView(view)
contentView.addSubview(imageView)
contentView.sendSubviewToBack(imageView)
return view
}
class Tool{
static func getContentViewFromPkCanvasView(_ view: UIView) -> some UIView {
return view.subviews[0]
}
}

- 41
- 3
-
This is clever, but unfortunately, it still just acts like a background image—you're not able to erase for example. – rawbee Apr 27 '20 at 00:54
-
1. this probably (i.e. most definitely) is a bad idea because apple can change the canvas view's internal structure at any time, in which case this would stop working (and would, in the worst case, crash); 2. there's no need to use `some UIView` as the return type. `subviews` is an `[UIView]`, so the type is fixed and the `some` doesn't do anything. (also, `UIView` is not generic in the first place) – lukas Aug 27 '21 at 13:57
Use an UIImageView and put it behind PKCanvasView, then set the PKCanvasView opaque to false, and color to clear. Draw on it is fine, but erase is not possible.

- 8,704
- 9
- 49
- 88
Use setDrawing of PKCanvasView
https://developer.apple.com/documentation/pencilkit/pkcanvasview/3229950-drawing
See 26:53 duration of Session video 221

- 666
- 6
- 19
-
2
-
maybe not useful for PNGs but I stumbled across this SO question and this answer is exactly what I needed. I'm making a drawing app and needed to figure out how to save and load drawings. – Vlad the Impala Nov 20 '20 at 22:34