在 macOS 上使用 Swift 在 PDF 上绘图
Posted
技术标签:
【中文标题】在 macOS 上使用 Swift 在 PDF 上绘图【英文标题】:Draw on a PDF using Swift on macOS 【发布时间】:2017-06-19 21:11:05 【问题描述】:我的目标是在 PDF 上编写文本,例如注释。
我实现了将 PDFPage 转换为 NSImage,我在 NSImage 上绘图,然后保存了由图像形成的 PDF。
let image = NSImage(size: pageImage.size)
image.lockFocus()
let rect: NSRect = NSRect(x: 50, y: 50, width: 60, height: 20)
"Write it on the page!".draw(in: rect, withAttributes: someAttributes)
image.unlockFocus()
let out = PDFPage(image: image)
问题显然是out
(输出 PDF 的新页面)是图像的 PDFPage,而不是常规图像。所以输出的 PDF 非常大,你不能在上面复制和粘贴任何东西。这只是一系列图像。
我的问题是,是否有一种方法可以在不使用 NSImage 的情况下以编程方式在 PDF 页面上添加简单文本。有什么想法吗?
注意:ios 编程中有这个课程UIGraphicsBeginPDFPageWithInfo
,对我来说可能非常有用。但是我找不到用于 macOS 开发的类似类。
【问题讨论】:
是的...您可以使用 html 来做到这一点。 @ClaudioCastro 没有别的办法吗?以下是如何在 iOS 上解决我的问题,但我在 macOS 中找不到等效的方法:***.com/questions/32113468/… 对不起,你说的是 macOS... 在新的 iOS 11 和 xCode 9 中,有一些关于 pdf api 的消息。 【参考方案1】:您可以在 macOS 上创建 PDF 图形上下文并在其中绘制 PDFPage
。然后,您可以使用 Core Graphics 或 AppKit 图形将更多对象绘制到上下文中。
这是我通过打印您的问题创建的测试 PDF:
这是将该页面绘制到 PDF 上下文中的结果,然后在其上绘制更多文本:
这是我编写的将第一个 PDF 转换为第二个 PDF 的代码:
import Cocoa
import Quartz
let inUrl: URL = URL(fileURLWithPath: "/Users/mayoff/Desktop/test.pdf")
let outUrl: CFURL = URL(fileURLWithPath: "/Users/mayoff/Desktop/testout.pdf") as CFURL
let doc: PDFDocument = PDFDocument(url: inUrl)!
let page: PDFPage = doc.page(at: 0)!
var mediaBox: CGRect = page.bounds(for: .mediaBox)
let gc = CGContext(outUrl, mediaBox: &mediaBox, nil)!
let nsgc = NSGraphicsContext(cgContext: gc, flipped: false)
NSGraphicsContext.current = nsgc
gc.beginPDFPage(nil); do
page.draw(with: .mediaBox, to: gc)
let style = NSMutableParagraphStyle()
style.alignment = .center
let richText = NSAttributedString(string: "Hello, world!", attributes: [
NSFontAttributeName: NSFont.systemFont(ofSize: 64),
NSForegroundColorAttributeName: NSColor.red,
NSParagraphStyleAttributeName: style
])
let richTextBounds = richText.size()
let point = CGPoint(x: mediaBox.midX - richTextBounds.width / 2, y: mediaBox.midY - richTextBounds.height / 2)
gc.saveGState(); do
gc.translateBy(x: point.x, y: point.y)
gc.rotate(by: .pi / 5)
richText.draw(at: .zero)
; gc.restoreGState()
; gc.endPDFPage()
NSGraphicsContext.current = nil
gc.closePDF()
【讨论】:
完美答案!我现在明白了。 嘿,罗伯!如果我需要使用新绘制的页面怎么办?使用您的代码,新页面将保存在 outUrl 路径中,但无法以编程方式访问它。我唯一能做的就是将 PDFPage 保存到 outUrl 然后再次打开它。我查看了 CGContext 的文档页面,但没有找到任何可以获取已修改的 PDFPage 的内容。知道如何在 gc.closePDF() 调用后立即获取它吗?这不重要,实际上只是为了好奇。 使用带有CGDataConsumer
参数的CGContext
初始化器。在closePDF
之后,您可以从数据中创建PDFDocument
的新实例,而无需通过文件。
这是一个很好的答案,虽然我在 Swift 4 中尝试使用 NSGraphicsContext.setCurrent()
时遇到错误。它说“类型 'NSGraphicsContext' 没有成员 'setCurrent'”。它仍在文档中,所以我不确定。
NSGraphicsContext
现在有一个属性,current
,而不是一个 setter 方法。我已经更新了我的答案。以上是关于在 macOS 上使用 Swift 在 PDF 上绘图的主要内容,如果未能解决你的问题,请参考以下文章
Cocoa swift macOS 打印 html 到 pdf
使用 swift 代码将 web 视图上的 pdf 共享到其他设备