iOS render HTML to UIImage-ThrowExceptions

Exception or error:

I pieced together this class and figured I would share because I couldn’t find a solution. A lot of code suggests using WKWebKit.snapshotView() but that only renders the visible area.

This code converts to PDF before rendering to UIImage, which I’m sure could be taken out.

Make sure you keep a stronger reference to the class or the delegate method won’t be called.

import UIKit
import WebKit

class HTMLtoImage : NSObject, WKNavigationDelegate {
    var webView = WKWebView()
    var callback : ((UIImage)->())?
    var width = 841

    func render(html:String, width:Int, callback:((UIImage)->())?) {
        self.callback = callback
        self.width = width
        webView.navigationDelegate = self
        webView.loadHTMLString(html, baseURL: nil)
    }

    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        let fmt = webView.viewPrintFormatter()

        fmt.perPageContentInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0) //Page margins

        // - 2 - Assign print formatter to UIPrintPageRenderer
        let render = UIPrintPageRenderer()
        render.addPrintFormatter(fmt, startingAtPageAt: 0)

        var page = CGRect(x: 0, y: 0, width: self.width, height: 200)
        render.setValue(NSValue(cgRect: page), forKey: "paperRect")
        render.setValue(NSValue(cgRect: page), forKey: "printableRect")
        let start = ((render.numberOfPages-1)*200 > 200) ? ((render.numberOfPages-1) * 200) : 200

        for i in stride(from: start, to: start + 1000, by: 10) {
            page = CGRect(x: 0, y: 0, width: self.width, height: i)
            render.setValue(NSValue(cgRect: page), forKey: "paperRect")
            render.setValue(NSValue(cgRect: page), forKey: "printableRect")
            if render.numberOfPages == 1 {
                break
            }
        }

        let pdfData = NSMutableData()
        UIGraphicsBeginPDFContextToData(pdfData, page, nil)
        render.prepare(forDrawingPages: NSMakeRange(0, render.numberOfPages-1))
        for i in 0..<render.numberOfPages {
            UIGraphicsBeginPDFPage()
            render.drawPage(at: i, in: UIGraphicsGetPDFContextBounds())
        }
        UIGraphicsEndPDFContext()

        let provider:CGDataProvider = CGDataProvider(data: pdfData)!
        let pdfDoc:CGPDFDocument = CGPDFDocument(provider)!
        let pdfPage:CGPDFPage = pdfDoc.page(at: 1)!
        var pageRect:CGRect = pdfPage.getBoxRect(.mediaBox)
        pageRect.size = CGSize(width:pageRect.size.width, height:pageRect.size.height)

        UIGraphicsBeginImageContext(pageRect.size)
        let context:CGContext = UIGraphicsGetCurrentContext()!
        context.saveGState()
        context.translateBy(x: 0.0, y: pageRect.size.height)
        context.scaleBy(x: 1.0, y: -1.0)
        context.concatenate(pdfPage.getDrawingTransform(.mediaBox, rect: pageRect, rotate: 0, preserveAspectRatio: true))
        context.drawPDFPage(pdfPage)
        context.restoreGState()
        let pdfImage:UIImage = UIGraphicsGetImageFromCurrentImageContext()!
        UIGraphicsEndImageContext()

        self.callback?(pdfImage)
    }
}
How to solve:

Leave a Reply

Your email address will not be published. Required fields are marked *