Annotating PDF file and saving in swift - swift

In my iOS app using swift, I annotated the pdf field and saved in the document directory. The view correctly display annotated field and the file is saved with annotation in document directory, however in the debugging area I am getting messages. The last method for two run was Ok but then also giving error message although displayed file and saved file in doc directory was fine. Any idea?
2020-02-14 21:51:23.245079-0800 PDFSaving[4092:1084625] [Unknown process name] Failed to load /System/Library/PrivateFrameworks/CorePDF.framework/Versions/A/CorePDF
2020-02-14 21:51:23.262963-0800 PDFSaving[4092:1084625] Error: Attempting to save dictionary with key: <CGPDFNameRef (/Encoding)>. Dictionary keys must be of type string.
2020-02-14 21:51:23.263062-0800 PDFSaving[4092:1084625] Error: Attempting to save dictionary with key: <CGPDFNameRef (/Font)>. Dictionary keys must be of type string.
2020-02-14 21:51:23.263113-0800 PDFSaving[4092:1084625] Error: Could not create dictionary value for key: /DR. Invalid value.
2020-02-14 21:51:23.263161-0800 PDFSaving[4092:1084625] Error: Cannot save value for annotation key: /DR. Invalid type.
I have used various techniques to save the pdf file but all are giving same message in the debugging area`
// 1st method of deleting and saving file
// File saving with errors in debugging area
let path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
let fileNameWithPath = "\(path)/editedFile.pdf"
if FileManager.default.fileExists(atPath: getFilePath()){
do{
try FileManager.default.removeItem(atPath: getFilePath())
print("File path for deleted file: \(path)")
print("File is deleted successfully, path & filename of deleted file: \(fileNameWithPath)")
}catch{
print("error while deleting item from docDir :: \(error.localizedDescription)")
}
}
if let data = pdfDocument.dataRepresentation(){
let url = URL(fileURLWithPath: fileNameWithPath)
do{
try data.write(to: url)
print("pdf saved successfully \(fileNameWithPath)")
}catch{
print("error while saving file \(error.localizedDescription)")
}
}
// 2nd method of deleting and saving file
// File saving with errors in debugging area
let path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
let fileNameWithPath = "\(path)/editedFile.pdf"
if FileManager.default.fileExists(atPath: getFilePath()){
do{
try FileManager.default.removeItem(atPath: getFilePath())
print("File path for deleted file: \(path)")
print("File is deleted successfully, path & filename of deleted file: \(fileNameWithPath)")
}catch{
print("error while deleting item from docDir :: \(error.localizedDescription)")
}
}
guard let url = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first,
let data = pdfView.document?.dataRepresentation() else {return}
let fileURL = url.appendingPathComponent(filename)
do {
try data.write(to: fileURL)
print("File path of saved file : \(path)")
print("pdf saved successfully, path and filename of saved file: \(fileNameWithPath)")
} catch {
print("error while saving file \(error.localizedDescription)")
}
// 3rd method of deleting and saving file
// Blank file is saving without any error in debugging area
let bundlePath = Bundle.main.path(forResource: "QW484A_2017R8", ofType: ".pdf")
let destPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first!
let fileManager = FileManager.default
let fullDestPath = URL(fileURLWithPath: destPath).appendingPathComponent("editedFile.pdf")
if fileManager.fileExists(atPath: fullDestPath.path){
do {
try fileManager.removeItem(at: fullDestPath)
print("File path for removed file: \(destPath)")
print("File path & filename of file removed: \(fullDestPath)")
}
catch{
print("error while removing modified file: \(error.localizedDescription)")
}
}
do{
try fileManager.copyItem(atPath: bundlePath!, toPath: fullDestPath.path)
print("File path of saved file : \(destPath)")
print("database saved successfully, path and filename of saved file: \(fullDestPath.path)")
}catch{
print("error while saving modified file: \(error.localizedDescription)")
}
// 4th method of deleting and saving
// File saving with errors in debugging area
let destPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first!
let fileManager = FileManager.default
let fullDestPath = URL(fileURLWithPath: destPath).appendingPathComponent("editedFile.pdf")
if fileManager.fileExists(atPath: fullDestPath.path){
do {
try fileManager.removeItem(at: fullDestPath)
print("File path for removed file: \(destPath)")
print("File path & filename of file removed: \(fullDestPath)")
}
catch{
print("error while removing modified file: \(error.localizedDescription)")
}
}
self.pdfDocument.write(to: fullDestPath)
print("The save filed path and name: \(fullDestPath)")
// 5th method of saving
// File saving with errors in debugging area
guard let url2 = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first,
let data = pdfView.document?.dataRepresentation() else {return}
let fileURL = url2.appendingPathComponent("editedfile.pdf")
do {
try data.write(to: fileURL)
print("print path: \(fileURL)")
} catch {
print(error.localizedDescription)
}
// 6th method
let destPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first!
let fileManager = FileManager.default
let fullDestPath = URL(fileURLWithPath: destPath).appendingPathComponent("editedFile.pdf")
if fileManager.fileExists(atPath: fullDestPath.path){
do {
try fileManager.removeItem(at: fullDestPath)
print("File path for removed file: \(destPath)")
print("File path & filename of file removed: \(fullDestPath)")
}
catch{
print("error while removing modified file: \(error.localizedDescription)")
}
}
self.pdfView.document?.write(to: fullDestPath)
print("The save filed path and name: \(fullDestPath)")
`

