Adding an image to a PDF file in Swift - swift

Hi i'm currently trying to get a image in a imageview added to my PDF file.
i already have text added to the PDF im just looking to get an image added in too.
Heres what i got so far
#IBAction func CreatePDF(sender: AnyObject) {
// 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, startingAtPageAtIndex: 0)
// 3. Assign paperRect and printableRect
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.pdf"
pdfData.writeToFile(path, atomically: true)
print("open \(path)") // command to open the generated file
}

Related

PDF Thumbnail Generator Always Returning Nil | Swift/Xcode

Would someone please explain to me why this pdf generator I'm attempting to use is always returning nil? I'm attempting to get a thumbnail to display in a UITableView alongside the filename of the PDF. Unfortunately, out of the four or so thumbnail generators I've tried, none of them have returned anything other than nil.
func uploadPDF() {
let types = UTType.types(tag: "pdf",
tagClass: UTTagClass.filenameExtension,
conformingTo: nil)
let documentPickerController = UIDocumentPickerViewController(forOpeningContentTypes: types)
documentPickerController.delegate = self
self.present(documentPickerController, animated: true, completion: nil)
}
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
for url in urls {
let thumbnail = thumbnailFromPdf(withUrl: url, pageNumber: 0)
self.modelController.bidPDFUploadThumbnails.append(thumbnail!)
}
tableView.reloadData()
}
func thumbnailFromPdf(withUrl url:URL, pageNumber:Int, width: CGFloat = 240) -> UIImage? {
guard let pdf = CGPDFDocument(url as CFURL),
let page = pdf.page(at: pageNumber)
else {
return nil
}
var pageRect = page.getBoxRect(.mediaBox)
let pdfScale = width / pageRect.size.width
pageRect.size = CGSize(width: pageRect.size.width*pdfScale, height: pageRect.size.height*pdfScale)
pageRect.origin = .zero
UIGraphicsBeginImageContext(pageRect.size)
let context = UIGraphicsGetCurrentContext()!
// White BG
context.setFillColor(UIColor.white.cgColor)
context.fill(pageRect)
context.saveGState()
// Next 3 lines makes the rotations so that the page look in the right direction
context.translateBy(x: 0.0, y: pageRect.size.height)
context.scaleBy(x: 1.0, y: -1.0)
context.concatenate(page.getDrawingTransform(.mediaBox, rect: pageRect, rotate: 0, preserveAspectRatio: true))
context.drawPDFPage(page)
context.restoreGState()
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
Generator source: Thumbnail Generator
the pdf document starts from page 1 not 0 because its not an array.
so simple is
let thumbnail = thumbnailFromPdf(withUrl: url, pageNumber: 1)
you'll get it
rather than using page number you can direct access the thumbnail of by default first page as follow:
import PDFKit
func generatePdfThumbnail(of thumbnailSize: CGSize , for documentUrl: URL, atPage pageIndex: Int) -> UIImage? {
let pdfDocument = PDFDocument(url: documentUrl)
let pdfDocumentPage = pdfDocument?.page(at: pageIndex)
return pdfDocumentPage?.thumbnail(of: thumbnailSize, for: PDFDisplayBox.trimBox)
}

Swift - Overlay Text on current PDF Document

I have been trying to simply overlay text onto a current PDF document that is essentially a timecard. I copy the file to the downloads folder and that works fine, but then when I try to use a CGContext to add text, it exports a white PDF document. Can anyone see where I'm going wrong?
do {
try fileManager.copyItem(at: pdfURL!, to: destinationURL)
} catch let error as NSError {
print("Copy failed :( with error: \(error)")
}
if let pdf: CGPDFDocument = CGPDFDocument(destinationURL as CFURL) { // Create a PDF Document
if pdf.numberOfPages == 1 {
let pdfPage: CGPDFPage = pdf.page(at: 1)!
let pageRect = pdfPage.getBoxRect(CGPDFBox.mediaBox)
//print(pageRect)
let context = CGContext.init(destinationURL as CFURL, mediaBox: nil, nil)
let font = NSFont(name: "Helvetica Bold", size: 20.0)
let textRect = CGRect(x: 250, y: 250, width: 500, height: 40)
let paragraphStyle: NSParagraphStyle = NSParagraphStyle.default
let textColor = NSColor.black
let textFontAttributes = [
NSAttributedStringKey.font: font!,
NSAttributedStringKey.foregroundColor: textColor,
NSAttributedStringKey.paragraphStyle: paragraphStyle
]
let text: NSString = "Hello world"
text.draw(in: textRect, withAttributes: textFontAttributes)
context?.addRect(textRect)
context?.closePDF()
}
}
The following code is what I used to overlay text on macOS. I've been trying to find a link to the source answer I got this from. If I find it I'll edit this answer with a link.
// Confirm there is a document there
if let doc: PDFDocument = PDFDocument(url: srcURL) {
// Create a document, get the first page, and set the size of the page
let page: PDFPage = doc.page(at: 0)!
var mediaBox: CGRect = CGRect(x: 0, y: 0, width: 792, height: 612)
// This is where the magic happens. Create the drawing context on the PDF
let context = CGContext(dstURL as CFURL, mediaBox: &mediaBox, nil)
let graphicsContext = NSGraphicsContext(cgContext: context!, flipped: false)
NSGraphicsContext.current = graphicsContext
context!.beginPDFPage(nil)
// Draws the PDF into the context
page.draw(with: .mediaBox, to: context!)
// Parse and Draw Text on the context
drawText()
context!.saveGState()
context!.restoreGState()
context!.endPDFPage()
NSGraphicsContext.current = nil
context?.closePDF()
}

Swift: Add file attachments (not only images) into PDF

How can I add other file attachments than images into a PDF natively in Swift or with "free" libraries? I know it is i.e. possible with the commercial library "quick pdf library" from debenu.com.
Today my working Swift3 code looks like this but does not include the above mentioned file attachment functionality:
// function PDF creation
func createPDFcontent(_ msgIDfunc: String) {
self.doctitle = msgIDfunc
self.author = "blabla"
self.creator = "blabla"
self.subject = msgIDfunc
var infoDict = [String: AnyObject]()
infoDict[kCGPDFContextTitle as String] = self.doctitle as NSString?
infoDict[kCGPDFContextAuthor as String] = self.author as NSString?
infoDict[kCGPDFContextCreator as String] = self.creator as NSString?
infoDict[kCGPDFContextSubject as String] = self.subject as NSString?
let HtmlForPDF = "<b><i><font color='red'>+++ Hello World +++</i></b></font>"
// new hmtl version
let frmt = UIMarkupTextPrintFormatter(markupText: HtmlForPDF)
// set print format
let render = UIPrintPageRenderer()
render.addPrintFormatter(frmt, startingAtPageAt: 0)
// create Paper Size for print
let page = CGRect(x: 0, y: 0, width: 595.2, height: 841.8)
let printable = page.insetBy(dx: 0, dy: 0)
render.setValue(NSValue(cgRect: page), forKey: "paperRect")
render.setValue(NSValue(cgRect: printable), forKey: "printableRect")
// create PDF context and draw
let filedata = NSMutableData()
UIGraphicsBeginPDFContextToData(filedata, CGRect.zero, infoDict)
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]
filedata.write(toFile: "\(documentsPath)/blabla.pdf", atomically: true)
}
Any hint is welcome.

