UIMarkupTextPrintFormatter never renders base64 images
Asked Answered
I

2

7

Im creating a pdf file out of html content in swift 3.0:

/**
 *
 */
func exportHtmlContentToPDF(HTMLContent: String, filePath: String) {
    // let webView = UIWebView(frame: CGRect(x: 0, y: 0, width: 694, height: 603));

    // webView.loadHTMLString(HTMLContent, baseURL: nil);

    let pdfPrinter = PDFPrinter();
    let printFormatter = UIMarkupTextPrintFormatter(markupText: HTMLContent);
    // let printFormatter = webView.viewPrintFormatter();

    pdfPrinter.addPrintFormatter(printFormatter, startingAtPageAt: 0);

    let pdfData = self.drawPDFUsingPrintPageRenderer(printPageRenderer: pdfPrinter);

    pdfData?.write(toFile: filePath, atomically: true);
}

/**
 *
 */
func drawPDFUsingPrintPageRenderer(printPageRenderer: UIPrintPageRenderer) -> NSData! {
    let data = NSMutableData();

    UIGraphicsBeginPDFContextToData(data, CGRect.zero, nil);

    printPageRenderer.prepare(forDrawingPages: NSMakeRange(0, printPageRenderer.numberOfPages));

    let bounds = UIGraphicsGetPDFContextBounds();

    for i in 0...(printPageRenderer.numberOfPages - 1) {
        UIGraphicsBeginPDFPage();

        printPageRenderer.drawPage(at: i, in: bounds);
    }

    UIGraphicsEndPDFContext();

    return data;
}

Everything is rendered fine except my base64 encoded images. The HTML content itself in a webview or inside safari or chrome browser is presented correctly and is showing all images correctly. But the images are never rendered into the pdf.

Why are the images not rendered and how can I get them to be rendered?

Ingmar answered 25/10, 2016 at 12:5 Comment(4)
I would recommend to do experiment. Crete HTML which hold two images. Fist is base64 encoded and second points to file image. Open this image with Safari browser on iPhone. Then export it to iBooks as PDF. And see are both image are rendered by the native Safari app.Hardnett
Are you doing it for iOS platform?Hardnett
I do it for iOS platform yes. I will test it with an image file but btw. when i open up a webview containing my html template the base64 images are showing up correctly.Ingmar
Dose it shows base64 image when exporting this html template to PDF using iBooks app?Hardnett
I
5

I found the solution!

The export to PDF happens before the rendering process is finished. If you put in a very small picture it is showing up in the PDF. If the picture is too big the rendering process takes too much time but the PDF export isnt waiting for the rendering to finish.

So what I did to make it work is the following:

Before I export to PDF I show the Result of the HTML in a WebView. The WebView is rendering everything correctly and now when I press on export to PDF the PDF is showing up correctly with all images inside.

So I guess this is a huge lag that there is no way to tell the PDF Exporter to wait for the rendering process to finish.

Ingmar answered 28/10, 2016 at 9:47 Comment(1)
Yes, DOM parsing and loading is asynchronous. There is fortunately a simple way to determine the exact timing when the document is export ready, which I've outlined in my answer: https://mcmap.net/q/410855/-uimarkuptextprintformatter-never-renders-base64-imagesRrhagia
R
6

This happens because WebKit first parses the HTML into a DOM, and renders content on multiple event loop cycles. You therefore need to wait for not just the page DOM to be ready but for the resource loading to be complete. As you also suggest, you need to refactor your code such that the webview gets loaded first, and you only then export its contents.

To determine the correct time to fire the export, you can observe for the state of the DOM document in the web view. There are multiple ways to do this, but the most readable option I find is a port of an answer to a related Objective-C question: in your UIWebViewDelegate implementation, implement webViewDidFinishLoad in the following way to monitor document.readyState:

    func webViewDidFinishLoad(_ webView: UIWebView) {

        guard let readyState = webView.stringByEvaluatingJavaScript(from: "document.readyState"),
            readyState == "complete" else
        {
            // document not yet parsed, or resources not yet loaded.
            return
        }

        // This is the last webViewDidFinishLoad call --> export.
        //
        // There is a problem with this method if you have JS code loading more content:
        // in that case -webViewDidFinishLoad can get called again still after document.readyState has already been in state 'complete' once or more.
        self.exportHtmlContentToPDF(…)
    }
Rrhagia answered 29/10, 2016 at 16:4 Comment(2)
For me this constantly flickers my screen endlesslyKaleb
Why you take about WebKit if the question is about UIMarkupTextPrintFormatter ?Scilla
I
5

I found the solution!

The export to PDF happens before the rendering process is finished. If you put in a very small picture it is showing up in the PDF. If the picture is too big the rendering process takes too much time but the PDF export isnt waiting for the rendering to finish.

So what I did to make it work is the following:

Before I export to PDF I show the Result of the HTML in a WebView. The WebView is rendering everything correctly and now when I press on export to PDF the PDF is showing up correctly with all images inside.

So I guess this is a huge lag that there is no way to tell the PDF Exporter to wait for the rendering process to finish.

Ingmar answered 28/10, 2016 at 9:47 Comment(1)
Yes, DOM parsing and loading is asynchronous. There is fortunately a simple way to determine the exact timing when the document is export ready, which I've outlined in my answer: https://mcmap.net/q/410855/-uimarkuptextprintformatter-never-renders-base64-imagesRrhagia

© 2022 - 2024 — McMap. All rights reserved.