Skip to content

Instantly share code, notes, and snippets.

@nyg
Last active April 2, 2024 11:09
Show Gist options
  • Save nyg/b8cd742250826cb1471f to your computer and use it in GitHub Desktop.
Save nyg/b8cd742250826cb1471f to your computer and use it in GitHub Desktop.
iOS, Swift: Create a PDF file from an HTML string.
// Thanks to http://www.labs.saachitech.com/2012/10/23/pdf-generation-using-uiprintpagerenderer
// Note: including images in the HTML won't work, see here:
// https://github.com/nyg/HTMLWithImagesToPDF
import UIKit
// 1. Create a print formatter
let html = "<b>Hello <i>World!</i></b>"
let fmt = UIMarkupTextPrintFormatter(markupText: html)
// 2. Assign print formatter to UIPrintPageRenderer
let render = UIPrintPageRenderer()
render.addPrintFormatter(fmt, startingAtPageAt: 0)
// 3. Assign paperRect and printableRect
let page = CGRect(x: 0, y: 0, width: 595.2, height: 841.8) // A4, 72 dpi
render.setValue(page, forKey: "paperRect")
render.setValue(page, forKey: "printableRect")
// 4. Create PDF context and draw
let pdfData = NSMutableData()
UIGraphicsBeginPDFContextToData(pdfData, .zero, nil)
for i in 0..<render.numberOfPages {
UIGraphicsBeginPDFPage();
render.drawPage(at: i, in: UIGraphicsGetPDFContextBounds())
}
UIGraphicsEndPDFContext();
// 5. Save PDF file
guard let outputURL = try? FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false).appendingPathComponent("output").appendingPathExtension("pdf")
else { fatalError("Destination URL not created") }
pdfData.write(to: outputURL, atomically: true)
print("open \(outputURL.path)") // command to open the generated file
@webphax
Copy link

webphax commented Oct 5, 2015

Great example! Did you tried to add base64 encoded images to the HTML? For me it doesn't work...

@nyg
Copy link
Author

nyg commented Nov 22, 2015

I've just tried it but it doesn't appear to work. However, if I load the HTML string with the Base64-encoded image into a UIWebView then it works correctly. Strange...

@jsalazar78
Copy link

How to you Print a tableView in to a PDF file.

@nyg
Copy link
Author

nyg commented Nov 30, 2015

I do not, I was just saying that printing an HTML string with a Base64-encoded image in a PDF doesn't work but loading the same string in a UIWebView works (the image is displayed).

@vineethvijayan
Copy link

can we have a local image loaded in html and print it with img tag?

@facundomedica
Copy link

I can't make images work!

@t2ac32
Copy link

t2ac32 commented May 18, 2016

can someone elaborate on how are you writing the src=" " when having problems with the images?

@MossoIsai
Copy link

I'm Losing a paragraph to reach the limit leaf, Any ideas??

@MossoIsai
Copy link

src='data:image/png;base64,(imageString) tambien para mi no funciona

@mark-oliveira
Copy link

mark-oliveira commented Sep 22, 2016

I can't get base 64 images working either. What's strange to me is that UIPrintInteractionController is able render the images using a UIMarkupTextPrintFormatter (which is also used in this gist). Try this code I sniped from SO for an example:

NSString* printContents = @"This is a work around <IMG SRC=\"data:image/gif;base64,R0lGODdhMAAwAPAAAAAAAP///ywAAAAAMAAwAAAC8IyPqcvt3wCcDkiLc7C0qwyGHhSWpjQu5yqmCYsapyuvUU lvONmOZtfzgFzByTB10QgxOR0TqBQejhRNzOfkVJ+5YiUqrXF5Y5lKh/DeuNcP5yLWGsEbtLiOSpa/TPg7JpJHxyendzWTBfX0cxOnKPjgBzi4diinWGdkF8kjdfnycQ ZXZeYGejmJlZeGl9i2icVqaNVailT6F5iJ90m6mvuTS4OK05M0vDk0Q4XUtwv KOzrcd3iq9uisF81M1OIcR7lEewwcLp7tuNNkM3uNna3F2JQFo97Vriy/Xl4/f1cf5VWzXyym7PHhhx4dbgYKAAA7\">";

    UIMarkupTextPrintFormatter *html = [[UIMarkupTextPrintFormatter alloc] initWithMarkupText:printContents];
    UIPrintInteractionController* printController = [UIPrintInteractionController sharedPrintController];
    [printController setPrintFormatter:html];
    [printController presentAnimated:YES completionHandler:^(UIPrintInteractionController *printInteractionController, BOOL completed, NSError *error) {
        //
    }];

