iOS 11 PDFKit Ink аннотация-не удается заполнить UIBezierPath


Я добавляю аннотации ink в PDFDocument, используя класс PDFAnnotation () с подтипом ink. Идея состоит в том, чтобы захватить подписи, которые рисуются с помощью прикосновения.

Вдохновленный UberSignature мой UIBezierPath-это ряд прямоугольников, которые должны быть заполнены цветом. Однако, когда я добавляю аннотацию в PDFDocument, она не заполняется.

Похоже, что метод fill () UIBezierPath вообще ничего не делает при добавлении в PDFAnnotation?

Если я использую то же самое 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

На скриншоте я попытался написать обычный текст и две строки примера. Линия слева рисуется медленно, линия справа-быстро. Идея состоит в том, чтобы ширина линии изменялась в зависимости от скорости, с которой она рисуется, чтобы сделать подпись более естественной/реалистичной.

2 3

2 ответа:

Инканнотация визуализируется как набор гладких путей. Нет никакого способа заполнить его цветом в соответствии с PDF reference 1.4 page 508.

Предварительный просмотр Apple использует аннотацию штампа для включения подписи в 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 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 

Метод fill() используется для заполнения пути в текущем графическом контексте, это не связано с аннотациями.

Если использование аннотации штампа не удается, вы также можете отобразить путь в графическом контексте, преобразовать его в изображение и поместить в PDF. Но я не уверен, что вы вообще принимаете это во внимание.

Вы можете найти больше ссылок на PDF в архивахAdobe .

Мне удалось найти решение проблемы, которое кажется относительно оптимальным.

Фокус в том, чтобы создать подкласс PDFAnnotation и переопределить функцию draw (with box:, in context:). В этой функции я могу использовать drawPath (используя: .fill) метод заполнения пути Безье.

Код может выглядеть следующим образом:

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

Добавьте эту аннотацию (тип .штамп) в PDF вместо чернильной аннотации, и все будет отображаться как вектор (полностью масштабируемый, не будучи pixelated) - и будет сохранен вместе с остальной частью PDF при сохранении в файл или буфер данных.

Единственным недостатком является то, что UIBezierPath не может быть слишком сложным, так как мерцание будет введено, если функция draw() занимает слишком много времени. Это можно решить, просто разбив UIBezierPath на несколько отдельных путей, каждый из которых имеет свою собственную аннотацию.