简体   繁体   中英

iOS 11 PDFKit Ink annotation - cannot fill UIBezierPath

I'm adding ink annotations to PDFDocument using the PDFAnnotation() class with subtype ink. The idea is to capture signatures that are drawn using touch.

Inspired by UberSignature my UIBezierPath is a series of rectangles that are supposed to be filled with a color. However, when I add the annotation to the PDFDocument it is not filled.

It seems the UIBezierPath's fill() method does nothing at all when added to a PDFAnnotation?

If I use the same UIBezierPath and draw it on an UIImage it is correctly filled with a solid color.

Any ideas on what could be wrong?

Problematic code:

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的当前视图

In the screenshot I have tried to write normal text, and two example lines. The line on the left is drawn slowly, the line on the right is drawn fast. The idea is to have width of the line vary according to the speed it is drawn to make a signature look more natural/realistic.

I managed to find a solution to the problem that seems relatively optimal.

The trick is do create a subclass of PDFAnnotation and override the draw(with box:, in context:) function. In this function I can use the drawPath(using: .fill) method to fill out bezier path.

The code can look like this:

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()
  }
}

Add this annotation (type .stamp) to the PDF instead of the ink annotation, and everything will be rendered as vector (fully zoomable without being pixelated) - and will be saved together with the rest of the PDF when saved to file or data buffer.

Only drawback is that the UIBezierPath cannot be too complicated as flickering will be introduced if the draw() function takes too long. This can be solved by simply splitting up the UIBezierPath into multiple seperate paths that each has its own annotation.

InkAnnotation is rendered as a collection of stroked paths. There is no way to fill it with colour according to PDF reference 1.4 page 508 .

Apple's Preview uses Stamp annotation to include signature to PDFs. I tried to use PDFKit to reverse engineer it but I cannot see any vector data that would contain the signature I placed in the PDF. PDFKit may be not sufficient here.

(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 Nagrodzki
  ▿ 3 : 2 elements
    ▿ key : AnyHashable("/F")
      - value : "/F"
    - value : 4
  ▿ 4 : 2 elements
    ▿ key : AnyHashable("/Subtype")
      - value : "/Subtype"
    - value : /Stamp
  ▿ 5 : 2 elements
    ▿ key : AnyHashable("/Name")
      - value : "/Name"
    - value : /Draft
  ▿ 6 : 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 : /Annot
  ▿ 9 : 2 elements
    ▿ key : AnyHashable("/C")
      - value : "/C"
    - value : kCGColorSpaceModelRGB 0 0 0 1 

The fill() method you is used to fill path in current graphic context, this is not related to annotations.

If using stamp annotation fails you could also render the path in graphic context, convert it to image and place in the PDF. But I am not sure if you take this under consideration at all.

You can find more PDF references in the Adobe's archives .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM