Skip to content

Instantly share code, notes, and snippets.

@RockfordWei
Forked from nyg/iOSCreatePDF.swift
Last active August 25, 2021 19:23
Show Gist options
  • Save RockfordWei/310829e2b59fb9e3d6ecad5401bbc002 to your computer and use it in GitHub Desktop.
Save RockfordWei/310829e2b59fb9e3d6ecad5401bbc002 to your computer and use it in GitHub Desktop.
iOS, Swift: Create a PDF file from an HTML string with local image file support
//
// ViewController.swift
// hrender
//
// Created by Rockford Wei on 2021-08-25.
//
import UIKit
import WebKit
class ViewController: UIViewController {
@IBOutlet weak var browser: WKWebView!
let home = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first ?? "/"
override func viewDidLoad() {
super.viewDidLoad()
let path = "\(home)/treefrog.png"
if let logo = UIImage(named: "logo")?.pngData(),
let root = URL(string: "file://\(home)/") {
let written = logo.writeToFile(path: path)
NSLog("file saved: \(written)")
let htm = """
<html>
<title>test</title>
<style>
p {
font-size: 16px;
}
</style>
<body>
<img src='treefrog.png' width='100%'/>
<hr>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse dignissim odio vitae mattis vestibulum. Curabitur eget sapien laoreet, fermentum nisl id, feugiat felis. Ut varius mollis arcu eget fermentum. Donec pellentesque metus tellus, eu luctus mi posuere in. Ut a posuere turpis, vel sagittis dolor. Donec venenatis, enim non tincidunt tempus, libero lectus varius lacus, ac consectetur lectus felis eu ipsum. Nam id nisl ac sem sagittis aliquet nec sollicitudin urna. Fusce fringilla est ac turpis venenatis suscipit. Quisque pellentesque arcu est, quis vehicula diam tempus quis. Sed aliquet semper nisi, ut porttitor orci fermentum et. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
</p>
<p>
Suspendisse iaculis aliquet dapibus. Curabitur bibendum justo sed tellus rutrum, sit amet vehicula sem scelerisque. Aenean hendrerit, turpis ut faucibus ultrices, mauris justo viverra libero, id venenatis velit libero non elit. Interdum et malesuada fames ac ante ipsum primis in faucibus. Aenean fermentum nisl at ante vestibulum venenatis. Fusce venenatis, tortor non varius lobortis, sem lorem porta tortor, vitae consectetur odio metus nec urna. Nam ut leo nec libero tincidunt sollicitudin. Phasellus aliquam mauris quis orci facilisis hendrerit. Donec mollis sit amet ligula vitae volutpat. Aenean quis libero non mauris viverra egestas. Donec laoreet metus enim, sed gravida diam fringilla vitae.
</p>
</body>
</html>
"""
browser.navigationDelegate = self
browser.loadHTMLString(htm, baseURL: root)
} else {
NSLog("logo not found")
}
}
}
extension ViewController: WKNavigationDelegate {
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
let path = browser.exportAsPdf()
NSLog("pdf exported: \(path)")
}
}
extension Data {
func writeToFile(path: String) -> Int {
guard count > 0 else { return 0 }
guard let file = fopen(path, "wb") else { return -2 }
defer {
fclose(file)
}
return withUnsafeBytes { buffered in
guard let pointer = buffered.baseAddress else { return -1 }
return fwrite(pointer, 1, count, file)
}
}
}
extension WKWebView {
// Call this function when WKWebView finish loading
func exportAsPdf() -> String {
let pdfData = createPdfFile(printFormatter: self.viewPrintFormatter())
return self.saveWebViewPdf(data: pdfData)
}
func createPdfFile(printFormatter: UIViewPrintFormatter) -> NSMutableData {
let originalBounds = self.bounds
self.bounds = CGRect(x: originalBounds.origin.x, y: bounds.origin.y, width: self.bounds.size.width, height: self.scrollView.contentSize.height)
let pdfPageFrame = CGRect(x: 0, y: 0, width: self.bounds.size.width, height: self.scrollView.contentSize.height)
let printPageRenderer = UIPrintPageRenderer()
printPageRenderer.addPrintFormatter(printFormatter, startingAtPageAt: 0)
printPageRenderer.setValue(NSValue(cgRect: UIScreen.main.bounds), forKey: "paperRect")
printPageRenderer.setValue(NSValue(cgRect: pdfPageFrame), forKey: "printableRect")
self.bounds = originalBounds
return printPageRenderer.generatePdfData()
}
// Save pdf file in document directory
func saveWebViewPdf(data: NSMutableData) -> String {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let docDirectoryPath = paths[0]
let pdfPath = docDirectoryPath.appendingPathComponent("webViewPdf.pdf")
if data.write(to: pdfPath, atomically: true) {
return pdfPath.path
} else {
return ""
}
}
}
extension UIPrintPageRenderer {
func generatePdfData() -> NSMutableData {
let pdfData = NSMutableData()
UIGraphicsBeginPDFContextToData(pdfData, self.paperRect, nil)
self.prepare(forDrawingPages: NSMakeRange(0, self.numberOfPages))
let printRect = UIGraphicsGetPDFContextBounds()
for pdfPage in 0 ..< self.numberOfPages {
UIGraphicsBeginPDFPage()
self.drawPage(at: pdfPage, in: printRect)
}
UIGraphicsEndPDFContext();
return pdfData
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment