create pdf of invisible view controller - swift

i have a ViewController_A with a button_A. this button shows me the ViewController_B. this second view controller has content and a button_B.
i you press the button_b the following code will create a pdf file of the ViewController_B content:
let pdfData = contentVC_B.dataWithPDF(inside: contentVC_B.frame)
let fileURL = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false).appendingPathComponent("test.pdf")
do {
try pdfData.write(to: fileURL, options: .atomic)
} catch {
print(error)
}
This works fine.
But now my question:
i would like to create a pdf file of the ViewController_B content with button_A (from the ViewController_A) without showing the ViewController_B.
is is possible? if yes, how can i realize it?

Get ViewController_B, get contentVC_B and get the pdf data.
let storyBoard = NSStoryboard(name:"Main", bundle:nil)
let viewController_B = storyBoard.instantiateController(withIdentifier:"viewController_B") as! NSViewController
let contentVC_B = viewController_B.view
let pdfData = contentVC_B.dataWithPDF(inside: contentVC_B.frame)

Related

Is there anyway for me to send a PDF and PNGs by text using MFMessageComposeViewController() in Swift?

Whenever I try to use .addAttachmentURL, it does not attach anything. The ViewController is presented with nothing within the body of the text. The URL is a path to the pdf data (I don't know if that makes a difference) in my file defaults. Is there any way I can send a PDF through text like this? I have not found anything by looking through documentation or StackOverflow. Also, I haven't implemented it yet, but I was wondering if there was a way to also attach PNGs to this message I am sending along with the PDF.
func getFileManager() -> NSString {
let filePath = (NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString)
return filePath
}
func displayMessageInterface() {
let composeVC = MFMessageComposeViewController()
composeVC.messageComposeDelegate = self
// Configure the fields of the interface.
composeVC.recipients = ["000000000"]
var url = URL(string: self.getFileManager() as String)!
url.appendPathComponent("my_report.pdf")
composeVC.addAttachmentURL(url, withAlternateFilename:
"this file")
// Present the view controller modally.
if MFMessageComposeViewController.canSendText() {
self.present(composeVC, animated: true, completion: nil)
} else {
print("Can't send messages.")
}
}
You are using the wrong URL initializer. URL(string:) initializer expects a scheme, in this case file://. You need to use URL(fileURLWithPath:) initializer or simply get the document directory URL using FileManager urls method:
extension URL {
static let documentDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
}
let url = URL.documentDirectory.appendingPathComponent("my_report.pdf")
I am not sure what you mean when you say "The URL is a path to the pdf data in my file defaults". If you have included your file in your project Bundle you need to use its url(forResource:) method.
let url = Bundle.main.url(forResource: "my_report", withExtension: "pdf")!

Trying to share a json string in a file with an activity view controller

iOS 11, Swift 4
Trying to use an activity view controller to share a json string I have just created, and I think I am almost there, but struggling to attach a file with the controller. I got this code.
let encoder = JSONEncoder()
if let jsonData = try? encoder.encode(w2GA) {
if let jsonString = String(data: jsonData, encoding: .utf8) {
let documentsDirectoryURL = try! FileManager().url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
let file2ShareURL = documentsDirectoryURL.appendingPathComponent("blah.json")
print(jsonString)
do {
let encodedData = try? JSONEncoder().encode(jsonString)
try encodedData?.write(to: file2ShareURL)
let activityViewController = UIActivityViewController(activityItems: [file2ShareURL], applicationActivities: nil)
activityViewController.popoverPresentationController?.sourceView = self.view
self.present(activityViewController, animated: true, completion: nil)
} catch {
print(error)
}
}
}
I am getting the error message:
file:///var/mobile/Containers/Data/Application/FD6E9F52-405F-4E66-927F-DCB7EDB0BF25/Documents/blah.json
Attachments Error confirming URL is readable
Pretty sure the file is there? is this some sort of race hazard perhaps? If I replace the URL with the jsonString it works! So I get a jsonString looking like this basically.
[{"imageURL":"http://","latitude":46.819945794990176,"name":"Clue 1","longitude":8.2581710034376599,"hint":"Hint"},{"imageURL":"http://","latitude":47.433033706679716,"name":"Clue 2","longitude":8.8540648624925371,"hint":"Hint"},{"imageURL":"http://","latitude":46.785125219263776,"name":"Clue","longitude":9.6534346734197598,"hint":"Hint"}]
Do you need to save this as a file?
Surely the simplest approach to this is to pass the JSON string as a variable?
Example:
let activityViewController = UIActivityViewController(activityItems: [jsonString], applicationActivities: nil)
EDIT
I've just noticed you've already tried this and it works. Apologies.
Ensure the JSONEncoder isn't throwing an exception and that the file exists before you try to pass the url to the UIActivityViewController
You can also try using the UIActivityItemProvider class as documented here
Ok, found the answer which is of course obvious! The file wasn't being created!
I made two changes, firstly I run the entire code block under the main thread, secondly I changed the lines writing out the json string which in the earlier version I encode twice!
DispatchQueue.main.async {
let encoder = JSONEncoder()
if let jsonData = try? encoder.encode(w2GA) {
if let jsonString = String(data: jsonData, encoding: .utf8) {
var documentsDirectoryURL = try! FileManager().url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
let file2ShareURL = documentsDirectoryURL.appendingPathComponent("blah.json")
do {
try jsonString.write(to: file2ShareURL, atomically: false, encoding: .utf8)
} catch {
print(error)
}
do {
let _ = try Data(contentsOf: file2ShareURL)
let activityViewController = UIActivityViewController(activityItems: [file2ShareURL], applicationActivities: nil)
activityViewController.popoverPresentationController?.sourceView = self.view
self.present(activityViewController, animated: true, completion: nil)
} catch {
print(error)
}
}
}
}

Get images from Document Directory not file path Swift 3

This is how I saved the images
let format = DateFormatter()
format.dateFormat="MMMM-dd-yyyy-ss"
let currentFileName = "\(format.string(from: Date())).img"
print(currentFileName)
// Save Images
let fileMgr = FileManager.default
let dirPath = fileMgr.urls(for: .documentDirectory, in: .userDomainMask)[0]
let imageFileUrl = dirPath.appendingPathComponent(currentFileName)
do {
try UIImagePNGRepresentation(returnedImages)!.write(to: imageFileUrl)
print("Image Added Successfully")
} catch {
print(error)
}
Below is code I am using to retrieve images, But I am getting the URL instead of the image file to populate tableview. Any help would be appreciated
let fileManager = FileManager.default
let imageUrl = fileManager.urls(for: .documentDirectory, in: .userDomainMask) [0].appendingPathComponent("img")
print("Your Images:\(imageUrl)")
It's simply because your image's name is invalid. Use the debugger to find the exact value of imageUrl, I bet it's something like this .../Documents/img. What you want is more like .../Documents/Sep-04-2017-12.img
You'd have to store currentFileName in the view controller so you can reference it later.
Also, your naming strategy is pretty fragile. Many images can end up sharing one name.
If you have a folder full of images, you can iterate on that folder to get back the img files:
let fileManager = FileManager.default
let documentDirectory = fileManager.urls(for: .documentDirectory, in: .userDomainMask)[0]
let directoryContents = try! fileManager.contentsOfDirectory(at: documentDirectory, includingPropertiesForKeys: nil)
for imageURL in directoryContents where imageURL.pathExtension == "img" {
if let image = UIImage(contentsOfFile; imageURL.path) {
// now do something with your image
} else {
fatalError("Can't create image from file \(imageURL)")
}
}
Try using this
func getImage(){
let fileManager = FileManager.default
let imagePAth = (self.getDirectoryPath() as NSString).appendingPathComponent("apple.jpg") // saved image name apple.jpg
if fileManager.fileExists(atPath: imagePAth){
self.lockbackImageview.image = UIImage(contentsOfFile: imagePAth)
}else{
print("No Image")
self.lockbackImageview.image = UIImage.init(named: "1.jpg")
}
}

How to share Image in Swift

I tried to share a image that I generate by my own. However when I tried to share the image it doesn't works well.
here is the code to share
func shareQR(){
//mainImage is the view that hold the image I want to share
let tempImage = view.mainImage.image
let imageToShare = [ tempImage ]
let activityViewController = UIActivityViewController(activityItems: imageToShare as! [UIImage], applicationActivities: nil)
activityViewController.popoverPresentationController?.sourceView = self.view
activityViewController.excludedActivityTypes = [ UIActivityType.airDrop ]
self.present(activityViewController, animated: true, completion: nil)
}
So I tried to debug and the result is my tempImage value is the same with the one I want to share. And then I tried to hardcode the image and become let tempImage = UIImage(named: "image.png")
and tap share button, and it works perfectly.
So I figured out, did I have to save my image to local file first and then called it ?
If yes how ? I tried use this code but failed.
// Create path.
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
let filePath = "\(paths[0])/temp.png"
// Save image.
UIImagePNGRepresentation(image!)?.write(to: filePath)
the error is : cannot convert value of type 'String' to expected
argument type 'URL' in this line
UIImagePNGRepresentation(tempImage!)?.write(to: filePath)
Or maybe I dont need to save image? how ?
Thank you
It seems like your variable image is a String variable instead of a UIImage (hence the error that you have posted). To confirm this theory, add the following line in your code
print(tempImage)
after
let tempImage = view.mainImageimage
If it prints the image name, then your variable is a String variable. If it prints something along the lines of UIImage, then it's an actual image and we can further investigate the issue. Let me know what you get in result
Edit:
To store a file locally, use the following code
if let data = UIImagePNGRepresentation(tempImage) {
let filename = getDocumentsDirectory().appendingPathComponent("copy.png")
try? data.write(to: filename)
}
func getDocumentsDirectory() -> URL {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let documentsDirectory = paths[0]
return documentsDirectory
}

UIDocumentInteractionController file attachment error

so I'm working on exporting a .txt file from Xcode, but whenever I try to export it, say through email, it creates an email with no attachments and an empty message. When I try to export it to iCloud Drive, a white screen comes up for a second, then leaves. When I check iCloud Drive, the file isn't there. What is wrong here?
let message = testLabel.text
func getDocumentsDirectory() -> NSString {
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
let documentsDirectory = paths[0]
return documentsDirectory as NSString
}
let filePath = getDocumentsDirectory().appendingPathComponent("matrixFile.txt")
do{
try message?.write(toFile: filePath, atomically: true, encoding: String.Encoding.utf8)
}catch let error as NSError{
testLabel.text = String(describing: error)
}
let documentInteractionController = UIDocumentInteractionController()
documentInteractionController.url = NSURL.fileURL(withPath: filePath)
documentInteractionController.uti = "public.data, public.content"
documentInteractionController.name = "matrixFile"
documentInteractionController.presentOptionsMenu(from: view.frame, in: view, animated: true)
The problem is you are declaring your document interaction controller as a constant within the method that calls it, like:
func someButton() {
let controller = UIDocumentInteractionController...
}
It will not work like that. The interaction controller needs to be an instance variable of the class that presents it, and it should be reinitialized every time you present it with a new url, like so:
var controller: UIDocumentInteractionController!
func someButton() {
controller = UIDocumentInteractionController(url: someURL)
controller.presentOptionsMenu...
}
Why? I have no idea, but file a bug report if you think this is absurd.
Your UTI is wrong. For a text file you should use "public.text". But there is a constant for this already - kUTTypePlainText. You just need to import MobileCoreServices to use it.
import MobileCoreServices
then:
documentInteractionController.uti = kUTTypePlainText as String
You should also use the proper initializer when creating the controller:
let documentInteractionController = UIDocumentInteractionController(url: URL(fileURLWithPath: filePath))
documentInteractionController.uti = kUTTypePlainText as String
documentInteractionController.name = "matrixFile"
documentInteractionController.presentOptionsMenu(from: view.frame, in: view, animated: true)
And I would only create and show the controller if the text isn't nil and you successfully write the file:
if let message = testLabel.text {
let filePath = getDocumentsDirectory().appendingPathComponent("matrixFile.txt")
do {
try message.write(toFile: filePath, atomically: true, encoding: String.Encoding.utf8)
let documentInteractionController = UIDocumentInteractionController(url: URL(fileURLWithPath: filePath))
documentInteractionController.uti = kUTTypePlainText as String
documentInteractionController.name = "matrixFile"
documentInteractionController.presentOptionsMenu(from: view.frame, in: view, animated: true)
} catch let error as NSError {
testLabel.text = String(describing: error)
}
}