将网页视图内容保存为PDF文件

9

注意:我正在使用适用于OSX的Swift 4。

我想从WebView生成PDF文件。

目前,我的WebView加载一个HTML字符串并成功显示出来。如果我按下按钮,打印面板将打开,并准备以正确的格式打印我的WebView内容。

这是我的打印代码:

var webView = WebView()
var htmlString = "MY HTML STRING"

override func viewDidLoad() {
    webView.mainFrame.loadHTMLString(htmlString, baseURL: nil)
}

func webView(_ sender: WebView!, didFinishLoadFor frame: WebFrame!) {

    let printInfo = NSPrintInfo.shared
    printInfo.paperSize = NSMakeSize(595.22, 841.85)
    printInfo.isHorizontallyCentered = true
    printInfo.isVerticallyCentered = true
    printInfo.orientation = .portrait
    printInfo.topMargin = 50
    printInfo.rightMargin = 0
    printInfo.bottomMargin = 50
    printInfo.leftMargin = 0
    printInfo.verticalPagination = .autoPagination
    printInfo.horizontalPagination = .fitPagination
    //webView.mainFrame.frameView.printOperation(with: printInfo).run()

    let printOp: NSPrintOperation = NSPrintOperation(view: webView.mainFrame.frameView.documentView, printInfo: printInfo)
    printOp.showsPrintPanel = true
    printOp.showsProgressPanel = false
    printOp.run() 
}

enter image description here

现在我想要另一个按钮,可以直接将内容保存为pdf文件。

我尝试了这个:

let pdfData = webView.mainFrame.frameView.documentView.dataWithPDF(inside: webView.mainFrame.frameView.documentView.frame)
let document = PDFDocument(data: pdfData)
let fileURL = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false).appendingPathComponent("myPDF.pdf")
document?.write(to: fileURL)

但是我的PDF结果看起来很糟糕: enter image description here 有人有什么想法吗?
更新: 这是我的Web视图结果的一部分: enter image description here 这是我的打印预览/PDF文件的结果,颜色丢失了,但现在到处都是。 "标志"(图片)将显示彩色: enter image description here
1个回答

6
问题是dataWithPDF使用视图的当前框架来决定生成的PDF应该有多宽。由于你应用中的WebView框架可能比8.5/11英寸页面更窄,因此生成的PDF宽度不足。你可以调整WebView的框架大小,生成PDF,然后再将其调整回来,或者创建一个新的WebView,将其呈现到屏幕外,设置为适当的尺寸,并创建PDF。但这有点烦人。如果有一种编程方式可以自动处理打印对话框中的“PDF”按钮所做的事情,那不是很好吗?因为打印系统会自动处理所有这些东西。

事实证明,你确实可以这样做!但是你必须深入到文档不太好的核心打印世界中。

func makePDF(at url: URL, for webView: WebView, printInfo: NSPrintInfo) throws {
    webView.preferences.shouldPrintBackgrounds = true

    guard let printOp = webView.mainFrame.frameView.printOperation(with: printInfo) else {
        throw MyPrintError.couldntGetPrintOperation // or something like this
    }

    let session = PMPrintSession(printOp.printInfo.pmPrintSession())
    let settings = PMPrintSettings(printOp.printInfo.pmPrintSettings())

    if PMSessionSetDestination(session,
                               settings,
                               PMDestinationType(kPMDestinationFile),
                               kPMDocumentFormatPDF as CFString,
                               url as CFURL) != noErr {
        throw MyPrintError.couldntSetDestination // or something like this
    }

    printOp.showsPrintPanel = false
    printOp.run()
}

关键是使用 PMSessionSetDestination 调用,它允许我们配置打印会话以将内容打印到 PDF 而不是实际打印机。然后我们只需告诉 NSPrintOperation 不要显示打印面板,运行操作,就可以轻松地打印 PDF 了。

这太棒了,而且运行良好!!我现在会给你100个声望。但是还有一件小事还没有完美解决。我该如何设置PDF的Din A4页面大小?结果看起来不像原始的Din A4大小。你能帮我解决这个问题吗? - Trombone0904
调整NSPrintInfo中的设置应该能够让您获得所需的纸张大小。我使用了您在问题中提供的NSPrintInfo进行尝试,它看起来像是A4大小。 - Charles Srstka
是的,你说得对,是我的错。但是“质量”方面有些问题。请看一下我的第一篇帖子,我添加了两张图片。 - Trombone0904
网页是否有单独的打印样式表?这可能会解释为什么打印出来的效果不同。 - Charles Srstka
我稍微研究了一下,发现默认情况下WebView不会打印背景颜色或图像,这是有道理的,因为在大多数情况下,打印背景会浪费很多墨粉,并且可能会使文本难以阅读。但是,可以在WebView.preferences中关闭此功能。我已经更新了答案。我还发现WebFrameView有自己的方法来创建打印操作,我认为这比从头开始制作更好,所以我也改变了答案的这部分。 - Charles Srstka
显示剩余2条评论

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