So finally I work around this issue. I thought to update as it may be hurting others. There two methods used for PDF form generation, ist form was created in word and than transferred to PDF with annotations, in 2nd method PDF form was generated using Acro Form, both were giving above problem. In 3rd attempt I created the the PDF form using Adobe Acrobat DC from scratch and tried, this time no problem in saving the PDF with annotations, seems this is the issue with format transformation

Related

Unable to save multiple text files in same folder (MacOS Swift Application)

I am trying to save multiple text files in the same folder. So far I can save one text file into a generated folder in my document directory, but I cannot save more than one text file in that same folder.
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
let documentsDirectory = paths[0]
let docURL = URL(string: documentsDirectory)!
let dataPath = docURL.appendingPathComponent("User_Notes")
// this is the folder name
if !FileManager.default.fileExists(atPath: dataPath.path) {
do {
try
FileManager.default.createDirectory(atPath: dataPath.path, withIntermediateDirectories: true, attributes: nil)
// try stringToWrite.write(to: &dataPath)
try stringToWrite.write(toFile: "\(dataPath)/\(userNotes)).txt", atomically: true, encoding: String.Encoding.utf8)
} catch {
print(error.localizedDescription)
}
}
if error != nil {
print("Error saving user data.")
}
}

How do I solve the strange "filehandle" problem? [duplicate]

I know there are a few questions pertaining to this, but they're in Objective-C.
How can I access a .txt file included in my app using Swift on an actual iPhone? I want to be able to read and write from it. Here are my project files if you want to take a look. I'm happy to add details if necessary.
Simply by searching in the app bundle for the resource
var filePath = NSBundle.mainBundle().URLForResource("file", withExtension: "txt")
However you can't write to it because it is in the app resources directory and you have to create it in the document directory to write to it
var documentsDirectory: NSURL?
var fileURL: NSURL?
documentsDirectory = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).last!
fileURL = documentsDirectory!.URLByAppendingPathComponent("file.txt")
if (fileURL!.checkResourceIsReachableAndReturnError(nil)) {
print("file exist")
}else{
print("file doesnt exist")
NSData().writeToURL(fileURL!,atomically:true)
}
now you can access it from fileURL
EDIT - 28 August 2018
This is how to do it in Swift 4.2
var filePath = Bundle.main.url(forResource: "file", withExtension: "txt")
To create it in the document directory
if let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last {
let fileURL = documentsDirectory.appendingPathComponent("file.txt")
do {
if try fileURL.checkResourceIsReachable() {
print("file exist")
} else {
print("file doesnt exist")
do {
try Data().write(to: fileURL)
} catch {
print("an error happened while creating the file")
}
}
} catch {
print("an error happened while checking for the file")
}
}
Swift 3, based on Karim’s answer.
Reading
You can read files included in an app’s bundle through the bundle’s resource:
let fileURL = Bundle.main.url(forResource:"filename", withExtension: "txt")
Writing
However, you can’t write there. You will need to create a copy, preferably in the Documents directory:
func makeWritableCopy(named destFileName: String, ofResourceFile originalFileName: String) throws -> URL {
// Get Documents directory in app bundle
guard let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last else {
fatalError("No document directory found in application bundle.")
}
// Get URL for dest file (in Documents directory)
let writableFileURL = documentsDirectory.appendingPathComponent(destFileName)
// If dest file doesn’t exist yet
if (try? writableFileURL.checkResourceIsReachable()) == nil {
// Get original (unwritable) file’s URL
guard let originalFileURL = Bundle.main.url(forResource: originalFileName, withExtension: nil) else {
fatalError("Cannot find original file “\(originalFileName)” in application bundle’s resources.")
}
// Get original file’s contents
let originalContents = try Data(contentsOf: originalFileURL)
// Write original file’s contents to dest file
try originalContents.write(to: writableFileURL, options: .atomic)
print("Made a writable copy of file “\(originalFileName)” in “\(documentsDirectory)\\\(destFileName)”.")
} else { // Dest file already exists
// Print dest file contents
let contents = try String(contentsOf: writableFileURL, encoding: String.Encoding.utf8)
print("File “\(destFileName)” already exists in “\(documentsDirectory)”.\nContents:\n\(contents)")
}
// Return dest file URL
return writableFileURL
}
Example usage:
let stuffFileURL = try makeWritableCopy(named: "Stuff.txt", ofResourceFile: "Stuff.txt")
try "New contents".write(to: stuffFileURL, atomically: true, encoding: String.Encoding.utf8)
Just a quick update for using this code with Swift 4:
Bundle.main.url(forResource:"YourFile", withExtension: "FileExtension")
And the following has been updated to account for writing the file out:
var myData: Data!
func checkFile() {
if let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last {
let fileURL = documentsDirectory.appendingPathComponent("YourFile.extension")
do {
let fileExists = try fileURL.checkResourceIsReachable()
if fileExists {
print("File exists")
} else {
print("File does not exist, create it")
writeFile(fileURL: fileURL)
}
} catch {
print(error.localizedDescription)
}
}
}
func writeFile(fileURL: URL) {
do {
try myData.write(to: fileURL)
} catch {
print(error.localizedDescription)
}
}
This particular example is not the most flexible, but with a little bit of work you can easily pass in your own file names, extensions and data values.
🎁 Property Wrapper - Fetch and convert to correct data type
This simple wrapper helps you to load any file from any bundle in a cleanest way:
#propertyWrapper struct BundleFile<DataType> {
let name: String
let type: String
let fileManager: FileManager = .default
let bundle: Bundle = .main
let decoder: (Data) -> DataType
var wrappedValue: DataType {
guard let path = bundle.path(forResource: name, ofType: type) else { fatalError("Resource not found: \(name).\(type)") }
guard let data = fileManager.contents(atPath: path) else { fatalError("Can not load file at: \(path)") }
return decoder(data)
}
}
Usage:
#BundleFile(name: "avatar", type: "jpg", decoder: { UIImage(data: $0)! } )
var avatar: UIImage
You can define any decoder to match your needs
Get File From Bundle in Swift 5.1
//For Video File
let stringPath = Bundle.main.path(forResource: "(Your video file name)", ofType: "mov")
let urlVideo = Bundle.main.url(forResource: "Your video file name", withExtension: "mov")
Bundles are read only. You can use NSBundle.mainBundle().pathForResource to access the file as read-only, but for read-write access you need to copy your document to Documents folder or tmp folder.
Bundles can be written. You can use Bundle.main.path to overwrite file by adding it into Copy Bundles Resource.
I have to use a file from another bundle. So, following code worked for me. Needful when you work with a frameworks.
let bundle = Bundle(for: ViewController.self)
let fileName = bundle.path(forResource: "fileName", ofType: "json")

