UIImagepickercontrollerreferenceurl returns nil - iphone

After picking image from camera this method gets called.
- (void) imagePickerController: (UIImagePickerController *) picker
didFinishPickingMediaWithInfo: (NSDictionary *) info {
[picker dismissModalViewControllerAnimated: YES];
// cameraImage.image = [info objectForKey:
// UIImagePickerControllerOriginalImage];
NSLog(#"%#",info);
NSURL *url = [info valueForKey:UIImagePickerControllerReferenceURL];
NSLog(#"%#",url);
NSLog(#"%#",[info valueForKey:UIImagePickerControllerMediaURL]);
}
I get the image from UIImagePickerControllerOriginalImage. But UIImagePickerControllerReferenceURL returns nil. I do not know what am i doing wrong. Please help.
Thanks

There is no Reference URL because the photo does not exist on the file system until you actually save it.
MediaURL is only used for movies. It is the URL for the compressed version of the movie, saved on a temp folder, accessible by your application.

I had the same problem for getting the file name for chosen photos. For newly taken pictures UIImagePickerControllerReferenceURL would return nil since NSURL does not exist so i assign a default name. It referenceUrl exists i get the filename with help of PHImageManager which was introduced in Photos Framework.
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
self.selectedIndex = 1
var fileName = UIImage.defaultFileName()
//Pic is comming from library so url exists
if let referenceUrl = info[UIImagePickerControllerReferenceURL] as? NSURL, image = info[UIImagePickerControllerOriginalImage] as? UIImage {
if #available(iOS 8.0, *) {
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
fileName = path.lastPathComponent!
}
self.addDocumentDelegate?.tabBarControllerDidTakePicture(self, image: image, fileName: fileName)
AppRoot.sharedInstance.dismissModalViewController(true, completion: nil)
})
} else {
self.addDocumentDelegate?.tabBarControllerDidTakePicture(self, image: image, fileName: fileName)
AppRoot.sharedInstance.dismissModalViewController(true, completion: nil)
}
} else if let image = info[UIImagePickerControllerOriginalImage] as? UIImage { //Pic is comming from Camera so url does not exists
self.addDocumentDelegate?.tabBarControllerDidTakePicture(self, image: image, fileName: fileName)
AppRoot.sharedInstance.dismissModalViewController(true, completion: nil)
}
}

Related

swift image picker gets several pictures

i have a problem with inserting images into a CollectionView cell using an ImagePicker. The problem is, if I click on a photo which I would like to insert quickly several times, then the photo is inserted several times in different cells.
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
picker.dismiss(animated: true, completion: nil)
picker.allowsEditing = true
if let pickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage {
collectionViewController?.imageArray.append(pickedImage)
collectionViewController?.newImages.append(pickedImage)
let guid = UUID()
let fileManager = FileManager.default
let imagePath = (NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString).appendingPathComponent("\(guid).png")
let data = UIImagePNGRepresentation(fixOrientation(img: pickedImage))
fileManager.createFile(atPath: imagePath as String, contents: data, attributes: nil)
let image = CoreDataManager.shared.createImageyObject(pfad: imagePath, date: Date(), guid: guid)
collectionViewController?.images.append(image)
if collectionViewController?.images.count == 1 {
collectionViewController?.images[0].isBaseImage = true
collectionViewController?.lastIndex = 0
}
collectionViewController?.update()
}
}
Mediainfo contains image url, media url... Maybe you should cache picked imageURL (that unique) in a Set then check if imageURL that's already existed.

Getting location details from image in ios swift

I am trying to get location details from image using
UIImagePickerControllerReferenceURL but I found that PHAsset.fetchAssets(withALAssetURLs: [URL], options: opts) has been deprecated .Please help me in getting location details.
Can we do it using PHAssetCollection?. If so please help me
public func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any])
{
print(info)
let chosenImage = info[UIImagePickerControllerOriginalImage] as! UIImage
selectedImage.contentMode = .scaleAspectFit
selectedImage.image = chosenImage
dismiss(animated:true, completion: nil)
if let URL = info[UIImagePickerControllerReferenceURL] as? URL {
let opts = PHFetchOptions()
opts.fetchLimit = 1
let assets = PHAsset.fetchAssets(withALAssetURLs: [URL], options: opts)
let asset = assets[0]
print(asset.location)
// The location is "asset.location", as a CLLocation
// ... Other stuff like dismiss omitted
}
}
Only solution I found so far is to use the iOS 10 code block even in iOS 11 and just ignore the UIImagePickerControllerReferenceURL deprecated message (the key still exists and works in iOS 11)
import AssetsLibrary
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let imageUrl = info[UIImagePickerControllerReferenceURL] as? NSURL{
print(imageUrl.absoluteString) //"assets-library://asset/asset.JPG?id=ED7AC36B-A150-4C38-BB8C-B6D696F4F2ED&ext=JPG"
// access image from URL
let assetLibrary = ALAssetsLibrary()
assetLibrary.asset(for: imageUrl as URL! , resultBlock: { (asset: ALAsset!) -> Void in
if let actualAsset = asset as ALAsset? {
let assetRep: ALAssetRepresentation = actualAsset.defaultRepresentation()
let iref = assetRep.fullResolutionImage().takeUnretainedValue()
let image = UIImage.init(cgImage: iref)
self.img.image = image
}
}, failureBlock: { (error) -> Void in
})
}
dismiss(animated: true, completion: nil)
}
Hope this will help.