http://stackoverflow.com/questions/7069140/how-do-i-use-uimarkuptextprintformatter-to-print-a-local-html-with-local-images

@Montrazul
Copy link

But what if the content does not fit on one side? What if you need more than one site to present your content? With the code above the content is just cut off and it is only printing the content fitting on one A4 site. With this code the other pages arent printed.

@NikunjGodhani
Copy link

NikunjGodhani commented Oct 26, 2016

"" Please provide solution. I want to set the image in the pdf file. I have image which is stored in the document directory path. Name of image is "title.png". This image i want to set in the pdf. Help me . . .

@Katuwal-Deepak
Copy link

 func convertImageAtPathToBase64String(fileName: String) -> String {
        let paths = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)
        let documentsURL = paths[0]
        let imageFileURL = documentsURL.URLByAppendingPathComponent(fileName)
        if let imageData = NSData(contentsOfURL: imageFileURL) {
            let strBase64:String = imageData.base64EncodedStringWithOptions(.Encoding64CharacterLineLength)
            print(strBase64)
            return "data:image/gif;base64,\(strBase64)"
        }
        return ""
    } 
func createPdfFile(printFormatter: UIViewPrintFormatter) -> NSData {
        let renderer = UIPrintPageRenderer()
        renderer.addPrintFormatter(printFormatter, startingAtPageAtIndex: 0);
        let paperSize = CGSizeMake(view.frame.size.width, view.frame.size.height)
        let printableRect = CGRectMake(0, 0, paperSize.width, paperSize.height)
        let paperRect = CGRectMake(0, 0, paperSize.width, paperSize.height);
        renderer.setValue(NSValue(CGRect: paperRect), forKey: "paperRect")
        renderer.setValue(NSValue(CGRect: printableRect), forKey: "printableRect")
        return renderer.printToPDF()
    }

Use the extension

extension UIPrintPageRenderer {
    func printToPDF() -> NSData {
        let pdfData = NSMutableData()
        UIGraphicsBeginPDFContextToData(pdfData, self.paperRect, nil)
        self.prepareForDrawingPages(NSMakeRange(0, self.numberOfPages()))
        let bounds = UIGraphicsGetPDFContextBounds()
        for i in 0..<self.numberOfPages() {
            UIGraphicsBeginPDFPage();
            self.drawPageAtIndex(i, inRect: bounds)
        }
        UIGraphicsEndPDFContext();
        return pdfData;
    }
}

Finally load the web view & call the createPdfFile function only when web view is fully loaded else image might not show up in converted pdf file. I used WKWebViewbut you can also try with UIWebView.

 htmlContent = htmlContent.stringByReplacingOccurrencesOfString("img src is suppose to be replace by base 64 string ", withString: convertImageAtPathToBase64String("imageName.jpg"))
webView.loadHTMLString(htmlContent, baseURL: NSURL(string: "HTML file path goes here"))

@rwichmann
Copy link

Does anyone know how to add a stylesheet to the markup?

I have a html string that refers to a css in html: <link rel="stylesheet" href="styles.css" type="text/css">
When I load the html string in a WKWebView the css is loaded since I can pass in a baseURL to the webView like this:
webView.loadHTMLString(htmlString, baseURL: URL(fileURLWithPath: Bundle.main.bundlePath))

But I don't know how to pass in a baseURL to the UIMarkupTextPrintFormatter. Does anybody know how?

@nyg
Copy link
Author

nyg commented Aug 12, 2017

My attempts at making images work (with UIMarkupTextPrintFormatter) tells me there's obviously a bug with iOS 10. More here: https://github.com/nyg/HTMLWithImagesToPDF

@ReDetection
Copy link

@nyg thanks a lot! So just before generating PDF I now add a UIWebView, load html there, and I have a working workaround!

@davidshapiro13
Copy link

