UIImage content of file unexpectedly found nil - ios

I am trying to load an image that I have saved inside Document directory. If I print the path I can see that there is the image however, when I trie to assign the path to a UIImage the app crashes:
static func callSavedProfileImage() -> UIImage{
//let profilePictureUser = NSUserDefaults.standardUserDefaults()
let nsDocumentDirectory = NSSearchPathDirectory.DocumentDirectory
let nsUserDomainMask = NSSearchPathDomainMask.UserDomainMask
let paths = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory, nsUserDomainMask, true)
var newImage = UIImage!()
if paths.count > 0
{
let dirPath = paths[0]
let readPath = (dirPath as NSString).stringByAppendingPathComponent("ProfilePic.png")
print(readPath) ///var/mobile/Containers/Data/Application/C9F738C1-F747-4C1D-ADBE-251F168444D4/Documents/ProfilePic.png
let savedProfilePicture = readPath
if let savedImage = UIImage(contentsOfFile: savedProfilePicture) {
newImage = savedImage
}
}
print(newImage)
return newImage
}
Any idea why?

var newImage = UIImage!()
should be
var newImage = UIImage()
When you declare UIImage!() it creates an implicitly unwrapped Optional which will crash if unwrapped while nil.
Just remove the ! to create a normal UIImage, then it won't crash if the image can't be found.

Related

how to get the file name from image path

i am trying to get the file name from image pathurl
but i am getting an error like "Cannot convert value of type 'URL' to type 'NSString' in coercion"can anyone help me to convert as NSstring .Thanks in advance
if var imgUrl = info[UIImagePickerController.InfoKey.imageURL] as? URL{
let imgName = imgUrl.lastPathComponent
let documentDirectory = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first
let localPath = documentDirectory?.appending(imgName)
var image = info[UIImagePickerController.InfoKey.originalImage] as! UIImage
let data = image.pngData()! as NSData
data.write(toFile: localPath!, atomically: true)
//let imageData = NSData(contentsOfFile: localPath!)!
let photoURL = URL.init(fileURLWithPath: localPath!)//NSURL(fileURLWithPath: localPath!)
print(photoURL)
let filename = (photoURL as NSString).lastPathComponent
// pdfURL is your file url
let fileExtention = (filename as NSString).pathExtension // get your file extension
let pathPrefix = (filename as NSString).deletingPathExtension
img.image = image
(In Swift) all methods for path manipulation are in the URL struct. No conversion needed
let filename = photoURL.lastPathComponent
// pdfURL is your file url
let fileExtention = photoURL.pathExtension // get your file extension
let pathPrefix = photoURL.deletingPathExtension.lastPathComponent
img.image = image
And don't use NS classes in Swift at all if there is a native equivalent.
And please consider warnings like
Variable 'image' was never mutated; consider changing to 'let' constant

Swift 3 - Save image alternative

I need to found an alternative of this method to save images
let save = UserDefaults.standard
let imageData = UIImageJPEGRepresentation(Photo.image!, 1.0)
save.set(imageData, forKey: "Image")
save.synchronize()
if let imgData = save.object(forKey: "Image"){
let compressedJPGImage = UIImage(data: imgData as! Data)
}
and load images
let imgData = save.object(forKey: "Image")
let compressedJPGImage = UIImage(data: imgData as! Data)
Photo.image = compressedJPGImage
The problem with this method is that i have a lot of another value saved with UserDefaults.standard so it take a lot of time (5-10 minutes) when i synchronize.
It is not advisable to save large files like images to UserDefaults. UserDefaults was intended to save very small data such as a user's preferred theme color of your app. Perhaps a suitable alternative is to save your images in the document directory. Here is a function that will allow you save an image:
func saveImage(image: UIImage) -> String {
let imageData = NSData(data: UIImagePNGRepresentation(image)!)
let paths = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)
let docs = paths[0] as NSString
let uuid = NSUUID().uuidString + ".png"
let fullPath = docs.appendingPathComponent(uuid)
_ = imageData.write(toFile: fullPath, atomically: true)
return uuid
}
The above function will create the name of the saved image for you. If you prefer to specify the name of the image you are saving then you could do the following (but you will be responsible for ensuring the image names you specify are unique):
func saveImage(image: UIImage, withName name: String) {
let imageData = NSData(data: UIImagePNGRepresentation(image)!)
let paths = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)
let docs = paths[0] as NSString
let name = name
let fullPath = docs.appendingPathComponent(name)
_ = imageData.write(toFile: fullPath, atomically: true)
}
To retrieve those images, you could pass the image name to this function:
func getImage(imageName: String) -> UIImage? {
var savedImage: UIImage?
if let imagePath = getFilePath(fileName: imageName) {
savedImage = UIImage(contentsOfFile: imagePath)
}
else {
savedImage = nil
}
return savedImage
}
Which relies on this function to work:
func getFilePath(fileName: String) -> String? {
let nsDocumentDirectory = FileManager.SearchPathDirectory.documentDirectory
let nsUserDomainMask = FileManager.SearchPathDomainMask.userDomainMask
var filePath: String?
let paths = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory, nsUserDomainMask, true)
if paths.count > 0 {
let dirPath = paths[0] as NSString
filePath = dirPath.appendingPathComponent(fileName)
}
else {
filePath = nil
}
return filePath
}
Here is an example of how you would now save your images instead of UserDefaults. I am saving an image I will call "Image":
saveImage(image: Photo.image, withName name: "Image")
Here is an example of how I would retrieve the saved image:
if let theSavedImage = getImage(imageName: "Image") {
//I got the image
}
UserDefaults is a place to store a small portion of data like user preferences. UserDefaults has very limited space and can be quite slow. In your case, you mentioned it's 5-10 minutes which I doubt though.
If you want images to be stored across the sessions of the app (persistent storage), you should consider using file system (Application_Folder/Library/Cache/) or Core Data framework. You will get better performance here while accessing the image.
If images are not needed to be persisted and need to be stored for a single session of the app, you should use the imageNamed: API of UIImage class. This API loads the image once in the memory and keeps it in the system cache. For all the successive accesses it refers to the cached image only. This will increase the system cache size and application's memory footprint if you are loading too many images. Another API is imageWithContentsOfFile:. Unlike the first API, this API will always load the new image instance in memory. Memory will be deallocated once image instance is released which is not the case with the first API.

