iOS 11 PDFKit墨迹注释 - 无法填充UIBezierPath

3
我正在使用PDFAnnotation()类和子类型墨水将墨水注释添加到PDFDocument中。目的是捕获使用触摸绘制的签名。
受UberSignature启发,我的UIBezierPath是一系列应该填充颜色的矩形。然而,当我将注释添加到PDFDocument时,它没有被填充。
当UIBezierPath添加到PDFAnnotation中时,似乎UIBezierPath的fill()方法根本没有起作用?
如果我使用相同的UIBezierPath并在UIImage上绘制它,则会正确地填充为实色。
有什么想法可能出了什么问题吗?
有问题的代码:
UIColor.red.setStroke()
UIColor.red.setFill()

var path = UIBezierPath()
path.append(myRectangles)
path.fill()

var annotation = PDFAnnotation(bounds: path.bounds, forType: .ink, withProperties: nil)
annotation.add(path)
myPDFPage.addAnnotation(annotation)

PDF的当前视图

在截图中,我尝试编写正常文本和两个示例行。左侧行绘制缓慢,右侧行绘制快速。这个想法是使线条宽度根据其绘制速度变化,从而使签名看起来更加自然/逼真。


你找到了一种根据铅笔的压力、速度和位置调整线条宽度和样式的方法吗?我尝试实现与苹果在他们的示例应用程序中使用的相同方式(https://developer.apple.com/documentation/uikit/touches_presses_and_gestures/leveraging_touch_input_for_drawing_apps),但遇到了严重的性能问题。 - Tim
是的,我使用了在我的问题和答案中展示的技术,即将行“切成”不同大小的多个四边形。为了提高性能,我确保进行多个注释而不是将所有内容捆绑在一起,并且我还实现了位图缓存。也就是说,我存储了每 x 次迭代计算出的实际位图,因此当添加笔画时,我只需要在每次绘制时渲染最新的笔画。其余部分已被缓存。 - jksoegaard
2个回答

5
我找到了一个相对最优的解决方案。
窍门是创建PDF注释的子类并覆盖draw(with box:,in context :)函数。在这个函数中,我可以使用drawPath(using:.fill)方法来填充bezier path。
代码可能如下所示:
class SignatureAnnotation : PDFAnnotation {
  public var myPath : UIBezierPath = UIBezierPath()

  override func draw(with box: PDFDisplayBox, in context: CGContext) {
    context.saveGState()
    self.page?.transform(context, for: box)
    context.beginPath()
    context.setLineWidth(0.1)
    context.setShouldAntialias(true)
    context.addPath(self.myPath.cgPath.mutableCopy()!)
    context.drawPath(using: .fill)
    context.restoreGState()
  }
}

将此注释(类型为.stamp)添加到PDF中,而不是墨水注释,所有内容将呈现为矢量图(完全可缩放而不会出现像素化),并在保存到文件或数据缓冲区时与PDF的其余部分一起保存。
唯一的缺点是UIBezierPath不能太复杂,因为如果draw()函数执行时间太长,则会引入闪烁。这可以通过将UIBezierPath分成多个单独的路径来解决,每个路径都有自己的注释。

1
这个注释在其他PDF渲染应用程序中可见吗?它可以像注释一样被操作(移动,改变大小,复制,粘贴)吗? - Wojciech Nagrodzki
2
是的,在其他PDF渲染应用程序中可见(我已经在Apple Preview和内置的Google Chrome PDF查看器中进行了测试)。我对之后操纵注释不感兴趣,所以我没有尝试过。 - jksoegaard
@jksoegaard 谢谢您的分享。我尝试在我的项目中实现您的解决方案,但只能绘制 UIBezierPath 的第一个线段,其他线段没有被绘制。您可以分享一些更多的代码吗? - Tim
你尝试过在调试器中检查你的UIBezierPath,以确保实际上有多个线段吗?对我来说没有问题。 - jksoegaard
第二个问题是强制PDFAnnotation重新绘制。我尝试在touchesBegan中创建一个注释,并在触摸继续时编辑路径。然而,我找到的唯一解决方案是调用addAnnotation/removeAnnotation。 - Tim
显示剩余3条评论

1
InkAnnotation被渲染为一组描边路径,无法根据PDF reference 1.4 page 508填充颜色。
Apple的预览使用Stamp注释将签名包含在PDF中。我尝试使用PDFKit进行逆向工程,但我看不到任何包含我放置在PDF中的签名的矢量数据。PDFKit可能在这里不够用。
(lldb) po annotation.annotationKeyValues
▿ 10 elements
  ▿ 0 : 2 elements
    ▿ key : AnyHashable("/AAPL:Hash")
      - value : "/AAPL:Hash"
    - value : /264236ab9aaabfe2d536167a89c26c2d
  ▿ 1 : 2 elements
    ▿ key : AnyHashable("/DA")
      - value : "/DA"
    - value : /Helvetica 12 Tf 0 g
  ▿ 2 : 2 elements
    ▿ key : AnyHashable("/T")
      - value : "/T"
    - value : Wojciech Nagrodzki3 : 2 elements
    ▿ key : AnyHashable("/F")
      - value : "/F"
    - value : 44 : 2 elements
    ▿ key : AnyHashable("/Subtype")
      - value : "/Subtype"
    - value : /Stamp5 : 2 elements
    ▿ key : AnyHashable("/Name")
      - value : "/Name"
    - value : /Draft6 : 2 elements
    ▿ key : AnyHashable("/Rect")
      - value : "/Rect"
    - value : NSRect: {{5.8745389999999995, 748.38995}, {307.66119599999996, 87.648936000000049}}
  ▿ 7 : 2 elements
    ▿ key : AnyHashable("/Border")
      - value : "/Border"
    - value : PDFBorder: {solid lineWidth:2.8 hCorner:0.0 vCorner:0.0 dashCount:0 dashPattern:(
)}
  ▿ 8 : 2 elements
    ▿ key : AnyHashable("/Type")
      - value : "/Type"
    - value : /Annot9 : 2 elements
    ▿ key : AnyHashable("/C")
      - value : "/C"
    - value : kCGColorSpaceModelRGB 0 0 0 1 
< p > fill() 方法用于填充当前图形上下文中的路径,与注释无关。

如果使用图章注释失败,您还可以在图形上下文中渲染路径,将其转换为图像并放置在PDF中。但我不确定您是否考虑过这一点。

您可以在Adobe's archives中找到更多有关PDF的参考资料。


很遗憾,这些都没有真正解决问题。图像不是最佳选择,因为当放大时会出现像素化,与墨迹注释的矢量格式相反。此外,在PDF中添加图像也存在问题,因为PDFKit实际上没有任何机制来更改PDF的内容 - 只有注释。与此同时,我前几天已经解决了这个问题 - 现在添加一个具体的答案。 - jksoegaard

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接