Search code examples
iosswiftswiftuipdfkit

Is there a way to store a pdf annotation on a click?


I'm building a Machine Learning app to read info of pdfs, to train my algorithm I need to get the pdf annotations location. Is there a way to set a gesture recognizer and add the annotation to an array upon click? I successfully added the annotations to a pdf upon a regex. But I need to add the annotation and its associated info (location in the document upon a click) can I add a gesture recognizer to an app? My app uses SwiftUI.

func makeNSView(context: NSViewRepresentableContext<PDFViewRepresentedView>) -> PDFViewRepresentedView.NSViewType {
    let pdfView = PDFView()
    let document = PDFDocument(url: url)
    let regex = try! NSRegularExpression(pattern: #"[0-9.,]+(,|\.)\d\d"#, options: .caseInsensitive)
    let string = document?.string!
    let results = regex.matches(in: string!, options: .withoutAnchoringBounds, range: NSRange(0..<(string?.utf16.count)!))
    let page = document?.page(at: 0)!
    results.forEach { (result) in
        let startIndex = result.range.location
        let endIndex = result.range.location + result.range.length - 1
        let selection = document?.selection(from: page!, atCharacterIndex: startIndex, to: page!, atCharacterIndex: endIndex)
        print(selection!.bounds(for: page!))
        let pdfAnnotation = PDFAnnotation(bounds: (selection?.bounds(for: page!))!, forType: .square, withProperties: nil)
        document?.page(at: 0)?.addAnnotation(pdfAnnotation)
    }
    pdfView.document = document
    return pdfView
}

and get the tap in

func annotationTapping(_ sender: NSClickGestureRecognizer){
    print("------- annotationTapping ------")
}

If some one has achieved this, by adding an observer or something like this?

Thanks


Solution

  • The PDFView already has a tap gesture recognizer attached for annotations, so no need to add another one. When a tap occurs it will publish a PDFViewAnnotationHit notification. The annotation object can be found in the userInfo.

    Set up an observer for the notification in makeUIView or wherever else makes sense.

    NotificationCenter.default.addObserver(forName: .PDFViewAnnotationHit, object: nil, queue: nil) { (notification) in
          if let annotation = notification.userInfo?["PDFAnnotationHit"] as? PDFAnnotation {
            print(annotation.debugDescription)
          }
        }
    

    or better, handle the notification in your SwiftUI View.

     @State private var selectedAnnotation: PDFAnnotation?
      
      var body: some View {
        VStack {
          Text("Selected Annotation Bounds: \(selectedAnnotation?.bounds.debugDescription ?? "none")")
          SomeView()
            .onReceive(NotificationCenter.default.publisher(for: .PDFViewAnnotationHit)) { (notification) in
              if let annotation = notification.userInfo?["PDFAnnotationHit"] as? PDFAnnotation {
                self.selectedAnnotation = annotation
              }
          }
        }
      }