Unable to convert CIImage to UIImage in Swift 3.0

I am making image form QR Code by using following code:
func createQRFromString(str: String) -> CIImage? {
let stringData = str.dataUsingEncoding(NSUTF8StringEncoding)
let filter = CIFilter(name: "CIQRCodeGenerator")
filter?.setValue(stringData, forKey: "inputMessage")
filter?.setValue("H", forKey: "inputCorrectionLevel")
return filter?.outputImage
}
And Then I am adding to UIImageView Like this:
if let img = createQRFromString(strQRData) {
let somImage = UIImage(CIImage: img, scale: 1.0, orientation: UIImageOrientation.Down)
imgviewQRcode.image = somImage
}
Now I need to save this to a JPEG or PNG file. But when I am doing so my app crashes:
#IBAction func btnSave(sender: AnyObject) {
// // Define the specific path, image name
let documentsDirectoryURL = try! NSFileManager().URLForDirectory(.DocumentDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: true)
// create a name for your image
let fileURL = documentsDirectoryURL.URLByAppendingPathComponent("image.jpg")
if let image = imgviewQRcode.image // imgviewQRcode is UIImageView
{
if let path = fileURL?.path
{
if !NSFileManager.defaultManager().fileExistsAtPath(fileURL!.path!)
{
if UIImageJPEGRepresentation(image, 1.0)!.writeToFile(path, atomically: true)
{
print("file saved")
}
}//Checking existing file
}//Checking path
}//CHecking image
}
Crash Point
UIImageJPEGRepresentation(image, 1.0)!.writeToFile(path, atomically: true)
Reason
fatal error: unexpectedly found nil while unwrapping an Optional value
Debug Tests:
func convert(cmage:CIImage) -> UIImage
{
let context:CIContext = CIContext.init(options: nil)
let cgImage:CGImage = context.createCGImage(cmage, from: cmage.extent)!
let image:UIImage = UIImage.init(cgImage: cgImage)
return image
}
Use this function to convert CIImage to UIImage . It works .
func convert(image:CIImage) -> UIImage
{
let image:UIImage = UIImage.init(ciImage: image)
return image
}
Perhaps, this was unavailable before, but it is now possible to create UIImages directly from CIImage.
My final code
func generateQRCode(from string: String) -> UIImage? {
let data = string.data(using: String.Encoding.ascii)
if let filter = CIFilter(name: "CIQRCodeGenerator") {
filter.setValue(data, forKey: "inputMessage")
let transform = CGAffineTransform(scaleX: 3, y: 3)
if let output = filter.outputImage?.transformed(by: transform) {
let context:CIContext = CIContext.init(options: nil)
let cgImage:CGImage = context.createCGImage(output, from: output.extent)!
let image:UIImage = UIImage.init(cgImage: cgImage)
return image
}
}
return nil
}