How to create a PDF in Swift with Cocoa (Mac)

Xcode 7.3.2, Swift 2, Cocoa (Mac).
My app involves the user entering in some text, which can be exported to a PDF.
In the iOS version of my app, I can create the PDF relatively easily with the CoreText framework:
let html = "<font face=\'Futura\' color=\"SlateGray\"><h2>\(title)</h2></font><font face=\"Avenir\" color=\"SlateGray\"><h4>\(string)</h4></font>"
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: 10, y: 10, width: 595.2, height: 841.8) // A4, 72 dpi, margin of 10 from top and left.
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();
// 5. Save PDF file
path = "\(NSTemporaryDirectory())\(title).pdf"
pdfData.write(toFile: path, atomically: true)
However, UIMarkupTextPrintFormatter, UIPrintPageRenderer, UIGraphicsBeginPDFContextToData, and UIGraphicsEndPDFContext all do not exist on OS X. How can I do the exact same thing as I am doing with this iOS code (create a basic PDF from some HTML and write it to a certain file path as a paginated PDF) with Mac and Cocoa?
EDIT: The answer to this question is here: Create a paginated PDF—Mac OS X.
Here is a function that will generate a PDF from pure HTML.
func makePDF(markup: String) {
let directoryURL = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0]
let printOpts: [NSPrintInfo.AttributeKey: Any] = [NSPrintInfo.AttributeKey.jobDisposition: NSPrintInfo.JobDisposition.save, NSPrintInfo.AttributeKey.jobSavingURL: directoryURL]
let printInfo = NSPrintInfo(dictionary: printOpts)
printInfo.horizontalPagination = NSPrintingPaginationMode.AutoPagination
printInfo.verticalPagination = NSPrintingPaginationMode.AutoPagination
printInfo.topMargin = 20.0
printInfo.leftMargin = 20.0
printInfo.rightMargin = 20.0
printInfo.bottomMargin = 20.0
let view = NSView(frame: NSRect(x: 0, y: 0, width: 570, height: 740))
if let htmlData = markup.dataUsingEncoding(NSUTF8StringEncoding) {
if let attrStr = NSAttributedString(HTML: htmlData, options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType], documentAttributes: nil) {
let frameRect = NSRect(x: 0, y: 0, width: 570, height: 740)
let textField = NSTextField(frame: frameRect)
textField.attributedStringValue = attrStr
view.addSubview(textField)
let printOperation = NSPrintOperation(view: view, printInfo: printInfo)
printOperation.showsPrintPanel = false
printOperation.showsProgressPanel = false
printOperation.run()
}
}
}
What is happening:
Put the HTML into a NSAttributedString.
Render the NSAttributedString to a NSTextField.
Render the NSTextField to a NSView.
Create a NSPrintOperation with that NSView.
Set the printing parameters to save as a PDF.
Run the print operation (which actually opens a dialog to save the PDF)
Everyone is happy.
This is not a perfect solution. Note the hard coded integer values.

