I'm converting the image I'm picking from the gallery into its URL like so...
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let image = info[UIImagePickerControllerOriginalImage] as? UIImage {
UIImageWriteToSavedPhotosAlbum(image, self, #selector(image(_:didFinishSavingWithError:contextInfo:)), nil)
let imageURL = info[UIImagePickerControllerReferenceURL] as? NSURL
let imageName = imageURL?.lastPathComponent
let documentDirectory = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first!
let photoURL = NSURL(fileURLWithPath: documentDirectory)
self.localPath = photoURL.appendingPathComponent(imageName!)
do {
try UIImageJPEGRepresentation(image, 1.0)?.write(to: localPath!)
print("File Saved")
imageArray.append(image)
} catch { //Error }
self.collectionView.reloadData()
} else { //Error here }
self.dismiss(animated: true, completion: nil)
}
Now if I have 2 images, I want to pass them one by one to my API call as a parameter. This I'm doing like so...
for imgURL in imageArray {
let url = "http://myapp.com/vw/images_upload"
let headers = [ "Content-Type":"application/x-www-form-urlencoded"]
let Parameters =
[
"image": imgURL,
"seller_id": id
] as [String : Any]
Alamofire.request(url, method: .post, parameters: Parameters, encoding: URLEncoding.httpBody, headers: headers)
.responseJSON { (response) in
if let httpResponse = response.response {
print("error \(httpResponse.statusCode)")
if httpResponse.statusCode == 200 {
if let result = response.result.value as? [String:Any] {
if result["success"] as! Int == 0 {
print("Something went wrong!")
} else if result["success"] as! Int == 1 {
print("UPLOADED IMAGE SUCCESSFULLY!!")
}}}}}}
But in the parameter, in imgURL, I'm not getting the url of the image. Above I had got the url in the localPath. But I cannot loop through localPath as it gives an error. Also, in the imageArray, I'm passing the image which is not in the url format...it is in this format: <UIImage: 0x60800009f9f0> size {4288, 2848} orientation 0 scale 1.000000...How the url format can be passed into the imageArray, that I'm not able to understand.Could this be the issue..?
Also how can I get the url of the image so that I can pass it into the API call...? Please help...
hi what i understand here from your question is that you are setting an image to an imageview and you want to pass that image's path to an api.
so i have written a function to do the same with a resizing ability which you can avoid or modify according to your needs.
So pass your image picked by the image picker and a default name string (eg:"image1") and you will get the image path/url in return
func storeImage(image:UIImage, fileName:String) -> String {
var resizedImage = image
func storeImage(image:UIImage, fileName:String) -> String {
var resizedImage = image
if (image.size.width > 200) {
let width = 200.0 as CGFloat
let height = image.size.height * width / image.size.width
resizedImage = image.scaleImage(toSize: CGSize(width: width, height: height))!
}
else if (image.size.height > 200) {
let height = 200.0 as CGFloat
let width = image.size.width * height / image.size.height
resizedImage = image.scaleImage(toSize: CGSize(width: width, height: height))!
}
let imageData = NSData(data:UIImagePNGRepresentation(resizedImage)!)
let paths = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)
let docs: String = paths[0]
let fullPath = docs.stringByAppendingPathComponent(path: fileName)
_ = imageData.write(toFile: fullPath, atomically: true)
return fullPath
}
Related
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
}
}
})
I am able select image from gallery and save to UIImageView but when trying of camera i can not able save the image in UIImageView. it calls didFinishPickingMediaWithInfo method but its going inside UIImagePickerControllerOriginalImage if case.
here is the code i used for camera and gallery picker:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let pickedImage = info[UIImagePickerControllerImageURL] as? URL {
if let data : Data = try? Data(contentsOf: pickedImage as URL)
{
print(data.format)
if data.format == "gif" {
let data = try? Data(contentsOf: pickedImage) //make sure your image in this url does exist, otherwise unwrap in a if let check / try-catch
let imageView = UIImage(data: data!)
let width = imageView?.size.width
let height = imageView?.size.height
let url = SaveItemFilemanager.sharedinstance.saveGifimage(data: data!)
addGifImage(url: url!, width: width!, height: height!)
} else {
if let photo = info[UIImagePickerControllerLivePhoto] as? PHLivePhoto {
let assetResources = PHAssetResource.assetResources(for: photo)
let asset = assetResources[1]
let url = SaveItemFilemanager.sharedinstance.saveLiveimage(data: asset)
print(url!)
let frameCount = 16
let delayTime = Float(0.2)
let loopCount = 0
let width = photo.size.width
let height = photo.size.height
let regift : Regift = Regift(sourceFileURL: url!, frameCount: frameCount, delayTime: delayTime, loopCount: loopCount)
addGifImage(url: regift.createGif()!, width: width, height: height)
} else if let normalImage = info[UIImagePickerControllerOriginalImage] as? UIImage {
let width = normalImage.size.width
let height = normalImage.size.height
let url = SaveItemFilemanager.sharedinstance.saveimage(image: normalImage)
addImage(url: url!, width: width, height: height)
} else {
let normalImage = info[UIImagePickerControllerOriginalImage] as? UIImage
let width = normalImage?.size.width
let height = normalImage?.size.height
let url = SaveItemFilemanager.sharedinstance.saveimage(image: normalImage!)
addImage(url: url!, width: width!, height: height!)
}
}
}
}
dismiss(animated: true, completion: nil)
}
func showCamera() {
let imagePicker = UIImagePickerController()
if(UIImagePickerController .isSourceTypeAvailable(.camera))
{
imagePicker.delegate = self
imagePicker.sourceType = .camera
}
present(imagePicker, animated: true, completion: nil)
}
I checked even by keeping break point in didfinishpicking media it calls and dismissed immediately.
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’ve encountered a strange behavior:
An imagePicker returns a PHAsset, and I do the Following and manage to present an imageView with image from the data:
asset.requestContentEditingInput(with: PHContentEditingInputRequestOptions()) { (input, _) in
let url = input?.fullSizeImageURL
let imgV = UIImageView()
let test_url = URL(string: (url?.absoluteString)!)
print("><><><^^^><><>\(test_url)")
//prints: ><><><^^^><><>Optional(file:///var/mobile/Media/DCIM/107APPLE/IMG_7242.JPG)
let data = NSData(contentsOf: test_url! as URL)
imgV.image = UIImage(data: data! as Data)
imgV.backgroundColor = UIColor.cyan
att.imageLocalURL = url?.absoluteString//// saving the string to use in the other class
imgV.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
self.view.addSubview(imgV) /// just to test that the file exists and can produce an image
However when I do the following in another class:
if((NSURL( string: self.attachment.imageLocalURL! ) as URL!).isFileURL)// checking if is Local URL
{
let test_url = URL(string: self.attachment.imageLocalURL!) // reading the value stored from before
print("><><><^^^><><>\(test_url)")
//prints :><><><^^^><><>Optional(file:///var/mobile/Media/DCIM/107APPLE/IMG_7242.JPG)
let data = NSData(contentsOf: test_url! as URL)
imageView.image = UIImage(data: data! as Data)
}
The data is nil! What am I doing wrong, the String for URL is identical in both cases!
PHAsset objects should be accessed via the PHImageManager class. If you want to load the image synchronously I recommend you do something like this:
func getImage(assetUrl: URL) -> UIImage? {
let asset = PHAsset.fetchAssets(withALAssetURLs: [assetUrl], options: nil)
guard let result = asset.firstObject else {
return nil
}
var assetImage: UIImage?
let options = PHImageRequestOptions()
options.isSynchronous = true
PHImageManager.default().requestImage(for: result, targetSize: UIScreen.main.bounds.size, contentMode: PHImageContentMode.aspectFill, options: options) { image, info in
assetImage = image
}
return assetImage
}
You could even write a UIImageView extension to load the image directly from a PHAsset url.
var images:NSMutableArray = NSMutableArray() //hold the fetched images
func fetchPhotos ()
{
images = NSMutableArray()
//totalImageCountNeeded = 3
self.fetchPhotoAtIndexFromEnd(0)
}
func fetchPhotoAtIndexFromEnd(index:Int)
{
let status : PHAuthorizationStatus = PHPhotoLibrary.authorizationStatus()
if status == PHAuthorizationStatus.Authorized
{
let imgManager = PHImageManager.defaultManager()
let requestOptions = PHImageRequestOptions()
requestOptions.synchronous = true
let fetchOptions = PHFetchOptions()
fetchOptions.sortDescriptors = [NSSortDescriptor(key:"creationDate", ascending: true)]
if let fetchResult: PHFetchResult = PHAsset.fetchAssetsWithMediaType(PHAssetMediaType.Image, options: fetchOptions)
{
if fetchResult.count > 0
{
imgManager.requestImageForAsset(fetchResult.objectAtIndex(fetchResult.count - 1 - index) as! PHAsset, targetSize: CGSizeMake(self.img_CollectionL.frame.size.height/3, self.img_CollectionL.frame.size.width/3), contentMode: PHImageContentMode.AspectFill, options: requestOptions, resultHandler: { (image, _) in
//self.images.addObject(image!)
if image != nil
{
self.images.addObject(image!)
}
if index + 1 < fetchResult.count && self.images.count < 20 //self.totalImageCountNeeded
{
self.fetchPhotoAtIndexFromEnd(index + 1)
}
else
{
}
})
self.img_CollectionL.reloadData()
}
}
}
}