Am creating an application for image share related things. Here my requirement is I have to store some custom information(Name, PhoneNumber, Price) into the Image Metadata and retrieve it back.
I use UIImagePickerController to capture the image and set my information into the image metadata in UIImagePickerControllerDelegate like below mentioned:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
picker.dismiss(animated: true, completion: nil)
let profileImage = info[UIImagePickerControllerOriginalImage] as? UIImage
let imageData: Data = UIImageJPEGRepresentation(profileImage!, 1)!
let cgImgSource: CGImageSource = CGImageSourceCreateWithData(imageData as CFData, nil)!
let uti: CFString = CGImageSourceGetType(cgImgSource)!
let dataWithExif: NSMutableData = NSMutableData(data: imageData)
let destination: CGImageDestination = CGImageDestinationCreateWithData((dataWithExif as CFMutableData), uti, 1, nil)!
let imageProoperties = CGImageSourceCopyPropertiesAtIndex(cgImgSource, 0, nil)! as NSDictionary
let mutable: NSMutableDictionary = imageProoperties.mutableCopy() as! NSMutableDictionary
let EXIFDictionary: NSMutableDictionary = (mutable[kCGImagePropertyExifDictionary as String] as? NSMutableDictionary)!
print("Before Modification: \(EXIFDictionary)")
EXIFDictionary[kCGImagePropertyExifUserComment as String] = "\(self.m_NameTxtFd.text!):\(self.m_PhoneNumberTxtFd.text!):\(self.m_PriceTxtFd.text!)"
mutable[kCGImagePropertyExifDictionary as String] = EXIFDictionary
CGImageDestinationAddImageFromSource(destination, cgImgSource, 0, (mutable as CFDictionary))
CGImageDestinationFinalize(destination)
let testImage: CIImage = CIImage(data: dataWithExif as Data, options: nil)!
let newProperties: NSDictionary = testImage.properties as NSDictionary
print("After Modification : \(newProperties)") //Here I Got My Information is Stored Successfully
self.m_ImgView.image = self.convert(cmage: testImage)
self.saveImageDocumentDirectory()
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
picker.dismiss(animated: true, completion: nil)
}
Now am going to save the image in NSDocumentDirectory like below mentioned:
func saveImageDocumentDirectory(){
let fileManager = FileManager.default
let paths = (NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString).appendingPathComponent("apple.jpg")
let image = self.m_ImgView.image
print(paths)
let imageData = UIImageJPEGRepresentation(image!, 0.5)
fileManager.createFile(atPath: paths as String, contents: imageData, attributes: nil)
}
Now am going to fetch the stored image in another view controller like below mentioned:
func getImage(){
let fileManager = FileManager.default
let imagePAth = (self.getDirectoryPath() as NSString).appendingPathComponent("apple.jpg")
print(imagePAth)
if fileManager.fileExists(atPath: imagePAth){
self.m_ImgView.image = UIImage(contentsOfFile: imagePAth)
self.fetchImageDetails()
}else{
print("No Image")
}
}
I successfully got the image and now I have to fetch the information from image metadata like below mentioned:
func fetchImageDetails() {
let profileImage = self.m_ImgView.image!
let ciImage: CIImage = CIImage(cgImage: profileImage.cgImage!)
let newProperties: NSDictionary = ciImage.properties as NSDictionary
}
But issue is the information is null in image property.
Please guide me to retrieve the custom information from stored Image.
First create NSMutableDictionary and set value to NSMutableDictionary when you set value to then you don't need to set again to metadata you directly assign to NSMutableDictionary to Metada.
let metadata = info[UIImagePickerControllerMediaMetadata] as? NSMutableDictionary
let exifData = NSMutableDictionary()
let metaStr = "\(self.m_NameTxtFd.text!),\(self.m_PhoneNumberTxtFd.text!),\(self.m_PriceTxtFd.text!)"
exifData.setValue(metaStr, forKey: kCGImagePropertyExifDictionary as String)
metadata = exifData
fileManager.requestImageData(for: fetchResult.object(at: i) as PHAsset, options: requestOptions, resultHandler: { (imagedata, dataUTI, orientation, info ) in
if let info = info {
if info.keys.contains(NSString(string: "PHImageFileURLKey")) {
path = info[NSString(string: "PHImageFileURLKey")] as? NSURL
size = (imagedata! as NSData).length
self.name = PHAssetResource.assetResources(for:fetchResult.object(at: i)).first?.originalFilename
self.imageData = imagedata
}
}
})
Related
I'm new to iOS dev and cannot figure out how to load an image in an imageView from a local directory.
I use imagePickerController to pick an image, get its info, then use this information to display the image in the imageView.
Here is the code to pick the image and its info dictionary:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
let image = info[UIImagePickerControllerOriginalImage] as! UIImage
let imageUrl = info[UIImagePickerControllerReferenceURL] as! NSURL
let imageName = imageUrl.lastPathComponent
let documentDirectory = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first!
let photoURL = NSURL(fileURLWithPath: documentDirectory)
let localPath = photoURL.appendingPathComponent(imageName!)!
imagesList.append(localPath)
picker.dismiss(animated: true, completion: nil)
}
Then, and here is where I'm looking for some help, I want to use either localPath or imageUrl to load the image in another imageView but cannot figure out how.
I tried
func changeImage(_ sender: Any) {
if imagesList.count > 0 {
let imageUrlPath = imagesList[indexList]
let urlString: String = imageUrlPath.absoluteString
imageView.image = UIImage(contentsOfFile: urlString)
indexList = (indexList + 1) % imagesList.count
}
}
But I cannot have something working.
Any idea how I can achieve that?
Thank you for your help.
You'll want to save a reference to PHAsset objects, not URL strings.
Start with defining your Array as:
var imagesList = [PHAsset]()
Then, in didFinishPickingMediaWithInfo:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
dismiss(animated: true)
// get the selected image as a UIImage object
let image = info[UIImagePickerControllerOriginalImage] as! UIImage
imageView.image = image
// save a PHAsset reference in imagesList array for later use
if let imageUrl = info[UIImagePickerControllerReferenceURL] as? URL{
let assets = PHAsset.fetchAssets(withALAssetURLs: [imageUrl], options: nil)
if let p = assets.firstObject {
imagesList.append(p)
}
}
}
Next, add a couple "convenience" functions:
func getAssetFullsize(asset: PHAsset) -> UIImage {
let manager = PHImageManager.default()
let option = PHImageRequestOptions()
var img = UIImage()
option.isSynchronous = true
let w = asset.pixelWidth
let h = asset.pixelHeight
manager.requestImage(for: asset, targetSize: CGSize(width: w, height: h), contentMode: .aspectFit, options: option, resultHandler: {(result, info)->Void in
img = result!
})
return img
}
func getAssetThumbnail(asset: PHAsset) -> UIImage {
let manager = PHImageManager.default()
let option = PHImageRequestOptions()
var thumbnail = UIImage()
option.isSynchronous = true
let w = 100
let h = 100
manager.requestImage(for: asset, targetSize: CGSize(width: w, height: h), contentMode: .aspectFit, options: option, resultHandler: {(result, info)->Void in
thumbnail = result!
})
return thumbnail
}
and finally, when you want to get the actual image:
func changeImage(_ sender: Any) {
if imagesList.count > 0 {
// get the full-size image from PHAsset
imageView.image = getAssetFullsize(asset: imagesList[indexList])
// or, just get a thumbnail-sized image
//imageView.image = getAssetThumbnail(asset: imagesList[indexList])
indexList = (indexList + 1) % imagesList.count
}
}
Naturally, you'll want to add appropriate error-checking, your own sizing, naming, tracking, etc... but I think this is the direction you want to head.
This below code is working perfectly fine for images picked from gallery. But will not work if taken with Camera. I tried to save image into storage and read again, but I was unable to do that. So could any one help me in this? Thank you.
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
if let referenceUrl = info[UIImagePickerControllerReferenceURL] as? NSURL, image = info[UIImagePickerControllerOriginalImage] as? UIImage {
let phAsset = PHAsset.fetchAssetsWithALAssetURLs([referenceUrl], options: nil).lastObject as! PHAsset
PHImageManager.defaultManager().requestImageDataForAsset(phAsset, options: PHImageRequestOptions(), resultHandler: { (imagedata, dataUTI, orientation, info) in
if info!.keys.contains(NSString(string: "PHImageFileURLKey")) {
let path = info![NSString(string: "PHImageFileURLKey")] as! NSURL
print("path q\(path)")
self.mImageUrl = path
self.mlocalPath = path.path
self.mImageExtension = path.pathExtension
self.mImageName = path.lastPathComponent!
print("mImageName q\(self.mImageName)")
}
})
}
dismissViewControllerAnimated(true, completion: nil)
}
Swift 5+
As the previous answers sugested, the image is not stored in gallery yet and hence no imageName. You need to store it in gallery. Use the below Helper class to save and get images from FileManager.
Thanks to this Answer
class CameraImageManager {
static let shared = CameraImageManager()
public func saveImage(imageName: String, image: UIImage) {
guard let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return }
let fileName = imageName
let fileURL = documentsDirectory.appendingPathComponent(fileName)
guard let data = image.jpegData(compressionQuality: 1) else { return }
//Checks if file exists, removes it if so.
if FileManager.default.fileExists(atPath: fileURL.path) {
do {
try FileManager.default.removeItem(atPath: fileURL.path)
print("Removed old image")
} catch let removeError {
print("couldn't remove file at path", removeError)
}
}
do {
try data.write(to: fileURL)
} catch let error {
print("error saving file with error", error)
}
}
public func getImagePathFromDiskWith(fileName: String) -> URL? {
let documentDirectory = FileManager.SearchPathDirectory.documentDirectory
let userDomainMask = FileManager.SearchPathDomainMask.userDomainMask
let paths = NSSearchPathForDirectoriesInDomains(documentDirectory, userDomainMask, true)
if let dirPath = paths.first {
let imageUrl = URL(fileURLWithPath: dirPath).appendingPathComponent(fileName)
return imageUrl
}
return nil
}
public func loadImageFromDiskWith(fileName: String) -> UIImage? {
let documentDirectory = FileManager.SearchPathDirectory.documentDirectory
let userDomainMask = FileManager.SearchPathDomainMask.userDomainMask
let paths = NSSearchPathForDirectoriesInDomains(documentDirectory, userDomainMask, true)
if let dirPath = paths.first {
let imageUrl = URL(fileURLWithPath: dirPath).appendingPathComponent(fileName)
let image = UIImage(contentsOfFile: imageUrl.path)
return image
}
return nil
}
}
Now, in your imagePickerController didFinishPickingMediaWithInfo callback function, this is how you can assign a name to an image and save it.
public func imagePickerController(_ picker: UIImagePickerController,
didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
guard let image = info[.editedImage] as? UIImage else { return }
let imageName = "RDV_" + UUID().uuidString
CameraImageManager.shared.saveImage(imageName: imageName, image: image)
print("IMAGE NAME IS: ", imageName)
}
Hope It Helps.
You can use a notification with addObserver like this
ViewController A : where you want image to be changed, add this in viewDidLoad
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(self.methodOfImageChange(_:)), name:"ImageChanged", object: nil)
Add this method in ViewController A
func methodOfImageChange(notification: NSNotification){
let appStatus = notification.userInfo as? Dictionary<String,AnyObject>
// appStatus contains your image in "image" key
}
Now in didFinishPickingMediaWithInfo add this
let dictionary: [String:AnyObject] = [
"image" : (info[UIImagePickerControllerOriginalImage] as? UIImage)!,
]
NSNotificationCenter.defaultCenter().postNotificationName("ImageChanged", object: self, userInfo: dictionary)
picker .dismissViewControllerAnimated(true, completion: nil)
Hope this helps
The image isn't in the gallery yet, so I don't believe you have a name.
In my app the flow (via navigation controller) is:
Selection VC (choice of Camera or Photo Library) ->
UIImagePickerController ->
Edit VC (with back navigation and action button for - among others - saving to Photo Library)
If the user chooses Camera, they take a picture and the options are "Retake" or "Use Photo". Is they choose "Use Photo", they are in the Edit VC.
If they then choose to go back to the Select VC, the image is nowhere to be found.
I want to display image metadata using UIImagePickerController in Swift.
where the image is been selected from gallery and would be displayed in the imageView along with the meta data such as PixelHeight,PixelWidth,PixelXDimension,PixelYDimension,Coordinates,Size,Date Created and Imagename.
At first, you can get info[UIImagePickerControllerReferenceURL] from UIImagePickerController. Then you can do things like the following:
let assetURL = info[UIImagePickerControllerReferenceURL] as! NSURL
let asset = PHAsset.fetchAssetsWithALAssetURLs([assetURL], options: nil)
guard let result = asset.firstObject where result is PHAsset else {
return
}
let imageManager = PHImageManager.defaultManager()
imageManager.requestImageDataForAsset(result as! PHAsset, options: nil, resultHandler:{
(data, responseString, imageOriet, info) -> Void in
let imageData: NSData = data!
if let imageSource = CGImageSourceCreateWithData(imageData, nil) {
let imageProperties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil)! as NSDictionary
//now you have got meta data in imageProperties, you can display PixelHeight, PixelWidth, etc.
}
})
After i took a photo with the camera i save the image with the following code:
UIImageWriteToSavedPhotosAlbum(image, self,"image:didFinishSavingWithError:contextInfo:", nil)
This saves the image in the camera roll. Additionally i want to save the URL to this saved image in Core Data. Is it possible to retrieve the URL (or the Path) to so that i only need to save this URL and not the full image in Core Data?
After reading a lot of answers written in ObjectivC i finally figured out how to write this in Swift with Xcode 6.2:
ALAssetsLibrary().writeImageToSavedPhotosAlbum(image.CGImage, orientation: ALAssetOrientation(rawValue: image.imageOrientation.rawValue)!,
completionBlock:{ (path:NSURL!, error:NSError!) -> Void in
println("\(path)")
})
Here is my combination..
Saving Image :
let imageData = NSData(data:UIImagePNGRepresentation(pickedimage))
let paths = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)
var docs: String = paths[0] as! String
let fullPath = docs.stringByAppendingPathComponent("yourNameImg.png")
let result = imageData.writeToFile(fullPath, atomically: true)
print(fullPath)
Get Image:
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")
let image = UIImage(contentsOfFile: readPath)
UploadImagePreview.image = image
}
}
}
We can try with Photos Framework to fetch the last saved image.
var fetchOptions: PHFetchOptions = PHFetchOptions()
fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: true)]
var fetchResult = PHAsset.fetchAssetsWithMediaType(PHAssetMediaType.Image, options: fetchOptions)
if (fetchResult.firstObject != nil) {
var lastAsset: PHAsset = fetchResult.lastObject as! PHAsset
PHImageManager.defaultManager().requestImageForAsset(lastAsset, targetSize: self.UploadImagePreview.bounds.size, contentMode: PHImageContentMode.AspectFill, options: PHImageRequestOptions(), resultHandler: { (result, info) -> Void in
self.UploadImagePreview.image = result
})
}
I'm trying to provide a user selection of an image from Photo Library. Thus I'm using UIImagePickerController for selecting. But here comes an issue with getting its initial URL in the file system (I need this for CKAsset).
My code.
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [NSObject : AnyObject]) {
let imageURL = info[UIImagePickerControllerReferenceURL] as NSURL
let path = imageURL.path!
let imageName = path.lastPathComponent
let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
let documentDirectory = paths.first as String!
let localPath = documentDirectory + "/" + imageName
let imageData = NSData(contentsOfFile: localPath)!
let image = UIImage(data: imageData)!
picker.dismissViewControllerAnimated(true, completion: nil)
}
imageURL is kinda cryptic. It describes Asset URL, but not one in File System. And it looks like: assets-library://asset/asset.JPG?id=B6C0A21C-07C3-493D-8B44-3BA4C9981C25&ext=JPG.
According to this logic the path is /asset.JPG where asset.JPG is a name of the image.
Then I'm accessing my Documents folder and trying to find there a file with path:
/Users/Eugene/Library/Developer/CoreSimulator/Devices/3C5E9A23-8220-4B37-BD14-F1E42EEC2C7C/data/Containers/Data/Application/20EBAAE2-6C6F-4651-A48F-16A222CCB3A2/Documents/asset.JPG
Cryptic as well but seems to be a real path for a not existing image... No image with that path can be found. And this makes me sick.
Do I have to save an image from the beginning? Or is there any other way to go?
I've looked through several tutorials using AssetsLibrary API but I didn't find anything useful to solve my problem. Thank you in advance!
Okay, I've solved the issue.
All you have to do is simply grab the image (info[UIImagePickerControllerOriginalImage] as UIImage) and save to the given directory. If you need to save only 1 picture it works great. The code id below.
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [NSObject : AnyObject]) {
let imageURL = info[UIImagePickerControllerReferenceURL] as NSURL
let imageName = imageURL.path!.lastPathComponent
let documentDirectory = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true).first as String
let localPath = documentDirectory.stringByAppendingPathComponent(imageName)
let image = info[UIImagePickerControllerOriginalImage] as UIImage
let data = UIImagePNGRepresentation(image)
data.writeToFile(localPath, atomically: true)
let imageData = NSData(contentsOfFile: localPath)!
let photoURL = NSURL(fileURLWithPath: localPath)
let imageWithData = UIImage(data: imageData)!
picker.dismissViewControllerAnimated(true, completion: nil)
}
In SWIFT 4 u Can Try This, It's working properly.
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let imgUrl = info[UIImagePickerControllerImageURL] as? URL{
let imgName = imgUrl.lastPathComponent
let documentDirectory = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first
let localPath = documentDirectory?.appending(imgName)
let image = info[UIImagePickerControllerOriginalImage] as! UIImage
let data = UIImagePNGRepresentation(image)! as NSData
data.write(toFile: localPath!, atomically: true)
//let imageData = NSData(contentsOfFile: localPath!)!
let photoURL = URL.init(fileURLWithPath: localPath!)//NSURL(fileURLWithPath: localPath!)
print(photoURL)
}
APPDEL.window?.rootViewController?.dismiss(animated: true, completion: nil)
}
For Swift 5+ ;according to #Jaydip answer
if let imgUrl = info[UIImagePickerController.InfoKey.imageURL] as? URL{
let imgName = imgUrl.lastPathComponent
let documentDirectory = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first
let localPath = documentDirectory?.appending(imgName)
let 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)
}
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [NSObject : AnyObject]) {
//this block of code grabs the path of the file
let imageURL = info[UIImagePickerControllerReferenceURL] as NSURL
let imagePath = imageURL.path!
let localPath = NSURL(fileURLWithPath: NSTemporaryDirectory()).URLByAppendingPathComponent(imagePath)
//this block of code adds data to the above path
let path = localPath.relativePath!
let imageName = info[UIImagePickerControllerOriginalImage] as UIImage
let data = UIImagePNGRepresentation(imageName)
data?.writeToFile(imagePath, atomically: true)
//this block grabs the NSURL so you can use it in CKASSET
let photoURL = NSURL(fileURLWithPath: path)
}
check this solution.
import AssetsLibrary
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
self.imagePicker = picker
if let selectedImage = info[UIImagePickerControllerOriginalImage] as? UIImage {
let controller = CropViewController(image: selectedImage )
controller.delegate = self
picker.presentViewController(controller, animated: true, completion: nil)
}
else if let imageUrl = info[UIImagePickerControllerReferenceURL] as? NSURL{
let assetLibrary = ALAssetsLibrary()
assetLibrary.assetForURL(imageUrl , resultBlock: { (asset: ALAsset!) -> Void in
if let actualAsset = asset as ALAsset? {
let assetRep: ALAssetRepresentation = actualAsset.defaultRepresentation()
let iref = assetRep.fullResolutionImage().takeUnretainedValue()
let image = UIImage(CGImage: iref)
let controller = CropViewController(image: image)
controller.delegate = self
picker.presentViewController(controller, animated: true, completion: nil)
}
}, failureBlock: { (error) -> Void in
})
}
}
In swift 4
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let imgUrl = info[UIImagePickerControllerReferenceURL] as? URL{
let imgName = imgUrl.lastPathComponent
let documentDirectory = NSTemporaryDirectory()
let localPath = documentDirectory.appending(imgName)
let image = info[UIImagePickerControllerOriginalImage] as! UIImage
let data = UIImageJPEGRepresentation(image, 0.3)! as NSData
data.write(toFile: localPath, atomically: true)
let photoURL = URL.init(fileURLWithPath: localPath)
}
}
swift 4.2
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
//obtaining saving path
let fileManager = FileManager.default
let documentsPath = fileManager.urls(for: .documentDirectory, in: .userDomainMask).first
let imagePath = documentsPath?.appendingPathComponent("image.jpg")
// extract image from the picker and save it
if let pickedImage = info[UIImagePickerController.InfoKey.originalImage] as? UIImage {
let imageData = pickedImage.jpegData(compressionQuality: 0.75)
try! imageData?.write(to: imagePath!)
}
}
Thanks
let imgUrl = info[UIImagePickerController.InfoKey.imageURL] as? URL