Last active
November 29, 2018 16:31
-
-
Save vin-the-dev/899869df4f1538ffc7d6 to your computer and use it in GitHub Desktop.
PDF Creation from iOS swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// CustomPageRenderer.swift | |
// (c) 2016 Vineeth Vijayan, licensed under the MIT License | |
// Inspired by https://gist.github.com/mattt/bd5e48ae461848cdbd1e#file-recipepagerenderer-swift | |
import UIKit | |
import AVFoundation | |
/// Units for printing content insets | |
let POINTS_PER_INCH: CGFloat = 72 | |
/// The alignment for drawing an NSString inside a bounding rectangle. | |
enum NCStringAlignment { | |
case LeftTop | |
case CenterTop | |
case RightTop | |
case LeftCenter | |
case Center | |
case RightCenter | |
case LeftBottom | |
case CenterBottom | |
case RightBottom | |
} | |
extension NSString { | |
/// Draw the `NSString` inside the bounding rectangle with a given alignment. | |
func drawAtPointInRect(rect: CGRect, withAttributes attributes: [String: AnyObject]?, andAlignment alignment: NCStringAlignment) { | |
let size = self.sizeWithAttributes(attributes) | |
var x, y: CGFloat | |
switch alignment { | |
case .LeftTop, .LeftCenter, .LeftBottom: | |
x = CGRectGetMinX(rect) | |
case .CenterTop, .Center, .CenterBottom: | |
x = CGRectGetMidX(rect) - size.width / 2 | |
case .RightTop, .RightCenter, .RightBottom: | |
x = CGRectGetMaxX(rect) - size.width | |
} | |
switch alignment { | |
case .LeftTop, .CenterTop, .RightTop: | |
y = CGRectGetMinY(rect) | |
case .LeftCenter, .Center, .RightCenter: | |
y = CGRectGetMidY(rect) - size.height / 2 | |
case .LeftBottom, .CenterBottom, .RightBottom: | |
y = CGRectGetMaxY(rect) - size.height | |
} | |
self.drawAtPoint(CGPoint(x: x, y: y), withAttributes: attributes) | |
} | |
} | |
class CustomPrintPageRenderer: UIPrintPageRenderer { | |
let authorName: NSString | |
let pageNumberAttributes = [NSFontAttributeName: UIFont(name: "Georgia-Italic", size: 11)!] | |
let nameAttributes = [NSFontAttributeName: UIFont(name: "Georgia", size: 11)!] | |
init(authorName: String, html: String) { | |
self.authorName = "Vineeth" // authorName | |
super.init() | |
self.headerHeight = 0.5 * POINTS_PER_INCH | |
self.footerHeight = POINTS_PER_INCH * 1.5 | |
} | |
override func drawFooterForPageAtIndex(pageIndex: Int, var inRect headerRect: CGRect) { | |
print("top : " + CGRectGetMinY(headerRect).description) | |
print("bottom : " + (CGRectGetMaxY(paperRect) - CGRectGetMaxY(headerRect)).description) | |
let headerInsets = UIEdgeInsets(top: CGRectGetMinY(headerRect), left: POINTS_PER_INCH * 2, bottom: 20, right: POINTS_PER_INCH) | |
headerRect = UIEdgeInsetsInsetRect(paperRect, headerInsets) | |
// Image left | |
let img = UIImage(named: "flag") | |
img?.drawAtPoint(CGPoint(x: 70, y: 760)) | |
authorName.drawAtPointInRect(headerRect, withAttributes: nameAttributes, andAlignment: .LeftCenter) | |
// page number on right | |
let pageNumberString: NSString = "\(pageIndex + 1)" | |
pageNumberString.drawAtPointInRect(headerRect, withAttributes: pageNumberAttributes, andAlignment: .RightCenter) | |
} | |
func drawImages(images: [UIImage], var inRect sourceRect: CGRect) { | |
// we'll use 1/8 of an inch of vertical padding between each image | |
let imagePadding = UIEdgeInsets(top: POINTS_PER_INCH / 8, left: 0, bottom: 0, right: 0) | |
for image in images { | |
// get the aspect-fit size of the image | |
var sizedRect = AVMakeRectWithAspectRatioInsideRect(image.size, sourceRect) | |
// if the new width of the image doesn't match the source rect, there wasn't enough vertical room: bail | |
if sizedRect.width != sourceRect.width { | |
return | |
} | |
// use divide to separate the image rect from the rest of the column | |
CGRectDivide(sourceRect, &sizedRect, &sourceRect, sizedRect.height, .MinYEdge) | |
// draw the image | |
image.drawInRect(sizedRect) | |
// inset the source rect to make a little padding before the next image | |
sourceRect = UIEdgeInsetsInsetRect(sourceRect, imagePadding) | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//http://stackoverflow.com/questions/6553540/merge-pdf-files-on-ios/35028513#35028513 | |
//http://stackoverflow.com/a/35028513/2100226 | |
//Using | |
func combinePDF() { | |
let file = "fileName.pdf" | |
let documentPaths = Path.temporaryDir[file].path_string | |
print(documentPaths) | |
let fullPDFOutput: CFURLRef = NSURL(fileURLWithPath: documentPaths) | |
let writeContext = CGPDFContextCreateWithURL(fullPDFOutput, nil, nil) | |
var pdfPagesURLArray = [String]() | |
for i in 0...(htmlURLs.count - 1) { | |
pdfPagesURLArray.insert(Path.temporaryDir["file" + i.description + ".pdf"].path_string, atIndex: i) | |
} | |
for pdfURL in pdfPagesURLArray { | |
let pdfPath: CFURLRef = NSURL(fileURLWithPath: pdfURL) | |
let pdfReference = CGPDFDocumentCreateWithURL(pdfPath) | |
let numberOfPages = CGPDFDocumentGetNumberOfPages(pdfReference) | |
var page: CGPDFPageRef | |
var mediaBox: CGRect | |
for index in 1...numberOfPages { | |
guard let getCGPDFPage = CGPDFDocumentGetPage(pdfReference, index) else { | |
NSLog("Error occurred in creating page") | |
return | |
} | |
page = getCGPDFPage | |
mediaBox = CGPDFPageGetBoxRect(page, .MediaBox) | |
CGContextBeginPage(writeContext, &mediaBox) | |
CGContextDrawPDFPage(writeContext, page) | |
CGContextEndPage(writeContext) | |
} | |
} | |
NSLog("DONE!") | |
CGPDFContextClose(writeContext); | |
NSLog(documentPaths) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//To generate pdf from html, | |
//htmlURLs is a list of paths to multipe htmls | |
//I have created multiple html's because page break was not working as required | |
func webViewDidFinishLoad(webView: UIWebView) { | |
let htmlString = Path.documentsDir["web" + webView.tag.description + ".html"].readString() | |
let render = UIPrintPageRenderer(authorName: "Vineeth", html: htmlString!) | |
let fmt = _webVeiw.viewPrintFormatter() // UIMarkupTextPrintFormatter(markupText: htmlString!) | |
fmt.contentInsets = UIEdgeInsets(top: 72, left: 72, bottom: 72, right: 72) | |
render.addPrintFormatter(fmt, startingAtPageAtIndex: 0) | |
let page = CGRect(x: 0, y: 0, width: 595.2, height: 841.8) // A4, 72 dpi | |
let printable = CGRectInset(page, 0, 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, CGRectZero, nil) | |
for i in 1 ... render.numberOfPages() { | |
UIGraphicsBeginPDFPage(); | |
let bounds = UIGraphicsGetPDFContextBounds() | |
render.drawPageAtIndex(i - 1, inRect: bounds) | |
} | |
UIGraphicsEndPDFContext(); | |
// 5. Save PDF file | |
let path = "\(NSTemporaryDirectory())file" + _webVeiw.tag.description + ".pdf" | |
pdfData.writeToFile(path, atomically: true) | |
print("open \(path)") | |
if webView.tag < htmlURLs.count - 1 { | |
_webVeiw.tag = _webVeiw.tag + 1 | |
_webVeiw.loadRequest(NSURLRequest(URL: NSURL(fileURLWithPath: Path.documentsDir[htmlURLs[_webVeiw.tag]].path_string))) | |
} | |
else { | |
combinePDF() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment