Create and store PDF document programmatically using Swift for iOS - ios

I have an app that can view a PDF that is already stored within the project. I want to be able to create a new PDF document and store it in the app directory to later view in the already existing viewer. The PDF would be created from an array var todoList: [String] = [] that is displayed on a UITableView. I know to create a PDF, I have to create a file name, path, and directory. I don't know how to do this. I saw online reference to URL and URL request, but I'm not sure if this is the correct avenue for what I want to do. Can someone please give me some advice and guidance? Everything I can find is for Objective-C.

I used this code to create and save the file (using HTML)
func createPDF() {
let html = "<b>Hello <i>World!</i></b> <p>Generate PDF file from HTML in Swift</p>"
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
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, .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 documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
pdfData.write(toFile: "\(documentsPath)/file.pdf", atomically: true)
}
Then I loaded it into UIWebView from the documents directory with this code:
func loadPDF(filename: String) {
let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
let url = URL(fileURLWithPath: documentsPath, isDirectory: true).appendingPathComponent(filename).appendingPathExtension("pdf")
let urlRequest = URLRequest(url: url)
webView.loadRequest(urlRequest)
}

For Swift 3:
createPdf() {
// 1. Create Print Formatter with input text.
let formatter = UIMarkupTextPrintFormatter(markupText: textView.text)
// 2. Add formatter with pageRender
let render = UIPrintPageRenderer()
render.addPrintFormatter(formatter, 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 rect = CGRect.zero
let pdfData = NSMutableData()
UIGraphicsBeginPDFContextToData(pdfData, rect, nil)
for i in 1...render.numberOfPages {
UIGraphicsBeginPDFPage();
let bounds = UIGraphicsGetPDFContextBounds()
render.drawPage(at: i - 1, in: bounds)
}
UIGraphicsEndPDFContext();
// 5. Save PDF file
let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
pdfData.write(toFile: "\(documentsPath)/new.pdf", atomically: true)
print("saved success")
}

Related

UIGraphicsBeginPDFContextToData does not show image after pdf creation

I am working on the HtmltoPDF creation. It is working fine when some image URL but not working with my server image URL.
Working URL downloaded from the google
Issue in the server image URL
I have put here my code for the pdf generation. Please find it
func exportHTMLContentToPDF(HTMLContent: String) -> String {
let printPageRenderer = IPPrintPageRenderer()
let printFormatter = UIMarkupTextPrintFormatter(markupText: HTMLContent)
printPageRenderer.addPrintFormatter(printFormatter, startingAtPageAt: 0)
let pdfData = drawPDFUsingPrintPageRenderer(printPageRenderer: printPageRenderer)
let str = "\(Global.kretriveUserData().firstName!.firstCharacter!)\(Global.kretriveUserData().Name!.firstCharacter!)".uppercased()
pdfFilename = "\(getDocDir())/\(str + invoiceNumber!).pdf"
pdfData?.write(toFile: pdfFilename, atomically: true)
print(pdfFilename)
return pdfFilename
}
func drawPDFUsingPrintPageRenderer(printPageRenderer: UIPrintPageRenderer) -> NSData! {
let data = NSMutableData()
UIGraphicsBeginPDFContextToData(data, CGRect.zero, nil)
for i in 0..<printPageRenderer.numberOfPages {
UIGraphicsBeginPDFPage()
printPageRenderer.drawPage(at: i, in: UIGraphicsGetPDFContextBounds())
}
UIGraphicsEndPDFContext()
return data
}
func getDocDir() -> String {
return NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
}
You can find a full demo here.
Thanks,
To generate a pdf from a webView you need to prepare your HTML code, create the WebView and inject the HTML code inside the webView and in webView didFinishLoading print the HTML content inside the pdf using the same width and height of the webView.
func webViewDidFinishLoad(_ webView: UIWebView) {
let render = UIPrintPageRenderer()
render.addPrintFormatter(webView.viewPrintFormatter(), startingAtPageAt: 0);
let page = CGRect(x: 0, y: 10, width: webView.frame.size.width, height: webView.frame.size.height) // take the size of the webView
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();
let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
print(documentsPath)
pdfData.write(toFile: "\(documentsPath)/pdfName.pdf", atomically: true)
self.pdfPath = "\(documentsPath)/pdfName.pdf"
self.pdfTitle = "pdfName"
self.performSegue(withIdentifier: "showPDFSegue", sender: nil)
webView.removeFromSuperview()
self.loadingScreenViewController.view.removeFromSuperview()
}
Happy coding:)

Swift Save UITextView Text to .Pdf, .Doc and .Txt file formate and Display