change resolution and size of image with cocoa/osx/swift (no mobile apps)

I try to change the size and the resolution of an image programmatically, afterwards I save this image.
The imagesize in the imageView is changing, but when I look at my file "file3.png" it always has the original resolution of 640x1142.
I googled around but can't find a solution. I try to redraw the image. But maybe it's the wrong strategy.
thanks
#IBAction func pickOneImageBtn(sender: AnyObject) {
//load image from path
pickedImage.image = loadImageFromPath(fileInDocumentsDirectory("Angebote.png"))
let newSize = NSSize(width: 10, height: 10)
if let image = pickedImage.image {
print("found image")
//cast to CGImage
var imageRect:CGRect = CGRectMake(0, 0, image.size.width, image.size.height)
let imageRef = image.CGImageForProposedRect(&imageRect, context: nil, hints: nil)
if let imageRefExists = imageRef {
print("Cast to CGImage worked \(imageRefExists)")
}
//redraw to NSImage with new size
let imageWithNewSize = NSImage(CGImage: imageRef!, size: newSize)
//save on disk
let imgData: NSData! = imageWithNewSize.TIFFRepresentation!
let bitmap: NSBitmapImageRep! = NSBitmapImageRep(data: imgData!)
if let pngCoverImage = bitmap!.representationUsingType(NSBitmapImageFileType.NSPNGFileType, properties: [:]) {
pngCoverImage.writeToFile("/...correctpath.../imageSourceForResize/file3.png", atomically: false)
print("saved new image")
}
//the size is smaller
pickedImage.image = imageWithNewSize
}
}
Change
let imgData: NSData! = pickedImage.image!.TIFFRepresentation!
to
let imgData: NSData! = imageWithNewSize.TIFFRepresentation!
I tried to change the size of a NSImage for Mac application and here is the working function to resize an image written in swift.
func resize(image: NSImage, w: Int, h: Int) -> NSImage
{
let destSize = NSMakeSize(CGFloat(w), CGFloat(h))
let newImage = NSImage(size: destSize)
newImage.lockFocus()
image.drawInRect(NSMakeRect(0, 0, destSize.width, destSize.height), fromRect: NSZeroRect, operation: NSCompositingOperation.CompositeCopy, fraction: 1.0)
newImage.unlockFocus()
newImage.size = destSize
return NSImage(data: newImage.TIFFRepresentation!)!
}
You need to pass 3 parameters to call this function i.e NSImage, width, height and this function will return resized image.
targetimage = resize(source, w: Int(targetwidth), h: Int(targetheight))