I am working with images for the first time and I have been able to select an image and display it on the page. My question is how can I get the name of the image selected ? I been searching around but have not been able to find it . This code below fires every time you select an image
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any])
{
photoImageView.image = info[UIImagePickerControllerOriginalImage] as? UIImage
self.dismiss(animated: false, completion: nil)
let FileName = " Image Name of selected file"
}
where the photoImageView is
var photoImageView = UIImageView(frame: CGRect(x: 82,y: 300,width: 100,height: 100))
a small ImageView that displays the selected image, I would like to get the FileName now any suggestions would be great
Short answer: You can't. The system doesn't give you the user's name for the file. I remember puzzling about this as well.
As I recall what it gives you is a pointer to an in-memory UIImage object, not even a URL to a system-named file on disk. (But it's been a while since I've used the image picker.)
Using Photos API (PHAsset & PHAssetResource) you can get file name of the image selected using UIImagePickerController. I posted the solution in this question.
From iOS 11.0 onwards they introduced a new key into info dictionary to get PHAsset of picked image , you can try this:
func imagePickerController(_ picker: UIImagePickerController,didFinishPickingMediaWithInfo info: [String : Any]) {
if let photoAsset = info[UIImagePickerControllerPHAsset] as? PHAsset {
if let fileName = photoAsset.value(forKey: "filename") ?? "nonamefound"}
Related
I'm extracting pixel colors from a CGImage using the code described in this answer.
However, I just realized that if I load an image that was created on another device, the pixels values look wrong. The first obvious problem is that the alpha is gone. The CGImageAlphaInfo reports .noneSkipLast, but I know the image is RGBA. If I read it from the same device it was created, it looks fine. The second problem is that there is some color bleeding, as if the image had been resized. Perhaps is being compressed or something.
Here's an example:
Source image is this watermelon, 12x12
It was created on my iPad. But if I load it on my iPhone through iCloud using that code I linked, I get this:
The alpha channel is gone, and colors bleed.
If from the same iPhone I send the little watermelon to my Mac using Airdrop, and send it back using Airdrop again (so it is supposedly the same image!), and load it now, I get the correct image:
(dark brown areas is where alpha is 0)
If you have a couple of iOS device with iCloud enabled, you can reproduce this behavior in this app: http://swiftpixels.endavid.com
where I'm using that code to read pixel colors.
What could be the difference between those images? How can I read the correct image from iCloud? Should I look for hints in UIImage instead of CGImage?
Any clues? Thanks!
Update
For reference, I'm reading the image using a UIImagePickerController, using this code:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage {
loadImageInMemory(image)
}
picker.dismiss(animated: true, completion: nil)
self.presentingViewController?.dismiss(animated: true, completion: nil)
}
fileprivate func loadImageInMemory(_ image: UIImage) {
/// skipping some preparation
guard let cgImage = image.cgImage else {
return
}
/// getImageData is a function like getPixelColor linked above,
/// but for a Rect
self.imageData = cgImage.getImageData(rect, width, height)
}
I also found this question which may be related: UIImagePickerController and iCloud photos
As Rob suggested in the comments below, I changed the Photos settings in my phone to "Download and Keep Originals" (instead of "Optimize iPhone Storage"), and that fixes the problem. So I guess the question is why iCloud tries to compress a PNG image that it's just 1,355 bytes, and whether it's possible to access the original image from the UIImagePickerController
In the Settings app, under “Photos” there is an “Optimize iPhone Storage” vs “Download and Keep Originals” option. The latter should synchronize the photos library without altering the images in any way.
It seems Airdrop can access the original image, though.
Airdrop is not relying upon photo library iCloud synchronization to send the image. That's why the asset makes it across, unaltered.
How can I make my app access the original as well?
It comes down to whether you really want to use the Photos library to synchronize your assets. This seems especially true as many people may not choose to sync their huge Photos library to iCloud at all. I'm not sure you want to rely upon that.
You might want to just use CloudKit yourself rather than relying upon the Photos library. Perhaps you should have an option in the app so a user can choose to use iCloud storage at all, and if so, do the iCloud storage within your app rather than relying upon the Photos library.
The reason why the image looked blurry and without alpha seems to be that Photos streams Jpeg-compressed images from iCloud by default. Even if your original image would be smaller without compression, like in this pixel art example.
As pointed out by Rob, a way to verify that this is the case is to change your Photos settings. From the Settings app:
Settings -> Photos -> Download and Keep Originals
This would fix the issue, but of course it's not desirable. If you want to keep using Photos, instead of implementing your own iCloud solution, while keeping the Optimize iPhone Storage setting, you can use PhotoKit to retrieve the original image.
Replace this code,
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage {
loadImageInMemory(image)
}
picker.dismiss(animated: true, completion: nil)
self.presentingViewController?.dismiss(animated: true, completion: nil)
}
by this other code:
import Photos
// ...
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
// it will be loaded asynchronously
loadImageFromPicker(info: info)
picker.dismiss(animated: true, completion: nil)
self.presentingViewController?.dismiss(animated: true, completion: nil)
}
private func loadImageFromPicker(info: [UIImagePickerController.InfoKey : Any]) {
var phAsset: PHAsset?
if #available(iOS 11.0, *) {
phAsset = info[UIImagePickerController.InfoKey.phAsset] as? PHAsset
} else {
// Fallback on earlier versions
if let referenceURL = info[UIImagePickerController.InfoKey.referenceURL] as? URL {
let fetchResult = PHAsset.fetchAssets(withALAssetURLs: [referenceURL], options: nil)
phAsset = fetchResult.firstObject
}
}
guard let asset = phAsset else {
return
}
// size doesn't matter, because resizeMode = .none
let size = CGSize(width: 32, height: 32)
let options = PHImageRequestOptions()
options.version = .original
options.deliveryMode = .highQualityFormat
options.resizeMode = .none
options.isNetworkAccessAllowed = true
PHImageManager.default().requestImage(for: asset, targetSize: size, contentMode: .aspectFit, options: options) { [weak self] (image, info) in
if let s = self, let image = image {
s.loadImageInMemory(image)
}
}
}
This code will work with both local images and iCloud images.
I think I have a similar problem like this other question's title suggests, but the accepted answer is not at all what I need.
I want to "force" the user to use a square image. Currently, when choosing a horizontally "longer" image (landscape image), one could theoretically make a selection with black bars top and bottom which results in a selected image that is NOT squared.
Here my code:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
var selected: UIImage?
if let img = info[UIImagePickerControllerEditedImage] as? UIImage {
selected = img
selected = UIImage.imgToSquare(image: selected)
doSomethingWithImage(selected!)
}
picker.dismiss(animated: true, completion: nil)
}
UIImage.imgToSquare(image: UIImage) is an Extension that I have and use as a temporary fallback but it would be much more elegant if the "maximum pinch/zoom-out" gives a square image.
To whoever marked this as a duplicate.. In which way is this a duplicate? I could not find a solution on this on the whole internet, and what you linked was not related to UIImagePickerController....
I already said I'm able to crop an image to a square already with my Extension (UIImage.imgToSquare(image: UIImage))....
But what I want, is the image SELECTION to always be square.
I'll attach a screenshot.
What I have:
What I want:
(the second one - what I want - would still be scrollable horizontally)
I think this will helpful for you..
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
var myimage:UIImage!
if let pickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage {
myImageView.contentMode = .ScaleAspectFit
myImageView.image = pickedImage
myimage = pickedImage
}
// So the user can pick only Square Image not others
if myimage.size.height == myimage.size.width
{
dismissViewControllerAnimated(true, completion: nil)
}
}
In my application, I have to store and upload multiple photos to a server using the standard iOS UIImagePickerController library. Currently, I am storing working on storing the UIImagePickerControllerReferenceURL for the photo library:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let assetURL = info["UIImagePickerControllerReferenceURL"] as? URL {
assetArray.append(assetURL) //assetArray globally stored as 'fileprivate var assetArray = [URL]()'
}
}
However, I just read somewhere that the camera does not provide a "UIImagePickerControllerReferenceURL" key. Thus this method may not work, when I get around to the camera part, so I am re-thinking my logic now.
I am using KingFisher so I am currently researching to see if you can cache images using that framework, but I am not certain. I'm also reading that I could grab the camera image's URL using the Photo's API, which I will attempt next. If I could, I will grab the url of the the photo taken by the camera, and append it to the assetArray.
Had this be a single photo upload, this would be relatively simple, but since I do not want to hinder the performance of the application by storing a large data/image array, this task has become complex.
Is it best to continue what I am doing:
1) Grab URL's of each image I want to upload, and storing them into an URL array. Before uploading to the server, grab the data in .png form of each URL, and upload images to server
2) Cache actual images somewhere, so when uploading to server, images will already be there (not needed to be converted from URL -> image). Issue here is having many images may hinder app performance if not done correctly.
or
3) Some other method
Any help would be greatly appreciated. Thank you!
I found a solution using Kingfisher. First, I created an ImageCache object for the VC handling the multiple photos (you need to import Kingfisher):
fileprivate var imageCache: ImageCache = ImageCache(name: "newTaskCache")
After I select the photo using UIImagePickerController, I save the unique ID in a string array, cachedImageIDs:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
let image : UIImage = (info[UIImagePickerControllerOriginalImage] as? UIImage)!
let imageID: String?
if let assetURL = info["UIImagePickerControllerReferenceURL"] as? URL {
imageID = assetURL.absoluteString
cachedImageIDs.append(imageID!)
}else{
//camera does not return a UIImagePickerControllerReferenceURL, so unique imageID will be posix time, until I figure out how to get imageURL string
imageID = String(describing: Date().posixTime())
cachedImageIDs.append(imageID!)
}
imageCache.store(image, forKey: imageID!) {
print("saved image")
picker.dismiss(animated: true, completion: nil)
}
}
When I need to retrieve the images, they are
func getImages() {
for id in cachedImageIDs {
//retrieve image
imageCache.retrieveImage(forKey: id, options: nil, completionHandler: { (image, cacheType) -> () in
print(image)
})
}
}
Can we load images found locally on the device with SDWebimage using URL option? if yes then Im trying to use SDWebimage to display images, below is my code and i am unable to load image in the imageview. its still blank. kindly help me to understand what im doing wrong?
func addImage(sender: AnyObject){
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.SavedPhotosAlbum){
picController.sourceType = UIImagePickerControllerSourceType.SavedPhotosAlbum;
picController.allowsEditing = true
self.presentViewController(picController, animated: true, completion: nil)
}
}
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
let url = info[UIImagePickerControllerReferenceURL] as! NSURL
titleImageView.sd_setImageWithURL(url)
self.dismissViewControllerAnimated(true, completion: nil)
}
Note that the UIImagePickerController delegate
imagePickerController: didFinishPickingMediaWithInfo
will have the info as described in documentation-
A dictionary containing the original image and the edited image, if an
image was picked; or a filesystem URL for the movie, if a movie was
picked. The dictionary also contains any relevant editing information.
The keys for this dictionary are listed in Editing Information Keys.
so if it is image that you are looking at, it will be right there in the dictionary itself.
You can get original image directly-
let image = info[UIImagePickerControllerOriginalImage]
if let image = image {
//Set this image to your image view directly
titleImageView.image = image
}
Here info as a NSDictonary and get that key is UIImagePickerControllerOriginalImage
see this code :
func imagePickerController(picker: UIImagePickerController!, didFinishPickingMediaWithInfo info:NSDictionary!) {
var tempImage:UIImage = info[UIImagePickerControllerOriginalImage] as UIImage
imagePreview.image = tempImage
self.dismissModalViewControllerAnimated(true)
}
I'm having an issue whereby images that were taken by a Sony digital camera and transferred to my phone return nil when I try to save the image in didFinishPickingMediaWithInfo. It returns an image for any image taken on my iPhone or downloaded from the Internet. Why is this and what can I do to fix it?
allowsEditing is set to false.
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [NSObject : AnyObject]) {
dismissViewControllerAnimated(true, completion: nil) //5
var chosenImage = info[UIImagePickerControllerOriginalImage] as? UIImage //2
let previewVC:ImagePreviewViewController = self.storyboard?.instantiateViewControllerWithIdentifier("PreviewVC") as! ImagePreviewViewController
previewVC.imageToCrop = chosenImage!
self.navigationController?.pushViewController(previewVC, animated: true)
}
UPDATE
I discovered that this issue relates to my iCloud Photo Library sync and I selected a raw image (.arw) instead of JPEG. The raw images return nil