My Scenario, I am trying to save UITextView Text with Three format .pdf, .doc and .txt. Here, formate option user can choose based on alert option. Once Its saved need to show in Preview controller for file sharing. How to achieve this?
func createPDF(text:String, filename:String) {
// 1. Create Print Formatter with input text.
let formatter = UIMarkupTextPrintFormatter(markupText: text)
// 2. Add formatter with pageRender
let render = UIPrintPageRenderer()
render.addPrintFormatter(formatter, 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 rect = CGRect.zero
let pdfData = NSMutableData()
UIGraphicsBeginPDFContextToData(pdfData, rect, nil)
for i in 1...render.numberOfPages {
UIGraphicsBeginPDFPage();
let bounds = UIGraphicsGetPDFContextBounds()
render.drawPage(at: i - 1, in: bounds)
}
UIGraphicsEndPDFContext();
// 5. Save PDF file
let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
pdfData.write(toFile: "\(documentsPath)/\(filename).pdf", atomically: true)
print("saved success:\(documentsPath)\(filename)")
listFiles()
}
Try the following code :)
let txtData = Data(textView.txt.utf8)
do {
let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
let filePath = (documentsPath as NSString).appendingPathComponent("\(filename).pdf")
let url = URL(fileURLWithPath: filePath)
// pdfData created by your code above
// txtData for ".txt"
pdfData.write(to: url)
let activityVC = UIActivityViewController(activityItems: [url], applicationActivities: nil)
// Use your desired viewController here, or just use the rootViewController
UIApplication.shared.keyWindow?.rootViewController?.presentViewController(activityVC, animated: true, completion: nil)
} catch (let error) {
print("\(error)")
}
If i understand correct you need show documents
You can do this with QLPreviewController
More info in -
https://developer.apple.com/documentation/quicklook
https://developer.apple.com/documentation/quicklook/qlpreviewcontroller#//apple_ref/occ/cl/QLPreviewController
https://medium.com/#garg.vivek/quick-display-documents-with-qlpreviewcontroller-eaca97928c7a
QLPreviewController have sharing control

How to image write in pdf through html in Swift 4

How to image write in pdf through html in Swift 4?
func createPDF(html: String, formmatter: UIViewPrintFormatter, filename: String) -> String
{
let fmt = UIMarkupTextPrintFormatter(markupText: sampleHTML)
// 2. Assign print formatter to UIPrintPageRenderer
let render = UIPrintPageRenderer()
render.addPrintFormatter(fmt, startingAtPageAt: 0)
render.drawPrintFormatter(formmatter, forPageAt: 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
UIGraphicsBeginPDFContextToData(pdfData, CGRect.zero, nil)
UIGraphicsBeginImageContext(CGSize.zero)
for i in 1...render.numberOfPages
{
UIGraphicsBeginPDFPage();
let bounds = UIGraphicsGetPDFContextBounds()
render.drawPage(at: i - 1, in: bounds)
}
UIGraphicsEndPDFContext();
// 5. Save PDF file
let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
print(documentsPath)
if pdfData.write(toFile: "\(documentsPath)/file.pdf", atomically: true)
{
pdfFilePath = "\(documentsPath)/file.pdf"
var URL = NSURL(fileURLWithPath: pdfFilePath!)
storedPdfFileData = try! Data(contentsOf:URL as URL)
fileName = URL.lastPathComponent
print("FileName\(fileName!)")
self.UserDefaultForfileName.setValue(self.fileName, forKey: "FILE")
}
else
{
print("choose how to handle error here")
}
return pdfFilePath!
}
If we have correctly understood, we can see two different requirements from your comments
1) you want to save the html pages to pdf.
or
2) you want to create pdf from images (list of UIImage).
for 1st approach:-
You should be using WKWebView to show html pages in your viewController. ( To know how to use WKWebView, you may search help from Stackoverflow. ) In the viewControler, you can have Button click event for 'printWebPagetoPDF" function. The function is as under.
func printWebPagetoPDF( theHeight:CGFloat = 0 ) {
var isHeightFound = true
let deviceW = UIScreen.main.bounds.size.width
let deviceH = UIScreen.main.bounds.size.height
let width = min(deviceW, deviceH)
var height = theHeight
if height <= 0 {
height = max(deviceW, deviceH)
isHeightFound = false
}
let fileParentPath = "<absolute path to save pdf file>" + "/"
let inDateTimeFormatter = DateFormatter()
inDateTimeFormatter.dateFormat = "yyyyMMddHHmm"
let dateTimeFileString = "test\(inDateTimeFormatter.string(from: Date()))"
let pdfFileName = dateTimeFileString + ".pdf"
let sharePdfFilePath = fileParentPath + pdfFileName
// - 1 - Grab the webView's print context
let fmt = myWKWebView.viewPrintFormatter()
fmt.perPageContentInsets = UIEdgeInsetsMake(10, 10, 10, 10) //Page margins
// - 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: width, height: height) //width: 841.85, height: 595.22) //Page size
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, page, nil)
print( render.numberOfPages )
render.prepare(forDrawingPages: NSMakeRange(0, render.numberOfPages-1))
for i in 0..<render.numberOfPages {
UIGraphicsBeginPDFPage()
render.drawPage(at: i, in: UIGraphicsGetPDFContextBounds())
}
UIGraphicsEndPDFContext()
// - 5 - Save the PDF file
let path = sharePdfFilePath
pdfData.write(toFile: path, atomically: true)
}
for 2nd approach:-
You may try following code to create pdf from images. I have not tested it properly, but you can try yourselves. mySelectedArray is the sequence of indexes of images to add in pdf. dataArray is array of UIImages. "import PDFKit" is required on start of swift file.
// The url to save the data to
let pdfFileName = "<some path>" + "/" + "test.pdf"
let url = URL(fileURLWithPath: pdfFileName)
if #available(iOS 11.0, *) {
// Create an empty PDF document
let pdfDocument = PDFDocument()
pdfDocument.delegate = self
for index in mySelectedArray {
// Load or create your UIImage
let image = dataArray[index].image
// Create a PDF page instance from your image
let pdfPage = PDFPage(image: image)
// Insert the PDF page into your document
pdfDocument.insert(pdfPage!, at: 0)
}
// Get the raw data of your PDF document
let data = pdfDocument.dataRepresentation()
// Save the data to the url
try! data!.write(to: url)
}
If possible, please comment clearly, for any further assistance.