Thank you so much for posting this, I have been searching all over for answers. Do I have your permission to use this code in an app?

@josephlive88
Copy link

@ReDetection, it only works for UIWebView for some weird reasons. As much as I try to avoid using UIWebView due to the fact it is deprecated, I just couldn't get WKWebView to work. It is able to render custom html page perfectly, but when I generate to PDF, all images disappeared. Any solution for WKWebView? Since its already 2018.

@nyg
Copy link
Author

nyg commented Oct 4, 2018

Thank you so much for posting this, I have been searching all over for answers. Do I have your permission to use this code in an app?

@davidshapiro13 Sorry for the delay... yes, sure!

@sllvn
Copy link

sllvn commented Oct 5, 2018

This is awesome. Thanks much.

A note for React Native folks: UIKit is not thread-safe, and React Native currently calls native module methods off main thread, so you'll want to request the main thread (as described or via DispatchQueue.main.async). Otherwise you'll get cryptic EXC_I386_BPT errors when instantiating your UIMarkupTextPrintFormatter.

@ddnn55
Copy link

ddnn55 commented Nov 11, 2018

Awesome, just one question... I'm setting page to 6 * 72 x 4 * 72 (6 inches wide by 4 inches tall). My content is cropped to that size, but the actual paper size in the PDF is 8.5x11. Do we know how to set the actual paper size?

@Jimenaleonbm
Copy link

Awesome, just one question... I'm setting page to 6 * 72 x 4 * 72 (6 inches wide by 4 inches tall). My content is cropped to that size, but the actual paper size in the PDF is 8.5x11. Do we know how to set the actual paper size?

Hi, how could you solve this?

@vixenaga
Copy link

Hi, do you know how to open a file after creating it? I tried this:
UIApplication.shared.open(outputURL, options: [:], completionHandler: { (success) in
Swift.print("Open url : (success)")
})
but I am getting false.

@GuzAlex
Copy link

GuzAlex commented Jan 8, 2020

Hi, who know how to edit pdf/doc file?

@Udit-sys
Copy link

Hi,

Actually my html content is cutting off on right?

Is there a way to set custom page for pdf...please see i dont require to print the pdf but just download it.

Thanks in advance.

@KaanYT
Copy link

KaanYT commented Aug 12, 2020

Objective-C Version

+(NSData*)htmlToPdf:(NSString*)html{
    //Formatter
    UIMarkupTextPrintFormatter * fmt = [[UIMarkupTextPrintFormatter alloc] initWithMarkupText:html];
    
    //Renderer
    UIPrintPageRenderer * render = [[UIPrintPageRenderer alloc] init];
    [render addPrintFormatter:fmt startingAtPageAtIndex:0];
    
    //Assign Printable Rect
    CGRect pageSize = CGRectMake(0, 0, 595.2, 841.8);// A4, 72 dpi
    [render setValue:[NSValue valueWithCGRect:pageSize] forKey:@"paperRect"];
    [render setValue:[NSValue valueWithCGRect:pageSize] forKey:@"printableRect"];
    
    //Create PDF Context and Draw
    NSMutableData* data = [[NSMutableData alloc] init];
    UIGraphicsBeginPDFContextToData(data, CGRectZero, NULL);
    
    for (int i=0; i<render.numberOfPages; i++) {
        UIGraphicsBeginPDFPage();
        [render drawPageAtIndex:i inRect: UIGraphicsGetPDFContextBounds()];
    }

    UIGraphicsEndPDFContext();

    return data;
}

@matrosovDev
Copy link

I also faced with image issue, just wonder if this resolved I've tried a few solutions but it still does not work for me. I tried to save image to the files and used base 64 image, but still with no luck

https://stackoverflow.com/questions/66251424/creating-pdf-file-with-uiimage-inserted-to-html-code

@Udit-sys
Copy link

Hey,
I think you need to use javascript with your HTML code to load image in web view and then create a pdf
Use evaluateJavaScript() to run javascript in web view

@matrosovDev
Copy link

Hey,
I think you need to use javascript with your HTML code to load image in web view and then create a pdf
Use evaluateJavaScript() to run javascript in web view

Now all works good! I used link above https://github.com/nyg/HTMLWithImagesToPDF in a wrong way. Image is in the PDF file now. thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment