首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在iOS 11 PDFKit文档上实现墨迹注释

在iOS 11 PDFKit文档上实现墨迹注释
EN

Stack Overflow用户
提问于 2017-11-06 11:19:16
回答 3查看 6.2K关注 0票数 7

我希望允许用户使用在iOS 11 PDFKit文档中查看的PDFView。绘图应该最终嵌入到PDF中。

后一种方法是将“PDFAnnotation”类型的“墨水”添加到PDFPage中,并使用与用户绘图相对应的UIBezierPath进行解决。

但是,我如何实际记录用户在PDFView之上创建这样一个UIBezierPath的操作呢?

我尝试过在PDFView和PDFPage上重写PDFView,但它从未被调用。我尝试过添加一个UIGestureRecognizer,但什么也没有完成。

我假设以后需要使用PDFView实例方法PDFPage(_ point: CGPoint,to page: PDFPage)将获得的坐标转换为适合注释的PDF坐标。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2018-01-24 21:56:43

最后,我通过创建一个扩展PDFViewController和UIGestureRecognizerDelegate的UIViewController类来解决这个问题。我添加了一个PDFView作为子视图,向navigationItem添加了一个UIBarButtonItem,用于切换注释模式。

我在一个名为UIBezierPath的signingPath中记录这些触摸,并使用以下代码在currentAnnotation中使用PDFAnnotation类型的当前注释:

代码语言:javascript
复制
 override func touchesBegan(_ touches: Set<UITouch>, 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<UITouch>, 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<UITouch>, 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)
    }
}

注释切换按钮刚刚运行:

代码语言:javascript
复制
pdfView.isUserInteractionEnabled = !pdfView.isUserInteractionEnabled

这确实是它的关键,因为这禁用了PDF上的滚动,并使我能够接收触摸事件。

触摸事件的记录和转换为PDFAnnotation的方式立即意味着注释在写入PDF时是可见的,并且它最终被记录到PDF中的正确位置--不管滚动位置如何。

确保它在正确的页面上结束只是一个类似的问题,就是将硬编码的0页号更改为pdfView.page( for : position,就近:true)值。

票数 12
EN

Stack Overflow用户

发布于 2018-01-24 21:21:49

为此,我创建了一个新的视图类(如注释视图),并在用户进行注释时将其放在PDFView的顶部。

该视图使用它的默认touchesBegan/touchesMoved/touchesEnded方法来创建一个跟随该手势的bezier路径。一旦触摸结束,我的视图就会将其保存为pdf上的注释。

注意:用户需要一种方式来决定他们是否处于注释状态。

用于我的主类

代码语言:javascript
复制
class MyViewController : UIViewController, PDFViewDelegate, VCDelegate {

var pdfView: PDFView?
var touchView: AnnotateView?

override func loadView() {
   touchView = AnnotateView(frame: CGRect(x: 0, y: 0, width: 375, height: 600))
   touchView?.backgroundColor = .clear
   touchView?.delegate = self
   view.addSubview(touchView!)
}

 func addAnnotation(_ annotation: PDFAnnotation) {
    print("Anotation added")
    pdfView?.document?.page(at: 0)?.addAnnotation(annotation)
}
}

我的注释视图

代码语言:javascript
复制
class AnnotateView: UIView {
var path: UIBezierPath?
var delegate: VCDelegate?

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    // Initialize a new path for the user gesture
    path = UIBezierPath()
    path?.lineWidth = 4.0

    var touch: UITouch = touches.first!
    path?.move(to: touch.location(in: self))
}

override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {

    // Add new points to the path
    let touch: UITouch = touches.first! 
    path?.addLine(to: touch.location(in: self))
    self.setNeedsDisplay()
}

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {

    let touch = touches.first 
    path?.addLine(to: touch!.location(in: self))
    self.setNeedsDisplay()
    let annotation = PDFAnnotation(bounds: self.bounds, forType: .ink, withProperties: nil)
    annotation.add(self.path!)
    delegate?.addAnnotation(annotation)
}

override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
    self.touchesEnded(touches, with: event)
}

override func draw(_ rect: CGRect) {
    // Draw the path
    path?.stroke()
}

override init(frame: CGRect) {
    super.init(frame: frame)
    self.isMultipleTouchEnabled = false
}
}
票数 5
EN

Stack Overflow用户

发布于 2018-09-06 22:17:58

编辑:

jksoegaard的回答虽然鼓舞了我在这方面的所有工作,但也存在一个缺陷:在touchedMoved期间,创建了多个PDF注释,从而使PDF页面陷入批注的泥潭,这严重影响了它的加载时间。我编写了在CAShapeLayer阶段使用touchedMoved的代码,并且只在touchesEnded阶段创建完整的touchesEnded注释。

我的实现是UIGestureRecognizer的一个子类,它允许您在笔、荧光笔和橡皮擦之间进行选择,并选择颜色和宽度。它还包括一个撤消管理器。示例项目是这里

原始答案

除了jksoegaard的出色回答外,我还为我这样的新手做了一些澄清:

  1. 您需要在您的项目中包括UIBezierPath+.swift,以便识别.moveCenter和rect.center。从https://github.com/xhamr/paintcode-path-scale下载。
  2. 这些行可以排除在外: UIGraphicsBeginImageContext(CGSize(宽度: 800,高度: 600))

代码语言:javascript
复制
    let page = pdfView.page(for: position, nearest: true)!
  1. 您需要在函数之外声明几个全局vars: var signingPath = UIBezierPath() var annotationAdded : Bool?lastPoint : CGPoint?currentAnnotation : PDFAnnotation?
  2. 最后,如果您希望墨水更宽、颜色更好,您需要做两件事:

每次在您看到annotation.add或currentAnnotation.add之前,您都需要(根据该函数的需要使用注释或currentAnnotation ):

代码语言:javascript
复制
    let b = PDFBorder()
    b.lineWidth = { choose a pixel number here }
    currentAnnotation?.border = b
    currentAnnotation?.color=UIColor.{ your color of choosing }

我建议为颜色指定一个低alpha值。结果是美丽的,并影响你的速度的中风。例如,红色是:

代码语言:javascript
复制
    UIColor(red: 255/255.0, green: 0/255.0, blue: 0/255.0, alpha: 0.1)

记录每一次触摸的rect都需要适应较厚的线条。而不是

代码语言:javascript
复制
    let rect = signingPath.bounds

试试看,10 of厚的例子如下:

代码语言:javascript
复制
    let rect = CGRect(x:signingPath.bounds.minX-5, 
    y:signingPath.bounds.minY-5, width:signingPath.bounds.maxX- 
    signingPath.bounds.minX+10, height:signingPath.bounds.maxY- 
    signingPath.bounds.minY+10)

重要的:touchesEnded函数还使用currentAnnotation变量。您还必须在该函数中重复rect的定义(或者是简短的定义,也可以是我上面建议的),并在这里重复currentAnnotation的定义:

代码语言:javascript
复制
    currentAnnotation = PDFAnnotation(bounds: rect, forType: .ink, withProperties: nil)

如果你不这样做,一个没有移动的点击就会使你的应用程序崩溃。

我可以验证,一旦保存了文件,注释就会被保留。用于保存的示例代码:

代码语言:javascript
复制
    let pdfData = pdfDocument?.dataRepresentation()
    let annotatedPdfUrl = URL(fileURLWithPath: "\ 
    (NSSearchPathForDirectoriesInDomains(.documentsDirectory, .userDomainMask, 
        true)[0])/AnnotatedPDF.pdf")
    try! pdfData!.write(to: annotatedPdfUrl)
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47135766

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档