Implement ink annotations on iOS 11 PDFKit document

前端 未结 3 762
广开言路
广开言路 2021-01-31 12:47

I want to allow the user to draw on an iOS 11 PDFKit document viewed in a PDFView. The drawing should ultimately be embedded inside the PDF.

The latter I have solved by

3条回答
  •  情深已故
    2021-01-31 13:18

    In the end I solved the problem by creating a PDFViewController class extending UIViewController and UIGestureRecognizerDelegate. I added a PDFView as a subview, and a UIBarButtonItem to the navigationItem, that serves to toggle annotation mode.

    I record the touches in a UIBezierPath called signingPath, and have the current annotation in currentAnnotation of type PDFAnnotation using the following code:

     override func touchesBegan(_ touches: Set, with event: UIEvent?) {
        if let touch = touches.first {
            let position = touch.location(in: pdfView)
            signingPath = UIBezierPath()
            signingPath.move(to: pdfView.convert(position, to: pdfView.page(for: position, nearest: true)!))
            annotationAdded = false
            UIGraphicsBeginImageContext(CGSize(width: 800, height: 600))
            lastPoint = pdfView.convert(position, to: pdfView.page(for: position, nearest: true)!)
        }
    }
    
    override func touchesMoved(_ touches: Set, with event: UIEvent?) {
        if let touch = touches.first {
            let position = touch.location(in: pdfView)
            let convertedPoint = pdfView.convert(position, to: pdfView.page(for: position, nearest: true)!)
            let page = pdfView.page(for: position, nearest: true)!
            signingPath.addLine(to: convertedPoint)
            let rect = signingPath.bounds
    
            if( annotationAdded ) {
                pdfView.document?.page(at: 0)?.removeAnnotation(currentAnnotation)
                currentAnnotation = PDFAnnotation(bounds: rect, forType: .ink, withProperties: nil)
    
                var signingPathCentered = UIBezierPath()
                signingPathCentered.cgPath = signingPath.cgPath
                signingPathCentered.moveCenter(to: rect.center)
                currentAnnotation.add(signingPathCentered)
                pdfView.document?.page(at: 0)?.addAnnotation(currentAnnotation)
    
            } else {
                lastPoint = pdfView.convert(position, to: pdfView.page(for: position, nearest: true)!)
                annotationAdded = true
                currentAnnotation = PDFAnnotation(bounds: rect, forType: .ink, withProperties: nil)
                currentAnnotation.add(signingPath)
                pdfView.document?.page(at: 0)?.addAnnotation(currentAnnotation)
            }
        }
    }
    
    override func touchesEnded(_ touches: Set, with event: UIEvent?) {
        if let touch = touches.first {
            let position = touch.location(in: pdfView)
            signingPath.addLine(to: pdfView.convert(position, to: pdfView.page(for: position, nearest: true)!))
    
            pdfView.document?.page(at: 0)?.removeAnnotation(currentAnnotation)
    
            let rect = signingPath.bounds
            let annotation = PDFAnnotation(bounds: rect, forType: .ink, withProperties: nil)
            annotation.color = UIColor(hex: 0x284283)
            signingPath.moveCenter(to: rect.center)
            annotation.add(signingPath)
            pdfView.document?.page(at: 0)?.addAnnotation(annotation)
        }
    }
    

    The annotation toggle button just runs:

    pdfView.isUserInteractionEnabled = !pdfView.isUserInteractionEnabled
    

    This was really the key to it, as this disables scrolling on the PDF and enables me to receive the touch events.

    The way the touch events are recorded and converted into PDFAnnotation immediately means that the annotation is visible while writing on the PDF, and that it is finally recorded into the correct position in the PDF - no matter the scroll position.

    Making sure it ends up on the right page is just a matter of similarly changing the hardcoded 0 for page number to the pdfView.page(for: position, nearest:true) value.

提交回复
热议问题