I'm building an APP with Swift 3 and backendless and i'm having trouble to upload an image from my APP (the user will take a pic from camera or from photoLibrary) to backendless.
The APP is saving the images to the photoLibrary :
func savePic() {
let imageData = UIImageJPEGRepresentation(itemPic.image!, 0.5);
let compressedJPEGImage = UIImage(data: imageData!);
UIImageWriteToSavedPhotosAlbum(compressedJPEGImage!, nil, nil, nil);
}
What is the taken image address?
And how do i upload it to backEndLess?
You should use Backendless.file.upload method.
For example:
func uploadImage(_ img:UIImage){
//convert UIImage to jpg Data with 0.5 compressionQuality (use 1 for full quality)
let jpg=UIImageJPEGRepresentation(img, 0.5);
//saving file name with current timestamp
let fileName="IMG_\(Date().timeIntervalSince1970).jpg";
//uploading image asynchronously
Backendless.sharedInstance().file.upload("imagesFolder/\(fileName)", content:jpg, response: {(res) in
//uploading image finished
}, error: {(e) in
//failed to upload
print("error code: \(e!.faultCode)");
})
}
If you need to upload it in PNG format use UIImagePNGRepresentation instead of IImageJPEGRepresentation
To upload an Image directly picked by user from saved photos album or taken by camera you can do it like this:
Use UINavigationControllerDelegate & UIImagePickerControllerDelegate
Specify UIImagePickerControllerSourceType to be used, such as: .photoLibrary, .camera or .savedPhotosAlbum
Upload the created UIImage when user didFinishPickingMediaWithInfo
Here an example:
class MyViewController : UIViewController, UINavigationControllerDelegate, UIImagePickerControllerDelegate{
var imgPicker = UIImagePickerController();
var backendless = Backendless.sharedInstance();
override func viewDidLoad() {
imgPicker.delegate = self;
}
#IBAction func imgFromCamera(_ btn:UIButton){
imgPicker.sourceType = .camera;//image picker with camera
show(imgPicker, sender: self);//open image picker
}
#IBAction func imgFromSavedPhotos(_ btn:UIButton){
imgPicker.sourceType = .savedPhotosAlbum;//image picker from saved photos
show(imgPicker, sender: self);//open image picker
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
let img = info[UIImagePickerControllerOriginalImage] as! UIImage;
uploadImage(img);
dismiss(animated: true, completion: nil);
}
func uploadImage(_ img:UIImage){
let jpg=UIImageJPEGRepresentation(img, 1);//full scale JPG
//let png=UIImagePNGRepresentation(img);//full scale PNG
let fileName="IMG_\(Date().timeIntervalSince1970).jpg";
//upload img
Backendless.sharedInstance().file.upload("imagesFolder/\(fileName)", content:jpg, response: {(res) in
//successfully uploaded
}, error: {(e) in
//failed to upload
})
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
dismiss(animated: false, completion: {
print("user didn't pick any image");
});
}
}
Also keep in mind that to use those you should declare: NSPhotoLibraryUsageDescription & NSCameraUsageDescription in you Info.plist otherwise it crash in iOS 10 as stated in linked reference.
Here an example:
<key>NSPhotoLibraryUsageDescription</key>
<string>Your explanation here</string>
<key>NSCameraUsageDescription</key>
<string>Your explanation here</string>
Related
I am building a simple app where I get an image from UIImagePickerController (from Camera or Photo Library, depends on user selection) and send it to a server.
The latter seems to be saving images on the App internal folder, because when I take any photo, in the Disk Debug Menu in Xcode, I can see every time 1 - 1,5 MB writing on Disk. The same happens for images from Photo Library, they too occupy about 1 MB.
This is the code, very basic:
(VisualRecognition is the IBM API to use one of their AI services)
let imagePicker = UIImagePickerController()
var imageShot = UIImage() //To send later the image to the server
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
let userPickedImage = info[UIImagePickerControllerOriginalImage] as! UIImage
imageShot = userPickedImage
picker.dismiss(animated: true) {
self.elaborateImage(self.imageShot). //The sending function
}
}
func elaborateImage(_ image: UIImage) {
animateIn()
let group = DispatchGroup()
group.enter()
DispatchQueue.main.async {
let visualRecognition = VisualRecognition(version: self.version, apiKey: self.apiKey)
visualRecognition.classify(image: image, acceptLanguage: self.language, failure: { (error) in
print("There was an error")
}, success: { (classifiedImage) in
let classes = classifiedImage.images.first!.classifiers.first!.classes
var classificationResults = [ScanResult]()
for index in 0..<classes.count {
let scan = ScanResult.init(score: Int(classes[index].score! * 100), name: classes[index].className)
classificationResults.append(scan)
}
self.sortedClassificationResults = classificationResults.sorted(by: {$0.score > $1.score})
group.leave()
})
}
group.notify(queue: .main) {
self.performSegue(withIdentifier: "goToResults", sender: self)
}
}
After sending the images to the server I don't need anymore them, but they continue to grow the app size.
How Can I stop UIImagePickerController from saving images inside the App Bundle?
Thanks
In iOS Swift I'm having difficulty loading an animated GIF from the device photo library to a UIImageView or creating a .gif file from it. I have no problem displaying the animated GIF if it's a file on a server or if it's right in the app. However, when I load it from the photo library, I lose the animation. I found some Objective-C solutions and tried to convert them over to Swift, but haven't had any luck.
Here is what I have so far:
#IBAction func buttonTapped(sender: UIButton) {
selectPhoto()
}
func selectPhoto() {
let photoLibraryController = UIImagePickerController()
photoLibraryController.delegate = self
photoLibraryController.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
let mediaTypes:[String] = [kUTTypeImage as String]
photoLibraryController.mediaTypes = mediaTypes
photoLibraryController.allowsEditing = false
self.presentViewController(photoLibraryController, animated: true, completion: nil)
}
// UIImagePickerControllerDelegate
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
let origImage = info[UIImagePickerControllerOriginalImage] as! UIImage
self.imageView.image = origImage
picker.dismissViewControllerAnimated(true, completion: nil)
}
Optimally, I would like to save the photo library image to a gif file on the server. From there I have no trouble displaying it. However, I need some help getting the data from the photo library into some type of property, without losing the animation. Do I need to use something like ALAssetsLibrary for this?
Thanks.
Yes, Use ALAssetsLibrary → now called PHAsset.
You should get the NSData of the gif, not UIImage( because UIImage will only get the first frame.)
So basically you would do something like this:
One you get the asset
let requestOptions = PHImageRequestOptions()
requestOptions.isSynchronous = true // adjust the parameters as you wish
PHImageManager.default().requestImageData(for: asset, options: requestOptions, resultHandler: { (imageData, UTI, _, _) in
if let uti = UTI,let data = imageData ,
// you can also use UTI to make sure it's a gif
UTTypeConformsTo(uti as CFString, kUTTypeGIF) {
// save data here
}
})
Resource: PHAsset
You can get an access to the location of the image file using InfoKey .imageURL and retrieve Data from this URL
// UIImagePickerControllerDelegate
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
if let path = info[.imageURL] as? URL {
if let data = try? Data(contentsOf: path) {
self.imageView.image = UIImage(data: data)
//Now you have Data of a file: so you can convert it to image or gif or send to server or start animation (e.g. Framework JellyGIF)
self.imageView.startGif(with: .data(data))
}
picker.dismissViewControllerAnimated(true, completion: nil)
}
In iOS Swift I'm having difficulty loading an animated GIF from the device photo library to a UIImageView or creating a .gif file from it. I have no problem displaying the animated GIF if it's a file on a server or if it's right in the app. However, when I load it from the photo library, I lose the animation. I found some Objective-C solutions and tried to convert them over to Swift, but haven't had any luck.
Here is what I have so far:
#IBAction func buttonTapped(sender: UIButton) {
selectPhoto()
}
func selectPhoto() {
let photoLibraryController = UIImagePickerController()
photoLibraryController.delegate = self
photoLibraryController.sourceType = UIImagePickerControllerSourceType.PhotoLibrary
let mediaTypes:[String] = [kUTTypeImage as String]
photoLibraryController.mediaTypes = mediaTypes
photoLibraryController.allowsEditing = false
self.presentViewController(photoLibraryController, animated: true, completion: nil)
}
// UIImagePickerControllerDelegate
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
let origImage = info[UIImagePickerControllerOriginalImage] as! UIImage
self.imageView.image = origImage
picker.dismissViewControllerAnimated(true, completion: nil)
}
Optimally, I would like to save the photo library image to a gif file on the server. From there I have no trouble displaying it. However, I need some help getting the data from the photo library into some type of property, without losing the animation. Do I need to use something like ALAssetsLibrary for this?
Thanks.
Yes, Use ALAssetsLibrary → now called PHAsset.
You should get the NSData of the gif, not UIImage( because UIImage will only get the first frame.)
So basically you would do something like this:
One you get the asset
let requestOptions = PHImageRequestOptions()
requestOptions.isSynchronous = true // adjust the parameters as you wish
PHImageManager.default().requestImageData(for: asset, options: requestOptions, resultHandler: { (imageData, UTI, _, _) in
if let uti = UTI,let data = imageData ,
// you can also use UTI to make sure it's a gif
UTTypeConformsTo(uti as CFString, kUTTypeGIF) {
// save data here
}
})
Resource: PHAsset
You can get an access to the location of the image file using InfoKey .imageURL and retrieve Data from this URL
// UIImagePickerControllerDelegate
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
if let path = info[.imageURL] as? URL {
if let data = try? Data(contentsOf: path) {
self.imageView.image = UIImage(data: data)
//Now you have Data of a file: so you can convert it to image or gif or send to server or start animation (e.g. Framework JellyGIF)
self.imageView.startGif(with: .data(data))
}
picker.dismissViewControllerAnimated(true, completion: nil)
}
I have a UIImagePickerController with the option to select from library.
When the accessLibrary button is called, it prompts another UIImagePickerController that has source type .PhotoLibrary.
func accessLibrary(sender: UIButton!) {
NSLog("access library")
choseFromLibrary = true
self.libraryPicker = UIImagePickerController()
self.libraryPicker!.allowsEditing = false
self.libraryPicker!.sourceType = .PhotoLibrary
self.presentViewController(self.libraryPicker!, animated: true, completion: nil)
}
This all works well, but when the user does select a photo, I want to pass that image to a view and then show that view on the screen.
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
let metadata = info[UIImagePickerControllerMediaMetadata] as? NSDictionary
var image = info[UIImagePickerControllerOriginalImage] as? UIImage
if (image != nil) {
if (choseFromLibrary) {
let cnfrmImgView = ConfirmImageView.init(image: image!)
self.view.addSubview(cnfrmImgView)
}
else {
if (frontFacing) {
image! = UIImage(CGImage: image!.CGImage!, scale: 1.0, orientation: .LeftMirrored)
}
let cnfrmImgView = ConfirmImageView.init(image: image!)
self.view.addSubview(cnfrmImgView)
}
}
}
The above function works if the image is taken using the camera, but not using the library.
When a user picks a photo from the library, the library picker controller just dismisses itself and the view is not display.
I ran an NSLog("here") to check if the didFinishPickingImageWithInfo function is called when choosing from the library and in fact it is not.
didFinishPickingImageWithInfo is a delegate message (UIImagePickerControllerDelegate). The problem, however, is that you have not given your image picker any delegate! Thus, it has no one to send delegate messages to.
if you want to implement a Instagram like image picker than try this
Image Picker like Instagram
The delegate function is updated in new swift versions from 4 to upwards.
Use this function instead
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) { }
Besides browsing the Photolibrary I've enabled the Camera to add a photo to my
#IBAction func startCameraButtonTapped(sender: AnyObject) {
let startCameraController = UIImagePickerController()
startCameraController.delegate = self
startCameraController.sourceType = UIImagePickerControllerSourceType.Camera
startCameraController.allowsEditing = true
self.presentViewController(startCameraController, animated: true, completion: nil)
//invoiceImageHolder.image!.scaleAndRotateImage2(280)
//self.invoiceImageHolder.transform = CGAffineTransformMakeRotation((180.0 * CGFloat(M_PI)) / 180.0)
}
Every user input can be deleted, but now I'd like to know where the corresponding photo is. When I browse the photo library I can't see the photos taken with my app? Where are those photos stored?
[edit]
This is my saveImage process
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
let selectedImage = info[UIImagePickerControllerOriginalImage] as! UIImage
saveImage(selectedImage, path: fileInDocumentsDirectory("\(uniqueImageName)"))
// set the unique image reference in textfield
// Set photoImageView to display the selected image
self.invoiceImageHolder.image = selectedImage
// Dismiss the picker
dismissViewControllerAnimated(true, completion: nil)
}
func saveImage(image: UIImage, path: String) -> Bool{
let pngImageData = UIImagePNGRepresentation(image)
// let jpgImageData = UIImageJPEGRepresentation(image, 1.0)
let result = pngImageData?.writeToFile(path, atomically: true)
//print("Save result \(result)")
return result!
}
EDIT hmm I think I see where the photos are stored, but now how do I browse to them for deletions?
I think it's here:
/var/mobile/Containers/Data/Application/CBFE9E9D-A657-4011-8B9F-EF0C9BB2C603/Documents/
BUT everytime i restart the app the part between Application and /Documents is different??
Still not a working solution, but for those newbies as me this is a valuable readup: http://www.techotopia.com/index.php/Working_with_Directories_in_Swift_on_iOS_8
[EDIT 2]
with this code i am able to see all whiles stored with my app. I was a bit surprise to see all the files
// Files stored in my app filemanager
let filemgr = NSFileManager.defaultManager()
do {
print("Start filemanager")
let filelist = try filemgr.contentsOfDirectoryAtPath(documentsDirectory())
for filename in filelist {
print(filename)
}
} catch {
print("No directory path \(error)")
}
// end filemanager
UIImagePickerController() doesn't automatically save your photos into the library. See its UIImagePickerControllerDelegate protocol and you'll see that it has a method returning your UIImage after making a photo. Then you can save it:
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
if let image = info[UIImagePickerControllerOriginalImage] as? UIImage {
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)
}
}
you save them - not in the photo library - but as 'simply' files inside your app's documents folder. There is no standard UI for deletion then.
You need to write your own ViewController to show & handle deletions then.