-
-
Save nyg/b8cd742250826cb1471f to your computer and use it in GitHub Desktop.
// 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 |
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...
How to you Print a tableView in to a PDF file.
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).
can we have a local image loaded in html and print it with img tag?
I can't make images work!
can someone elaborate on how are you writing the src=" " when having problems with the images?
I'm Losing a paragraph to reach the limit leaf, Any ideas??
src='data:image/png;base64,(imageString) tambien para mi no funciona
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) {
//
}];
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.
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 WKWebView
but 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"))
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?
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
@nyg thanks a lot! So just before generating PDF I now add a UIWebView, load html there, and I have a working workaround!
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?
@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.
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!
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
.
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?
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?
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.
Hi, who know how to edit pdf/doc file?
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.
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;
}
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
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
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
Great example! Did you tried to add base64 encoded images to the HTML? For me it doesn't work...