Ответ 1
UIMarkupTextPrintFormatter
, похоже, не поддерживает тег html img
. Документация Apple здесь не очень информативна, она просто утверждает, что параметром инициализации является "Текст разметки HTML для форматирования печати". Нет никаких указаний на то, какие теги поддерживаются форматом печати.
После многих тестов единственный вывод, который я могу сделать, заключается в том, что UIMarkupTextPrintFormatter
поддерживает НЕ отображение изображений.
Итак, где же это оставляет людей, которые хотят, чтобы удобство создания PDF из содержимого HTML?
Таким образом, единственный способ, которым я нашел эту работу, - использовать скрытый веб-вид, в который вы загружаете свой html-контент, а затем использовать веб-представление UIViewPrintFormatter
. Это работает, но на самом деле выглядит как хак.
Он работает, и он будет вставлять изображения в ваш PDF-документ, однако, если бы это был я, я бы наклонился к использованию CoreText и Quartz 2D, поскольку у вас будет намного больше контроля над процессом создания pdf файла, сказав, что я понимаю, что это может быть излишним, я не знаю размер или сложность содержимого html.
Итак, к рабочему примеру...
Настройка
Было полезно определить базовый url, чтобы я мог просто передать имена файлов, которые я хотел использовать. Базовый url сопоставляется с каталогом в комплекте приложений, где находятся изображения. Вы также можете определить свое собственное местоположение.
Bundle.main.resourceURL + "www/"
Затем я создал протокол для обработки связанных с документами функций. Реализации по умолчанию предоставляют расширение, как вы можете видеть в приведенном ниже коде.
protocol DocumentOperations {
// Takes your image tags and the base url and generates a html string
func generateHTMLString(imageTags: [String], baseURL: String) -> String
// Uses UIViewPrintFormatter to generate pdf and returns pdf location
func createPDF(html: String, formmatter: UIViewPrintFormatter, filename: String) -> String
// Wraps your image filename in a HTML img tag
func imageTags(filenames: [String]) -> [String]
}
extension DocumentOperations {
func imageTags(filenames: [String]) -> [String] {
let tags = filenames.map { "<img src=\"\($0)\">" }
return tags
}
func generateHTMLString(imageTags: [String], baseURL: String) -> String {
// Example: just using the first element in the array
var string = "<!DOCTYPE html><head><base href=\"\(baseURL)\"></head>\n<html>\n<body>\n"
string = string + "\t<h2>PDF Document With Image</h2>\n"
string = string + "\t\(imageTags[0])\n"
string = string + "</body>\n</html>\n"
return string
}
func createPDF(html: String, formmatter: UIViewPrintFormatter, filename: String) -> String {
// From: https://gist.github.com/nyg/b8cd742250826cb1471f
print("createPDF: \(html)")
// 2. Assign print formatter to UIPrintPageRenderer
let render = UIPrintPageRenderer()
render.addPrintFormatter(formmatter, startingAtPageAt: 0)
// 3. Assign paperRect and printableRect
let page = CGRect(x: 0, y: 0, width: 595.2, height: 841.8) // A4, 72 dpi
let printable = page.insetBy(dx: 0, dy: 0)
render.setValue(NSValue(cgRect: page), forKey: "paperRect")
render.setValue(NSValue(cgRect: printable), forKey: "printableRect")
// 4. Create PDF context and draw
let pdfData = NSMutableData()
UIGraphicsBeginPDFContextToData(pdfData, CGRect.zero, nil)
for i in 1...render.numberOfPages {
UIGraphicsBeginPDFPage();
let bounds = UIGraphicsGetPDFContextBounds()
render.drawPage(at: i - 1, in: bounds)
}
UIGraphicsEndPDFContext();
// 5. Save PDF file
let path = "\(NSTemporaryDirectory())\(filename).pdf"
pdfData.write(toFile: path, atomically: true)
print("open \(path)")
return path
}
}
Тогда у меня был этот протокол, принятый контроллером вида. Ключ к выполнению этой работы здесь, ваш контроллер представления должен принять UIWebViewDelegate
и в
func webViewDidFinishLoad(_ webView: UIWebView)
вы можете видеть, что PDF файл создан.
class ViewController: UIViewController, DocumentOperations {
@IBOutlet private var webView: UIWebView!
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
webView.delegate = self
webView.alpha = 0
if let html = prepareHTML() {
print("html document:\(html)")
webView.loadHTMLString(html, baseURL: nil)
}
}
fileprivate func prepareHTML() -> String? {
// Create Your Image tags here
let tags = imageTags(filenames: ["PJH_144.png"])
var html: String?
// html
if let url = Bundle.main.resourceURL {
// Images are stored in the app bundle under the 'www' directory
html = generateHTMLString(imageTags: tags, baseURL: url.absoluteString + "www/")
}
return html
}
}
extension ViewController: UIWebViewDelegate {
func webViewDidFinishLoad(_ webView: UIWebView) {
if let content = prepareHTML() {
let path = createPDF(html: content, formmatter: webView.viewPrintFormatter(), filename: "MyPDFDocument")
print("PDF location: \(path)")
}
}
}