Save image in Realm

I'm trying to pick image from device's Photo Library in method:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any])
{
userPhoto.image = info[UIImagePickerControllerOriginalImage] as! UIImage?
userPhoto.contentMode = .scaleAspectFill
userPhoto.clipsToBounds = true
dismiss(animated: true, completion: nil)
}
and save this picture in Realm (as NSData):
asset.assetImage = UIImagePNGRepresentation(userPhoto.image!)! as NSData?
...
try! myRealm.write
{
user.assetsList.append(asset)
myRealm.add(user)
}
After build succeeded and trying to pick and save image (in the app) i have app error:
'Binary too big'
What i'm doing wrong?
P.S. Sorry for my English :)
After some actions i have this code. But it's overwrite my image.
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any])
{
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!)
let image = info[UIImagePickerControllerOriginalImage]as! UIImage
let data = UIImagePNGRepresentation(image)
do
{
try data?.write(to: localPath!, options: Data.WritingOptions.atomic)
}
catch
{
// Catch exception here and act accordingly
}
userPhoto.image = image
userPhoto.contentMode = .scaleAspectFill
userPhoto.clipsToBounds = true
urlCatch = (localPath?.path)!
self.dismiss(animated: true, completion: nil);
}
Don't save the image itself into realm, just save the location of the image into realm as String or NSString and load the image from that saved path. Performance wise it's always better to load images from that physical location and your database doesn't get too big
func loadImageFromPath(_ path: NSString) -> UIImage? {
let image = UIImage(contentsOfFile: path as String)
if image == nil {
return UIImage()
} else{
return image
}
}
or you just save the image name, if it's in your documents directory anyhow
func loadImageFromName(_ imgName: String) -> UIImage? {
guard imgName.characters.count > 0 else {
print("ERROR: No image name")
return UIImage()
}
let imgPath = Utils.getDocumentsDirectory().appendingPathComponent(imgName)
let image = ImageUtils.loadImageFromPath(imgPath as NSString)
return image
}
and here a rough example how to save a captured image to your directory with a unique name:
#IBAction func capture(_ sender: AnyObject) {
let videoConnection = stillImageOutput?.connection(withMediaType: AVMediaTypeVideo)
stillImageOutput?.captureStillImageAsynchronously(from: videoConnection, completionHandler: { (imageDataSampleBuffer, error) -> Void in
let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(imageDataSampleBuffer)
//self.stillImage = UIImage(data: imageData!)
//self.savedImage.image = self.stillImage
let timestampFilename = String(Int(Date().timeIntervalSince1970)) + "someName.png"
let filenamePath = URL(fileReferenceLiteralResourceName: getDocumentsDirectory().appendingPathComponent(timestampFilename))
let imgData = try! imageData?.write(to: filenamePath, options: [])
})
/* helper get Document Directory */
class func getDocumentsDirectory() -> NSString {
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
let documentsDirectory = paths[0]
//print("Path: \(documentsDirectory)")
return documentsDirectory as NSString
}
https://realm.io/docs/objc/latest/#current-limitations
maximum data size is 16 MB . this is limitation of realm
Depending on how your serializing the image data (for example if it's a lossless bitmap), it's quite possible that this data exceed 16MB, which as you've stated is Realm's maximum supported size for binary properties.
When you invoke NSData.length, how large does it say your data is?

Obtain NSURL from UIImagePickerController

I'm attempting to grab the file path of an image selected through an imagePickerController in order to upload the file to Firebase Storage.
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
mediaUploadView.image = info[UIImagePickerControllerOriginalImage] as? UIImage
let localUrl: NSURL = (info[UIImagePickerControllerReferenceURL] as! NSURL)
print(localUrl)
let localFile: NSURL = localUrl
let mediaRef = storageRef.child("media")
let uploadTask = mediaRef.putFile(localUrl, metadata: nil) { metadata, error in
if (error != nil) {
} else {
let downloadURL = metadata!.downloadURL
}
}
self.dismissViewControllerAnimated(true, completion: nil)
}
The output reads:
assets-library://asset/asset.JPG?id=C224DA06-6B7B-4BE2-8F5E-2EC7BC8B0526&ext=JPG
Body file is unreachable: /asset.JPG
Error Domain=NSCocoaErrorDomain Code=4 "The file doesn’t exist."
It grabs what I believe is the NSURL, but then is unable to find it for upload.
I have attempted to follow along with this similar problem on stack "How do I get Image reference and upload image to Firebase?" but the output then simply returns nil.
Any help would be great, thank you!
I had trouble getting the info[UIImagePickerControllerOriginalImage] to work. I had to do it like this:
let assets = PHAsset.fetchAssetsWithALAssetURLs([localUrl], options: nil)
let asset = assets.firstObject
asset?.requestContentEditingInputWithOptions(nil, completionHandler: { (contentEditingInput, info) in
let imageFile = contentEditingInput?.fullSizeImageURL
// now call putFile with imageFile instead of localURL

Unable to load image from asset URL

I have a class that stores information about the assets on the phone (images, videos).
My class has the ResourceURLString defined as such
#property NSURL *ResourceURL;
I am setting the property while looping trough the assets on the phone as such
Item.ResourceURLString = [[asset valueForProperty:ALAssetPropertyURLs] objectForKey:[[asset valueForProperty:ALAssetPropertyRepresentations] objectAtIndex:0]];
When the user clicks on an image I want to load the image.
The code that I have is this
NSData *imageUrl = [NSData dataWithContentsOfURL:[NSURL URLWithString:[CurrentItem.ResourceURL absoluteString]]];
Img = [UIImage imageWithData:imageUrl];
But the Image is always nil
I have verified that the ResourceURL property contains the URL
assets: library://asset/asset.JPG?id=82690321-91C1-4650-8348-F3FD93D14613&ext=JPG
You can't load images in this way.
You need to use ALAssetsLibrary class for this.
Add assetslibrary framework to your project and add header files.
Use the below code for loading image:
ALAssetsLibraryAssetForURLResultBlock resultblock = ^(ALAsset *myasset)
{
ALAssetRepresentation *rep = [myasset defaultRepresentation];
CGImageRef iref = [rep fullResolutionImage];
if (iref) {
UIImage *largeimage = [UIImage imageWithCGImage:iref];
yourImageView.image = largeImage;
}
};
ALAssetsLibraryAccessFailureBlock failureblock = ^(NSError *myerror)
{
NSLog(#"Can't get image - %#",[myerror localizedDescription]);
};
NSURL *asseturl = [NSURL URLWithString:yourURL];
ALAssetsLibrary* assetslibrary = [[[ALAssetsLibrary alloc] init] autorelease];
[assetslibrary assetForURL:asseturl
resultBlock:resultblock
failureBlock:failureblock];
Since iOS 8 you can use the Photos Framework here is how to do it in Swift 3
import Photos // use the Photos Framework
// declare your asset url
let assetUrl = URL(string: "assets-library://asset/asset.JPG?id=9F983DBA-EC35-42B8-8773-B597CF782EDD&ext=JPG")!
// retrieve the list of matching results for your asset url
let fetchResult = PHAsset.fetchAssets(withALAssetURLs: [assetUrl], options: nil)
if let photo = fetchResult.firstObject {
// retrieve the image for the first result
PHImageManager.default().requestImage(for: photo, targetSize: PHImageManagerMaximumSize, contentMode: .aspectFill, options: nil) {
image, info in
let myImage = image //here is the image
}
}
Use PHImageManagerMaximumSize if you want to retrieve the original size of the picture. But if you want to retrieve a smaller or specific size you can replace PHImageManagerMaximumSize by CGSize(width:150, height:150)
As of iOS 9.0 ALAssetsLibraryis deprecated. Since iOS 8.0, this works with the PHPhotoLibrary. This is a small UIImage extension, Swift 2X.
This uses a fixed image size.
import Photos
extension UIImageView {
func imageFromAssetURL(assetURL: NSURL) {
let asset = PHAsset.fetchAssetsWithALAssetURLs([assetURL], options: nil)
guard let result = asset.firstObject where result is PHAsset else {
return
}
let imageManager = PHImageManager.defaultManager()
imageManager.requestImageForAsset(result as! PHAsset, targetSize: CGSize(width: 200, height: 200), contentMode: PHImageContentMode.AspectFill, options: nil) { (image, dict) -> Void in
if let image = image {
self.image = image
}
}
}
}
Getting the imageReferenceURL from the UIImagePickerController delegate:
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
imageURL = info[UIImagePickerControllerReferenceURL] as? NSURL
}
Setting the image
let imageView = UIImageView()
imageView.imageFromAssetURL(imageURL)
There might be effects I haven't encountered yet, a classic would be UITableViewCell or thread problems. I'll keep this updated, also appreciate your feedback.
For Swift 5
fetchAssets(withALAssetURLs) will be removed in a future release. Hence we using fetchAssets to get image from asset local identifier
extension UIImageView {
func imageFromLocalIdentifier(localIdentifier: String, targetSize: CGSize) {
let fetchOptions = PHFetchOptions()
// sort by date desending
fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
// fetch photo with localIdentifier
let results = PHAsset.fetchAssets(withLocalIdentifiers: [localIdentifier], options: fetchOptions)
let manager = PHImageManager.default()
results.enumerateObjects { (thisAsset, _, _) in
manager.requestImage(for: thisAsset, targetSize: targetSize, contentMode: .aspectFit, options: nil, resultHandler: {(image, _) in
DispatchQueue.main.async {[weak self] in
self?.image = image
}
})
}
}
}
Update
let image = UIImage(data: NSData(contentsOf: imageURL as URL)! as Data)
ALAsset *asset = "asset array index"
[tileView.tileImageView setImage:[UIImage imageWithCGImage:[asset thumbnail]]];