Android App Development
iOS App Development
Flutter App Development
Cross Platform App Development
Hire on-demand project developers and turn your idea into working reality.
Big thanks to Webkul and his team for helping get Opencart 3.0.3.7 release ready!
Deniel Kerr
Founder. Opencart
Top Partners
Updated 2 December 2020
In the article, I will discuss, how we can create PDF programmatically using the PDFKit framework.
First of all, The PDFKit is a framework available in AppKit since iOS 11.0 and macOS 10.4. Please click here to read more about PDFKit.
PDFView is mainly used to show the pdf file in our application and also it allows users to set zoom level, select content, navigate through a document, and copy the textual content to the Pasteboard, and also keeps track of page history.
Swift version: 5 iOS version: 13 Xcode: 11.3
First Create a project from Xcode.
File ▸ New ▸ Project…. Choose the iOS ▸ Application ▸ Single View App template and create a new project.
Then create a PDFCreator class where we will add all functions and variables which helps us to create the PDF.
Now we will add basic variables that manage the PDF layout.
pageWidth : To define page width of PDF.
pageHeight : To define page Height of PDF.
marginPoint : To define the page margin of PDF.
currentPage : To Store page count of the PDF.
Now create a function that creates the actual PDF data.
Now add a page footer in the PDF.
And, Now show this PDF Data in the ViewController.
I hope this code will help you better to understand how PDF generates. If you feel any doubt or query please comment below.
Thank you.
Your email address will not be published. Required fields are marked*
Name*
Email*
Save my name email and website in this browser for the next time I comment.
It would be great if you could write a similar post dedicated to macOS ! How generate a pdf on macOS big sur ? Thanks
class PDFCreator: NSObject { var headerImage = UIImage(named: “qr-code”) let defaultOffset: CGFloat = 20 let tableDataItems: String var yPosition : CGFloat = 0 var drawContext: CGContext! var topMargin : CGFloat = 70 var bottomMargin : CGFloat = 30 var currentPageNo = 1 var title = “” var topTitle = “CUSTOM REPORT”
var backgroundColor = UIColor(hexString: “#F19A37”) init(tableDataItems: String,headerImage:UIImage,title:String,topTitle:String) { self.tableDataItems = tableDataItems self.headerImage = headerImage self.title = title self.topTitle = topTitle }
func create() -> Data { // default page format let pageWidth = 8.3 * 72.0 let pageHeight = 11 * 72.0 let pageRect = CGRect(x: 0, y: 0, width: pageWidth, height: pageHeight) let renderer = UIGraphicsPDFRenderer(bounds: pageRect, format: UIGraphicsPDFRendererFormat()) let data = renderer.pdfData { context in drawContext = context.cgContext context.beginPage() drawTableHeaderTitles( pageRect: pageRect) footer(pageRect: pageRect) drawtitle(pageRect: pageRect) drawTableData(drawContext: drawContext, pageRect: pageRect, data: tableDataItems) if currentPageNo != 1{ waterMark(pageRect: pageRect, context: drawContext) } } return data }
func calculateNumberOfElementsPerPage(with pageRect: CGRect) -> Int { let rowHeight = (defaultOffset * 3) let number = Int((pageRect.height – rowHeight) / rowHeight) return number } }
// Drawings extension PDFCreator { func drawtitle(pageRect: CGRect){ if title != “”{ drawContext.saveGState()
let style = NSMutableParagraphStyle()
style.alignment = NSTextAlignment.center var att = boldAttribute(size: 16, color: .black) att[.paragraphStyle] = style let attributedText = NSAttributedString(string: title, attributes: att) let height = attributedText.height(containerWidth: pageRect.width – (2*defaultOffset)) let textRect = CGRect(x: 10 , y: yPosition + 10, width: pageRect.width, height: height) attributedText.draw(in: textRect) title = “” yPosition += height + 20 drawContext.restoreGState() } }
func drawTableTopImage(drawContext: CGContext,pageRect: CGRect,image:UIImage) { drawContext.saveGState() drawContext.restoreGState() image.draw(in: pageRect) let textFont = UIFont.systemFont(ofSize: 45) let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.alignment = .left paragraphStyle.lineBreakMode = .byWordWrapping paragraphStyle.alignment = NSTextAlignment.center let textAttributes = [ NSAttributedString.Key.paragraphStyle: paragraphStyle, NSAttributedString.Key.font: textFont, NSAttributedString.Key.foregroundColor : UIColor.white ]
let attributedText = NSAttributedString(string: topTitle, attributes: textAttributes) let textRect = CGRect(x: 110 , y: 195, width: 350, height: 140) attributedText.draw(in: textRect) yPosition += pageRect.height
}
func drawTableData(drawContext: CGContext,pageRect: CGRect,data: String) {
drawContext.setLineWidth(1.0) drawContext.saveGState()
drawContext.move(to: CGPoint(x: defaultOffset, y: defaultOffset ))
var lastDrawnFrame = CGRect(x: 0, y: 0, width: 0, height: 0) let textAttributes = normalAttribute() let actualRiskName = NSAttributedString(string: data, attributes: textAttributes)
lastDrawnFrame = drawAttributedText(actualRiskName,width:pageRect.width – 20, pageRect: pageRect, currentOffset: CGPoint(x: defaultOffset + lastDrawnFrame.width + 13, y: yPosition-1 )) yPosition = lastDrawnFrame.origin.y + lastDrawnFrame.height
yPosition += 10
drawContext.restoreGState()
func footer (pageRect: CGRect){ drawContext.saveGState() drawContext.setFillColor(backgroundColor.cgColor) let textFont = UIFont.systemFont(ofSize: 10) let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.alignment = .center paragraphStyle.lineBreakMode = .byWordWrapping let textAttributes = [ NSAttributedString.Key.paragraphStyle: paragraphStyle, NSAttributedString.Key.font: textFont, NSAttributedString.Key.foregroundColor:UIColor.white ] drawContext.move(to: CGPoint(x: 0, y: pageRect.height – bottomMargin)) drawContext.addRect(CGRect(x: 0, y: Int(pageRect.height – bottomMargin), width: Int((pageRect.width – 60)/3), height: Int(bottomMargin))) drawContext.fill(CGRect(x: 0, y: Int(pageRect.height – bottomMargin), width: Int((pageRect.width – 60)/3), height: Int(bottomMargin))) var text = NSAttributedString(string: “Webkul Software PVT LTD.”, attributes: textAttributes)
text.draw(in: CGRect(x: 0, y: Int(pageRect.height – bottomMargin + 7), width: Int((pageRect.width – 60)/3), height: Int(bottomMargin))) drawContext.setFillColor(backgroundColor.cgColor) drawContext.addRect(CGRect(x: Int((pageRect.width – 60)/3) + 2, y: Int(pageRect.height – bottomMargin), width: Int((pageRect.width – 60)/3), height: Int(bottomMargin))) drawContext.fill(CGRect(x: Int((pageRect.width – 60)/3) + 2, y: Int(pageRect.height – bottomMargin), width: Int((pageRect.width – 60)/3), height: Int(bottomMargin))) text = NSAttributedString(string: “000-000-0000”, attributes: textAttributes)
text.draw(in: CGRect(x: Int((pageRect.width – 60)/3) + 2, y: Int(pageRect.height – bottomMargin + 7), width: Int((pageRect.width – 60)/3), height: Int(bottomMargin)))
drawContext.setFillColor(backgroundColor.cgColor)
drawContext.addRect(CGRect(x: (Int((pageRect.width – 60)/3) * 2) + 4, y: Int(pageRect.height – bottomMargin), width: Int((pageRect.width – 60)/3), height: Int(bottomMargin))) drawContext.fill(CGRect(x: (Int((pageRect.width – 60)/3) * 2) + 4, y: Int(pageRect.height – bottomMargin), width: Int((pageRect.width – 60)/3), height: Int(bottomMargin))) text = NSAttributedString(string: “[email protected]”, attributes: textAttributes)
text.draw(in: CGRect(x: (Int((pageRect.width – 60)/3) * 2) + 4, y: Int(pageRect.height – bottomMargin + 7), width: Int((pageRect.width – 60)/3), height: Int(bottomMargin)))
drawContext.setFillColor(backgroundColor.cgColor) drawContext.addRect(CGRect(x: Int(pageRect.width – 54), y: Int(pageRect.height – bottomMargin), width: 54, height: Int(bottomMargin))) drawContext.fill(CGRect(x: Int(pageRect.width – 54), y: Int(pageRect.height – bottomMargin), width: 54, height: Int(bottomMargin))) text = NSAttributedString(string: “\(currentPageNo)”, attributes: textAttributes)
text.draw(in: CGRect(x: Int(pageRect.width – 54), y: Int(pageRect.height – bottomMargin + 7), width: 54, height: Int(bottomMargin)))
drawContext.strokePath() drawContext.restoreGState() currentPageNo += 1 } func drawTableHeaderTitles( pageRect: CGRect) { drawContext.saveGState() drawContext.move(to: CGPoint(x: 100, y: 0 )) headerImage?.draw(in: CGRect(x: 0, y: 0, width: 50, height: 50)) headerImage?.draw(in: CGRect(x: pageRect.width – 50, y: 0, width: 50, height: 50)) drawContext.setFillColor(UIColor(hexString: “#F19A37”).cgColor) drawContext.move(to: CGPoint(x: 0, y: topMargin – 2)) drawContext.addLine(to: CGPoint(x: pageRect.width, y: topMargin – 2)) drawContext.strokePath() drawContext.restoreGState()
} //paragraphStyle.alignment = NSTextAlignment.Justified
fileprivate func drawAttributedText( _ attributedText: NSAttributedString,width:CGFloat, pageRect: CGRect,currentOffset: CGPoint) -> CGRect {
var drawingYoffset = currentOffset.y
let currentText = CFAttributedStringCreateCopy(nil, attributedText as CFAttributedString) let framesetter = CTFramesetterCreateWithAttributedString(currentText!) var currentRange = CFRange(location: 0, length: 0) var done = false
var lastDrawnFrame: CGRect!
repeat { drawContext.saveGState()
drawContext.textMatrix = CGAffineTransform.identity
let textMaxWidth = width – defaultOffset * 2 let textMaxHeight = pageRect.height – (drawingYoffset + topMargin + 10) – bottomMargin – 10
let frameRect = CGRect(x: currentOffset.x, y: drawingYoffset , width: textMaxWidth, height: textMaxHeight) let framePath = UIBezierPath(rect: frameRect).cgPath
let frameRef = CTFramesetterCreateFrame(framesetter, currentRange, framePath, nil)
drawContext.translateBy(x: 0, y: pageRect.height + drawingYoffset – bottomMargin) drawContext.scaleBy(x: 1.0, y: -1.0)
// Draw the frame. CTFrameDraw(frameRef, drawContext)
// Pop state drawContext.restoreGState()
// Update the current range based on what was drawn. let visibleRange = CTFrameGetVisibleStringRange(frameRef) currentRange = CFRange(location: visibleRange.location + visibleRange.length , length: 0)
// Update last drawn frame let constraintSize = CGSize(width: textMaxWidth, height: textMaxHeight) let drawnSize = CTFramesetterSuggestFrameSizeWithConstraints(framesetter, visibleRange, nil, constraintSize, nil) lastDrawnFrame = CGRect(x: currentOffset.x, y: drawingYoffset, width: drawnSize.width, height: drawnSize.height)
if currentRange.location == CFAttributedStringGetLength(currentText) { done = true // print(“exit”) } else { // begin a new page to draw text that is remaining.
createPage(pageRect:pageRect) drawingYoffset = 0 yPosition = 0 // print(“begin a new page to draw text that is remaining”) }
} while(!done)
return lastDrawnFrame } func boldAttribute(size: CGFloat,color:UIColor) -> [NSAttributedString.Key : NSObject]{ let textFont = UIFont.boldSystemFont(ofSize: size) let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.alignment = .left paragraphStyle.lineBreakMode = .byWordWrapping let textAttributes = [ NSAttributedString.Key.paragraphStyle: paragraphStyle, NSAttributedString.Key.font: textFont, NSAttributedString.Key.foregroundColor : color ] return textAttributes } func normalAttribute() -> [NSAttributedString.Key : NSObject]{ let textFont = UIFont.systemFont(ofSize: 10.0) let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.alignment = .left paragraphStyle.lineBreakMode = .byWordWrapping let textAttributes = [ NSAttributedString.Key.paragraphStyle: paragraphStyle, NSAttributedString.Key.font: textFont // NSAttributedString.Key.foregroundColor : UIColor(hexString: “333333”)
] return textAttributes } func waterMark(pageRect: CGRect, context: CGContext) {
// Draw rotated overlay string UIGraphicsPushContext(context) context.saveGState() let attributes: [NSAttributedString.Key: Any] = [ NSAttributedString.Key.foregroundColor: #colorLiteral(red: 0.5899451484, green: 0.5899451484, blue: 0.5899451484, alpha: 0.2536386986), NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: 64) ] drawVerticalText(text: “PDFKit app”, withAttributes: attributes, origin: CGPoint(x: 250, y: 450) , context: drawContext)
context.restoreGState() UIGraphicsPopContext()
} func drawVerticalText(text: String, withAttributes attributes: [NSAttributedString.Key: Any]?, origin: CGPoint, context: CGContext) {
let halfRadian : CGFloat = -(CGFloat.pi / 5.0)
context.rotate(by: halfRadian )
let translatedOrigin = CGPoint(x: -origin.x, y: origin.y)
// Draw the text.
text.draw(at: translatedOrigin, withAttributes: attributes)
context.rotate(by: -halfRadian ) } func createPage(pageRect:CGRect){ if currentPageNo != 1{ waterMark(pageRect: pageRect, context: drawContext) } UIGraphicsBeginPDFPageWithInfo(pageRect, nil) footer(pageRect: pageRect) drawTableHeaderTitles( pageRect: pageRect) yPosition = 0 }
extension NSAttributedString {
func height(containerWidth: CGFloat) -> CGFloat {
let rect = self.boundingRect(with: CGSize.init(width: containerWidth, height: CGFloat.greatestFiniteMagnitude), options: [.usesLineFragmentOrigin, .usesFontLeading], context: nil) return ceil(rect.size.height) }
func width(containerHeight: CGFloat) -> CGFloat {
let rect = self.boundingRect(with: CGSize.init(width: CGFloat.greatestFiniteMagnitude, height: containerHeight), options: [.usesLineFragmentOrigin, .usesFontLeading], context: nil) return ceil(rect.size.width) } }
We use cookies to personalize your experience. By continuing to visit this website you agree to our use of cookies. Learn more about privacy policy
Name
Email
Subject
Enquiry or Requirement
If you have more details or questions, you can reply to the received confirmation email.