我正在尝试将
UIView
渲染为 PDF,同时将文本元素保留为实际文本而不是光栅化它们。
我使用 TextKit 2 支持的
UITextView
和 NSTextLayoutManager
来提供内容。然而,无论我做什么,UITextView
都会被光栅化为位图。
这是基本代码:
let renderer = UIGraphicsPDFRenderer(bounds: pageRect, format: format)
let data = renderer.pdfData { (context) in
for page in self.pageViews {
context.beginPage()
let cgContext = context.cgContext
page.layer.render(in: cgContext)
}
}
页面视图通常包含一个
UITextView
,它使用了一些高级布局,因此不幸的是我不能将其扔进单个 NSAttributedString
并绘制到 CoreText 上下文中。
有一个 hack 可以让 UILabel
将自己渲染为非光栅化文本,如果我理解正确的话,它的工作原理是在当前上下文中实际绘制它们。有趣的是,当使用 TextKit 2 通过
UILabel
向文本视图提供
NSTextAttachmentViewProvider
视图时,文本视图内的
UILabel
不会被光栅化:
这暗示实际的文本片段是在绘制时被光栅化的文本片段,而不是整个视图,我是对的。您可以枚举文本片段并将它们直接绘制在上下文上,这使得它们保留为文本而不是成为位图:
page.textView?.textLayoutManager?.enumerateTextLayoutFragments(from: location, options: [.ensuresLayout, .estimatesSize, .ensuresExtraLineFragment], using: { fragment in
let frame = fragment.layoutFragmentFrame
fragment.draw(at: frame.origin, in: cgContext)
return true
})
但是,这会导致其他问题,因为布局坐标将遍布各处,并且不限于文本视图本身(对于我的自定义
NSTextLayoutFragment
类更是如此),并且文本附件也不会以这种方式绘制,但显示倾斜的占位符图标。
我想知道是否有办法让UITextView
和
NSTextLayoutManager
绘制类似于 UILabel
的内容,这样片段将在 PDF 中保留为文本,而不是成为位图?UITextView
作为真实文本渲染到 PDF 中的简单方法。它目前仅支持每个段落一个文本片段,因为您显然无法使用
fragment.draw(at:origin:)
来显示文本片段。let renderer = UIGraphicsPDFRenderer(bounds: pageRect, format: format)
let data = renderer.pdfData { (context) in
let cgContext = context.cgContext
textView.textLayoutManager.enumerateTextLayoutFragments(from: location, options: [.ensuresLayout, .estimatesSize, .ensuresExtraLineFragment], using: { fragment in
let frame = fragment.layoutFragmentFrame
let origin = page.textView?.frame.origin ?? CGPointZero
var actualFrame = frame
actualFrame.origin.x += origin.x
actualFrame.origin.y += origin.y
if let provider = fragment.textAttachmentViewProviders.first, let view = provider.view {
// Draw a text attachment
let attachmentFrame = fragment.frameForTextAttachment(at: fragment.rangeInElement.location)
actualFrame.origin.y += attachmentFrame.origin.y
cgContext.saveGState()
cgContext.translateBy(x: actualFrame.origin.x, y: actualFrame.origin.y)
view.layer.render(in: cgContext)
cgContext.restoreGState()
return true
} else {
// Draw a normal paragraph
fragment.draw(at: origin, in: cgContext)
}
return true
})
}
我不知道为什么苹果决定不将此作为默认行为包含在
UITextView
中,因为这似乎完全有可能。