writeToFile in documents directory not updating until I restart the app

I am using the documents directory of my application to cache images locally, but when I go to access them, they are not updated until I close the app and reopen.
Here is my save:
var readPath = ""
let nsDocumentDirectory = NSSearchPathDirectory.DocumentDirectory
let nsUserDomainMask = NSSearchPathDomainMask.UserDomainMask
if let paths = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory, nsUserDomainMask, true) {
if paths.count > 0 {
if let dirPath = paths[0] as? String {
readPath = dirPath.stringByAppendingPathComponent("\(user).png")
UIImagePNGRepresentation(imageView.image).writeToFile(readPath, atomically: true)
}
}
}
Here is my retrieval:
var readPath = ""
let nsDocumentDirectory = NSSearchPathDirectory.DocumentDirectory
let nsUserDomainMask = NSSearchPathDomainMask.UserDomainMask
if let paths = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory, nsUserDomainMask, true) {
if paths.count > 0 {
if let dirPath = paths[0] as? String {
readPath = dirPath.stringByAppendingPathComponent("\(user).png")
//UIImagePNGRepresentation(imageView.image).writeToFile(readPath, atomically: true)
}
}
}
let cachedImage = UIImage(named: readPath)
if (cachedImage != nil)
{
println("cached")
self.userPictures.append(cachedImage!)
}
For some reason though, it is not until I have reset the application that these resources become available.
Can anyone shed some light on why this could be?
The image that gets returned to cachedImage is an image that I had previously saved into that specific path btw
This may helps you....
let fileManager = NSFileManager.defaultManager()
var paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as! String
var getImagePath = paths.stringByAppendingPathComponent("\(fileName).png")
if (fileManager.fileExistsAtPath(getImagePath))
{
println("FILE AVAILABLE");
//Pick Image and Use accordingly
var imageis: UIImage = UIImage(contentsOfFile: getImagePath)!
self.image = imageis // UIImageView Class
let datas: NSData = UIImagePNGRepresentation(imageis)
}
else
{
println("FILE NOT AVAILABLE");
let getImage = UIImage(data: self.data)
self.image = getImage
var filePathToWrite = "\(paths)/\(fileName).png"
var imageData: NSData = UIImagePNGRepresentation(self.image)
fileManager.createFileAtPath(filePathToWrite, contents: imageData, attributes: nil)
}
Check the Project in Github

How to get URL of image of Image Gallery iOS Swift?

I am coding as below for UIImagePickerController to get image from the photo library.
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.PhotoLibrary) {
// Code here
var imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = UIImagePickerControllerSourceType.PhotoLibrary;
imagePicker.mediaTypes = [kUTTypeImage]
imagePicker.allowsEditing = false
self.presentViewController(imagePicker, animated: true, completion: nil)
}
After selecting an image, I can show it on UIImageView, but I cannot get it's URL.
This is code I wrote to get it.
let url: NSString = info[UIImagePickerControllerReferenceURL] as NSString
var imageName:String = url.lastPathComponent
println("URL is \(imageName)")
let image = info[UIImagePickerControllerOriginalImage] as UIImage
profileImage.image = image
self.dismissViewControllerAnimated(true, completion: nil)
Here it gives nil and if I use UIImagePickerControllerEditedImage, it also crashes.
Can't we access URL directly, if not what is UIImagePickerControllerReferenceURL supposed to return?
How can I get the URL of the image so it could be sent to the server.
Thanks
let nsDocumentDirectory = NSSearchPathDirectory.DocumentDirectory
let nsUserDomainMask = NSSearchPathDomainMask.UserDomainMask
if let paths = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory, nsUserDomainMask, true) {
if paths.count > 0 {
if let dirPath = paths[0] as? String {
let readPath = dirPath.stringByAppendingPathComponent("yourNameImg.png")
var pickedimage = UIImage(CGImage: UIImage(contentsOfFile: readPath)!.CGImage, scale: 1.0, orientation: .Up)
UploadImagePreview.image = pickedimage
}
}
}
Note: We can set the image from url if the complete address is known. Here we are searching for the given image name in nsDocumentDirectory , finds out the complete image path and then set to image view.

Resources