How to save video data to document directory in swift?

I want to save video data to document directory.
I know how to create document directory my folder.
But how to save data that document directory??
let fileManager = FileManager.default
if let tDocumentDirectory = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first {
let filePath = tDocumentDirectory.appendingPathComponent("\(FOLDER_NAME)")
if !fileManager.fileExists(atPath: filePath.path) {
do {
try fileManager.createDirectory(atPath: filePath.path, withIntermediateDirectories: true, attributes: nil)
} catch {
print("Couldn't create document directory")
}
}
print("Document directory is \(filePath)")
}
Now, I have (FOLDER_NAME) folder. But How to save video data to (FOLDER_NAME) folder??
And How to I get saved video file path?
I apologize for my stupidity.
In your Info.plist, add the following permissions:
Supports opening documents in place: YES
Application supports iTunes file sharing: YES
let videoFilename = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] + "/" + getFileName() //return your filename from the getFileName function
videoNSData.write(toFile: videoFilename, atomically: true)
Then, inside Files, you can get a folder named with your app name, where you can access your saved video file (with the specified filename).

How To Get This To Save To Where My App Is Located

Save data to file
let fileName = "Test"
let DocumentDirURL = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
let fileURL = DocumentDirURL.appendingPathComponent(fileName).appendingPathExtension("txt")
print("FilePath: \(fileURL.path)")
let writeString = "Write this text to the fileURL as text in iOS using Swift"
do {
// Write to the file
try writeString.write(to: fileURL, atomically: true, encoding: String.Encoding.utf8)
} catch let error as NSError {
print("Failed writing to URL: \(fileURL), Error: " + error.localizedDescription)
}
var readString = "" // Used to store the file contents
do {
// Read the file contents
readString = try String(contentsOf: fileURL)
} catch let error as NSError {
print("Failed reading from URL: \(fileURL), Error: " + error.localizedDescription)
}
print("File Text: \(readString)")
How can I get this to save the Test.txt file to save where my App directory is. I don't know where this is saving the Text File to.

Can't save a file in a Documents directory in macOS

I created a function to save a data.txt file in ~/Documents directory.
But it doesn't save a file at all.
func SaveFile(){
print("save file")
let file_name = "data.txt"
let text = "12345"
let fm = FileManager.default
do {
let docsurl = try! fm.url(for: .documentDirectory, in: .userDomainMask, appropriateFor:nil, create:false)
let fileURL = docsurl.appendingPathComponent(file_name)
try text.write( to: fileURL, atomically: false, encoding: String.Encoding.utf8 )
} catch {
print("error: \(error)")
}
}
In the output area there is only text save file.
What am I doing wrong?