Create a PDF file from a UIScrollView in Swift

I want to create a PDF file from the contents of a UIScrollView.
func createPdfFromView(aView: UIView, saveToDocumentsWithFileName fileName: String) {
let pdfData = NSMutableData()
let height = 1754.0
let width = 1240.0
UIGraphicsBeginPDFContextToData(pdfData, CGRect(x:-30, y:15,width:width,height:height) , nil)
UIGraphicsBeginPDFPage()
guard let pdfContext = UIGraphicsGetCurrentContext() else { return }
aView.layer.render(in: pdfContext)
UIGraphicsEndPDFContext()
if let documentDirectories = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first {
let documentsFileName = documentDirectories + "/" + fileName
debugPrint(documentsFileName)
pdfData.write(toFile: documentsFileName, atomically: true)
}
}
I would expect that the code generates a PDF oriented on the size of the content in the scrollview.
The code currently only generates a static PDF. If the content in the scrollview is bigger than the PDF page, the content is cut off.
func createPdfFromView()
{
// Set frame as per content of view
self.spreadsheetView.frame = CGRect(x: 0, y: 0, width: self.spreadsheetView.contentSize.width, height: self.spreadsheetView.contentSize.height)
let pdfPageBounds: CGRect = self.spreadsheetView.frame
let pdfData: NSMutableData = NSMutableData()
// Rendering spreadsheetView
UIGraphicsBeginPDFContextToData(pdfData, pdfPageBounds, nil)
UIGraphicsBeginPDFPageWithInfo(pdfPageBounds, nil)
self.spreadsheetView.layer.render(in: UIGraphicsGetCurrentContext()!)
UIGraphicsEndPDFContext()
let documentDirectories = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first
let documentsFileName = documentDirectories! + "/" + "pdfName.pdf"
pdfData.write(toFile: documentsFileName, atomically: true)
print(documentsFileName)
// Reset spreadsheetView
self.spreadsheetView.frame = CGRect(x: 0, y: 64, width: self.view.frame.width, height: self.view.frame.height)
self.spreadsheetView.layoutSubviews()
self.spreadsheetView.layoutIfNeeded()
self.spreadsheetView.reloadData()}
Hope it will help you to create PDF from the spreadsheet.
Ref. Github code Link: SpreadsheetView
I could achieve this using this Cocoapods framework. In my case I wanted to make a PDF from Spreadsheet , so that this framework help me to add table with different column size and many more features which I had wanted from my data.
https://cocoapods.org/pods/SimplePDF

Open the pdf file automatically after saving it

My app creates a pdf file when I hit enter button. I do this by the code below. At the moment I want to open the saved file automatically after saving.
The code for saving:
#IBAction func EnterButtonAction(_ sender: AnyObject) {
let html = "PDF FILE TITLE"
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: 1000) // 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();
// Save PDF file
let path = "\(NSTemporaryDirectory())MyAppFile.pdf"
pdfData.write(toFile: path, atomically: true)
print("open \(path)") // command to open the generated file
}
You can open your PDF file using UIDocumentInteractionController and find the below code:
func showFileWithPath(path: String){
let isFileFound:Bool? = NSFileManager.defaultManager().fileExistsAtPath(path)
if isFileFound == true{
let viewer = UIDocumentInteractionController(URL: NSURL(fileURLWithPath: path))
viewer.delegate = self
viewer.presentPreviewAnimated(true)
}
}
pdfData.write(toFile: path, atomically: true); is synchronous call, so you can write code to open file directly after this line, but first check if file is written successfully .
var success = pdfData.write(toFile: path, atomically: true);
if success {
//Write code to open file in Webview or UIDocumentInteractionController
}

Resources