Can we add text, shape and signature in Photo Markup with Pencil Kit?
Asked Answered
D

1

12

I am not getting any option to add text, shape and signature while markup a photo with PencelKit in my app. This option is available in Apple's Photos App. I have tried to access this with various properties of CanvasView and PKToolPicker, but with no success.

self.canvasView?.drawing = PKDrawing()
self.canvasView.allowsFingerDrawing = true
if let window = self.view.window, let toolPicker = PKToolPicker.shared(for: window) {
     toolPicker.setVisible(true, forFirstResponder: self.canvasView)
     toolPicker.addObserver(self.canvasView)
     self.canvasView.becomeFirstResponder()
}
Dekko answered 27/2, 2020 at 11:3 Comment(2)
I have the same need, but can not find a solution to it :(Genuflection
If anyone knows how, please tell us!Salesmanship
S
9

I figured it out, finally! It's the QLPreviewController!

Editing with shapes, arrows and signature is only available for iOS13+. First of all we need to read the file from an url, so set it up with init. I go with something like this as base and append the filename, also with file extension, e.g. .pdf:

FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last!

You can't save it in the tempDirectory, because the QLPreviewViewController needs access. No permission could result in an error like this:

AX Lookup problem - errorCode:1100 error:Permission denied portName:

Your customVC should look like this:

import UIKit
import QuickLook
class CustomVC: UIViewController {
    var url: URL    

    init(url: URL) {
        self.url = url
    }

....func viewDidLoad() and stuff ......

    func editFile() {
        let editor = QLPreviewController()
        editor.dataSource = self
        editor.delegate = self
        editor.setEditing(true, animated: true)
        present(editor, animated: true, completion: nil)
    }
}

// Load the file in the QLPreviewController with DataSource
extension CustomVC: QLPreviewControllerDataSource {
    func numberOfPreviewItems(in controller: QLPreviewController) -> Int {
        return 1
    }
    
    func previewController(_ controller: QLPreviewController, previewItemAt index: Int) -> QLPreviewItem {
        return self.url! as QLPreviewItem
    }  
}

// Make editing available with Delegate
@available(iOS 13.0, *)
extension CustomVC: QLPreviewControllerDelegate {
    
    func previewController(_ controller: QLPreviewController, editingModeFor previewItem: QLPreviewItem) -> QLPreviewItemEditingMode {
        return .updateContents
    }
    
    func previewController(_ controller: QLPreviewController, didUpdateContentsOf previewItem: QLPreviewItem) {
        print("UPDATE")
    }
    
    func previewController(_ controller: QLPreviewController, didSaveEditedCopyOf previewItem: QLPreviewItem, at modifiedContentsURL: URL) {
        print("SAVED at \(modifiedContentsURL)")
    }
}

The markup button will show automatically if you have implemented these functions in the delegate correctly.

You can also add more barButtonItems for this VC like normal with an extra navigationController, e.g. something like this in the editFile function:

        let navController = UINavigationController(rootViewController: editor)
        let customButton = UIBarButtonItem(image: UIImage(systemName: "yourImageName"), style: .plain, target: self, action: #selector(customButtonTapped(_:)))
        let doneButton = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(doneButtonTapped(_:)))

        if var items = editor.navigationItem.rightBarButtonItems {
            items.append(customButton)
            editor.navigationItem.rightBarButtonItems = items
        } else {
            editor.navigationItem.rightBarButtonItems = [customButton]
        }
        editor.navigationItem.leftBarButtonItem = doneButton
        viewController?.present(navController, animated: true, completion: nil)
        self.navigationController = navController
Salesmanship answered 11/8, 2021 at 13:33 Comment(1)
Thanks for this option... But when editions are done, and user clicks DONE nav item, the QLP asks to save the image in storage... is there any workaround to have the resulting image called back in the app ?Socket

© 2022 - 2024 — McMap. All rights reserved.