I have done static image upload to AWS server successfully. When i combine it with imagepicker, I am facing a wierd issue due to which same image is being uploaded to AWS even though I pick and name them differently. The code is as follows:
internal func imagePickerController(_ picker: UIImagePickerController,
didFinishPickingMediaWithInfo info: [String : Any])
{
let image = info[UIImagePickerControllerOriginalImage] as! UIImage
var 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!)
print("image name : \(imageName)")
if !FileManager.default.fileExists(atPath: localPath!.path) {
do {
try UIImageJPEGRepresentation(image, 1.0)?.write(to: localPath!)
print("file saved")
//let imageData = NSData(contentsOf: localPath!)
//let finalURL = localPath!
//this is in swift 2; above 2 lines are its equivalent in swift3. I think the problem lies here
//let imageData = NSData(contentsOfFile: localPath)!
//imageURL = NSURL(fileURLWithPath: localPath)
}catch {
print("error saving file")
}
}
else {
print("file already exists")
}
self.dismiss(animated: true, completion: nil)
let credentialProvider = AWSCognitoCredentialsProvider(regionType: .USEast1, identityPoolId: "identity pool id")
let configuration = AWSServiceConfiguration(region: .APSoutheast1, credentialsProvider: credentialProvider)
AWSServiceManager.default().defaultServiceConfiguration = configuration
//these are the static values I used that worked perfectly fine with separate images
//let localFileName = "Alerts_bg"
//let ext = "png"
//let remoteName = localFileName + "." + ext
//let imageURL = Bundle.main.url(forResource: localFileName, withExtension: ext)!
let transferManager = AWSS3TransferManager.default()
let uploadRequest = AWSS3TransferManagerUploadRequest()!
uploadRequest.bucket = "bucket"
let imageAWSName = "ios_" + NSUUID().uuidString + ".jpg"
uploadRequest.key = imageAWSName
uploadRequest.body = localPath! as URL
uploadRequest.contentType = "image/jpg"
print("req123 : \(uploadRequest)")
uploadRequest.uploadProgress = { (bytesSent, totalBytesSent, totalBytesExpectedToSend) -> Void in
DispatchQueue.main.async(execute: {
//self.amountUploaded = totalBytesSent // To show the updating data status in label.
//self.fileSize = totalBytesExpectedToSend
print("progress : \(totalBytesSent)/\(totalBytesExpectedToSend)")
})
}
transferManager.upload(uploadRequest).continueWith(executor: AWSExecutor.mainThread(), block: { (task:AWSTask<AnyObject>) -> Any? in
if let error = task.error {
print("Upload failed with error: (\(error.localizedDescription))")
}
if task.result != nil {
let s3URL = URL(string: "https://s3-ap-southeast-1.amazonaws.com/bucket/\(imageAWSName)")!
print("Uploaded to:\(s3URL)")
}
return nil
})
dismiss(animated:true, completion: nil) //5
}
I have seen lot of blogs such as this and this but these are in earlier versions of swift and I am unable to convert it in Swift 3 and combine imagepicker with AWS properly.
Someone please help.
I found a solution to my problem:
let imageAWSName = "ios_" + NSUUID().uuidString + ".jpg"
let image = info[UIImagePickerControllerOriginalImage] as! UIImage
let documentDirectory = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first!
let photoURL = NSURL(fileURLWithPath: documentDirectory)
let localPath = photoURL.appendingPathComponent(imageAWSName)
if !FileManager.default.fileExists(atPath: localPath!.path) {
do {
try UIImageJPEGRepresentation(image, 1.0)?.write(to: localPath!)
print("file saved")
}catch {
print("error saving file")
}
}
else {
print("file already exists")
}
let credentialProvider = AWSCognitoCredentialsProvider(regionType: .USEast1, identityPoolId: “your identity pool id”)
let configuration = AWSServiceConfiguration(region: .APSoutheast1, credentialsProvider: credentialProvider)
AWSServiceManager.default().defaultServiceConfiguration = configuration
let transferManager = AWSS3TransferManager.default()
let uploadRequest = AWSS3TransferManagerUploadRequest()!
let yourBucketName = “your bucket name”
uploadRequest.bucket = yourBucketName
uploadRequest.key = imageAWSName
uploadRequest.body = localPath! as URL
uploadRequest.contentType = "image/jpg"
uploadRequest.uploadProgress = { (bytesSent, totalBytesSent, totalBytesExpectedToSend) -> Void in
DispatchQueue.main.async(execute: {
//self.amountUploaded = totalBytesSent // To show the updating data status in label.
//self.fileSize = totalBytesExpectedToSend
print("progress : \(totalBytesSent)/\(totalBytesExpectedToSend)")
})
}
transferManager.upload(uploadRequest).continueWith(executor: AWSExecutor.mainThread(), block: { (task:AWSTask<AnyObject>) -> Any? in
if let error = task.error {
print("Upload failed with error: (\(error.localizedDescription))")
}
if task.result != nil {
let s3URL = URL(string: "https://s3-ap-southeast-1.amazonaws.com/\(yourBucketName)/\(imageAWSName)")!
print("Uploaded to:\(s3URL)")
}
return nil
})
self.picker.dismiss(animated: true, completion: nil)
Make sure the imageAWSName used in localPath is always different as I have done. That is the main thing otherwise AWS will save same image multiple times even though you pick different images from picker.
Hope it helps someone in future!
Actually, when you are doing this:
let photoURL = NSURL(fileURLWithPath: documentDirectory)
let localPath = photoURL.appendingPathComponent(imageName!)
you are creating localPath as URL.
So when you are doing:
let imageURL = NSURL(fileURLWithPath: localPath)
It's giving error, because localPath is URL not String.
Here you can directly using as:
let imageURL = localPath!
Related
I am trying to use the AWS S3 bucket to store user photos from when they have taken them from their phones. I right now have my code set up to the point where the user is able to take a photo of something and have that show up on the UIImageView.
The issue I am encountering is that I have no clue how to store it on the S3 bucket, I have code right now that is able to store a specified photo the bucket, but not really code that is able to store a photo that is taken from the camera.
Take Photo code
#IBAction func takePhoto(_ sender: Any) {
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerController.SourceType.camera) {
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = UIImagePickerController.SourceType.camera
imagePicker.allowsEditing = false
self.present(imagePicker, animated: true, completion: nil)
}
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let pickedImage = info[UIImagePickerController.InfoKey.originalImage] as? UIImage {
takenPhoto.contentMode = .scaleToFill
takenPhoto.image = pickedImage
print(takenPhoto.image = pickedImage)
}
picker.dismiss(animated: true, completion: nil)
}
AWS S3 Bucket Code
#IBAction func uploadFile(_ sender: Any) {
uploadFile(with: "eartj", type: ".jpeg")
}
func uploadFile(with resource: String, type: String){
let key = "\(resource),\(type)"
let imagePath = Bundle.main.path(forResource: resource, ofType: type)!
let imageUrl = URL(fileURLWithPath: imagePath)
let request = AWSS3TransferManagerUploadRequest()!
request.bucket = "wuuurktest"
request.key = key
request.body = imageUrl
request.acl = .publicReadWrite
let transferManager = AWSS3TransferManager.default()
transferManager.upload(request).continueWith(executor: AWSExecutor.mainThread()) { (task) -> Any? in
if let error = task.error {
print(error)
}
if task.result != nil {
print("Uploaded File")
}
return nil
}
}
Link to the guide I am using to create the file upload
https://www.youtube.com/watch?v=UMgApUhg7ic
Most of the answers are outdated and too complicated. I was struggling with the same problem and finally found a solution.
This works best for me and works on Swift 5.
First of all, let's update the function to upload images to AWS.
func uploadToS3(url: URL) {
let fileArr = url.path.components(separatedBy: "/") // Path will be too long, so you have to separate the elements by / and store in an array
let key = fileArr.last // We get the last element of the array which in our case will be the image (my-image.jpg)
let localImageUrl = url
let request = AWSS3TransferManagerUploadRequest()!
request.bucket = bucketName
request.key = key
request.body = localImageUrl
request.acl = .publicReadWrite
let transferManager = AWSS3TransferManager.default()
transferManager.upload(request).continueWith(executor: AWSExecutor.mainThread()) { (task) -> Any? in
if let error = task.error {
print(error)
}
if task.result != nil {
print("Uploaded \(key)")
let contentUrl = self.s3Url.appendingPathComponent(bucketName).appendingPathComponent(key!)
self.contentUrl = contentUrl
}
return nil
}
}
In this block of code:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let pickedImage = info[UIImagePickerController.InfoKey.originalImage] as? UIImage {
takenPhoto.contentMode = .scaleToFill
takenPhoto.image = pickedImage
print(takenPhoto.image = pickedImage)
// Add here:
let url = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true)
.appendingPathComponent("my-image", isDirectory: false)
.appendingPathExtension("jpg") /* here we are naming the image 'my-image' and it will be 'jpg', if you want you can add a counter to increase the number each time you upload an image, and you make something like this: "my-image-\(counter)"*/
// Then write to disk
if let data = pickedImage.jpegData(compressionQuality: 0.8) {
do {
try data.write(to: url)
uploadToS3(url: url) //Call the updated function to store to AWS bucket
} catch {
print("Handle the error, i.e. disk can be full")
}
}
}
picker.dismiss(animated: true, completion: nil)
}
With this implementation, the image will be uploaded immediately to the server once you select the image from the library.
First thing you need to do is to store the picked image in your app's document directory as a temporary file. As soon as your image is picked, save it to the document directory using the below function.
func saveFileToDocumentDirectory(file: Data, fileExtension: String, folderName: String) -> URL? {
let formatter = DateFormatter()
formatter.dateFormat = "yyyyMMdd_HHmmss"
let stringOfDateTimeStamp = formatter.string(from: Date())
print("Date time stamp String: \(stringOfDateTimeStamp)")
let directoryPath = (NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString).appendingPathComponent("\(folderName)/")
if !FileManager.default.fileExists(atPath: directoryPath) {
do {
try FileManager.default.createDirectory(at: NSURL.fileURL(withPath: directoryPath), withIntermediateDirectories: true, attributes: nil)
} catch {
print(error)
}
}
let filename = "/\(stringOfDateTimeStamp)_\(fileExtension)"
let customPath = "\(folderName)\(filename)"
let filepath = directoryPath+filename
print("FilePATH: \(filepath)")
let url = NSURL.fileURL(withPath: filepath)
do {
try file.write(to: url, options: .atomic)
print("CustomPAth:\(customPath)")
print(String.init("\(directoryPath)\(filename)"))
return url
} catch {
print(error)
print("file cant not be save at path \(filepath), with error : \(error)");
return nil
}
}
This will return a URL and you can then use the below function to upload that file to your S3 bucket.
func uploadToS3(url: URL, contentType: String, fileExtension: String){
SwiftLoader.show(title: "Uploading File", animated: true)
let accessKey = "YOUR_ACCESS_KEY"
let secretKey = "YOUR_SECRET_KEY"
let credentialsProvider = AWSStaticCredentialsProvider(accessKey: accessKey, secretKey: secretKey)
let configuration = AWSServiceConfiguration(region: .USWest2, credentialsProvider: credentialsProvider)
AWSServiceManager.default().defaultServiceConfiguration = configuration
let remoteName = "IMG_\(UUID().uuidString)"+".\(fileExtension)"
let S3BucketName = "YOUR_BUCKET_NAME"
let uploadRequest = AWSS3TransferManagerUploadRequest()!
uploadRequest.body = url
uploadRequest.key = remoteName
uploadRequest.bucket = S3BucketName
uploadRequest.contentType = contentType
uploadRequest.acl = .publicRead
let transferManager = AWSS3TransferManager.default()
transferManager.upload(uploadRequest).continueWith(block: { (task: AWSTask) -> Any? in
if let error = task.error {
print("Upload failed with error: (\(error.localizedDescription))")
DispatchQueue.main.async {
print("An error occurred while Uploading your file, try again.")
SwiftLoader.hide()
}
}
if task.result != nil {
let url = AWSS3.default().configuration.endpoint.url
let publicURL = url?.appendingPathComponent(uploadRequest.bucket!).appendingPathComponent(uploadRequest.key!)
print("Uploaded to:\(String(describing: publicURL))")
}
return nil
})
}
Don't forget to delete your temporary file once your upload is successful.
Here is an example using TransferUtility:-
import AWSCognitoIdentityProvider
import AWSS3
typealias progressBlock = (_ progress: Double) -> Void
typealias completionBlock = (_ response: Any?, _ error: Error?) -> Void
//using Utility upload expression
func uploadImage(with image: URL, key: String?, progress: progressBlock?, completion: completionBlock?) {
let expression = AWSS3TransferUtilityUploadExpression()
expression.progressBlock = { (task: AWSS3TransferUtilityTask, awsProgress: Progress) -> Void in
//print(awsProgress.fractionCompleted)
guard let uploadProgress = progress else { return }
DispatchQueue.main.async {
uploadProgress(awsProgress.fractionCompleted)
}
}
expression.setValue("public-read-write", forRequestHeader: "x-amz-acl")
expression.setValue("public-read-write", forRequestParameter: "x-amz-acl")
// Completion block
var completionHandler: AWSS3TransferUtilityUploadCompletionHandlerBlock?
completionHandler = { (task, error) -> Void in
DispatchQueue.main.async(execute: {
if error == nil {
let url = AWSS3.default().configuration.endpoint.url
let publicURL = url?.appendingPathComponent(AWS.bucketName).appendingPathComponent(key!)
print("Uploaded to:\(String(describing: publicURL))")
if let completionBlock = completion {
completionBlock(publicURL?.absoluteString, nil)
}
} else {
if let completionBlock = completion {
completionBlock(nil, error)
}
}
})
}
// Start uploading using AWSS3TransferUtility
let awsTransferUtility = AWSS3TransferUtility.default()
awsTransferUtility.uploadFile(
image as URL,
bucket: AWS.bucketName, //Make sure you write the correct bucket name here
key: key!, //"private/{user_identity_id}/my-picture.png"
contentType: "image/png",
expression: expression,
completionHandler: completionHandler).continueWith(block: { (task) -> Any? in
if let error = task.error {
print("error is: \(error.localizedDescription)")
}
if let _ = task.result {
// your uploadTask
print("Starting upload...")
}
return nil
})
}
Two parameters I am passing:-
image: URL and key: String?
Here is how I get image and image name (key):-
//setting temp name for upload // I am using a random string here
let imageName = "\(CommonMethod.randomString(length: 6))" + ".png"
//settings temp location for image
let tempDirectoryUrl = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(imageName)
guard let localUrlPath = image!.save(at: tempDirectoryUrl) else { return }
//URL
print(localUrlPath)
Happy coding!
I just want to upload an image to S3, but I am using AWS Educate Account and I'm trying since 4 hours to get this done and have ZERO ideas what isn't working correctly.
So I've set up everything on the AWS console and the bucket is public to EVERYONE + Region US West N.Virginia like it should be with AWS Educate Accounts.
So here is my code:
let accessKey = "accessKey"
let secretKey = "secretKey"
let credentialsProvider = AWSStaticCredentialsProvider(accessKey: accessKey, secretKey: secretKey)
let configuration = AWSServiceConfiguration(region: AWSRegionType.USEast1, credentialsProvider: credentialsProvider)
AWSServiceManager.default().defaultServiceConfiguration = configuration
let transferUtility = AWSS3TransferUtility.default()
let bucketname = "bucketname"
let expression = AWSS3TransferUtilityUploadExpression()
transferUtility.uploadData(jpegData, bucket: bucketname, key: "myTransferUtilityUpload.jpg", contentType: "image/jpg", expression: expression) { (task, error) in
if let error = error {
print(error.localizedDescription)
}
if let response = task.response {
print(response)
}
}
Can anyone tell me what I do wrong?
I get this error message:
The operation couldn’t be completed.
(com.amazonaws.AWSS3TransferUtilityErrorDomain error 2.)
accessKey + secretKey I got from Account Details + AWS CLI on the 'Welcome to AWS Educate Starter Account' Dashboard and obviously the bucket name is the same name like in my console
EDIT:
if let jpegData = image.jpegData(compressionQuality: 0.7) {
let fileManager = FileManager.default
if let documentDirectory = fileManager.urls(for: .documentDirectory,
in: .userDomainMask).first {
var sourceFolderURL = documentDirectory.appendingPathComponent("image.jpg")
do {
try jpegData.write(to: sourceFolderURL)
} catch {
print(error.localizedDescription)
completionHandler(nil)
return
}
let accessKey = "-"
let secretKey = "-"
let bucketname = "-"
let credentialsProvider = AWSStaticCredentialsProvider(accessKey: accessKey, secretKey: secretKey)
let configuration = AWSServiceConfiguration(region: AWSRegionType.USEast1, credentialsProvider: credentialsProvider)
AWSServiceManager.default().defaultServiceConfiguration = configuration
let uploadRequest = AWSS3TransferManagerUploadRequest()!
uploadRequest.body = sourceFolderURL
uploadRequest.key = "image.jpg"
uploadRequest.bucket = bucketname
uploadRequest.contentType = "image/jpeg"
uploadRequest.acl = .publicReadWrite
let transferManager = AWSS3TransferManager.default()
transferManager.upload(uploadRequest).continueWith { [weak self] (task) -> Any? in
if let error = task.error {
print("Upload failed with error: (\(error.localizedDescription))")
completionHandler(nil)
return nil
}
if task.result != nil {
let url = AWSS3.default().configuration.endpoint.url
let publicURL = url?.appendingPathComponent(uploadRequest.bucket!).appendingPathComponent(uploadRequest.key!)
if let absoluteString = publicURL?.absoluteString {
print("Uploaded to:\(absoluteString)")
completionHandler(nil)
}
}
completionHandler(nil)
return nil
}
}
}
I have uploaded an image to S3 bucket with the following code:
First, save the image to a temporary directory.
func uploadImageToS3(imageName:String, completion:#escaping (Bool) -> Void) {
let accessKey = "accessKey"
let secretKey = "secretKey"
let credentialsProvider = AWSStaticCredentialsProvider(accessKey: accessKey, secretKey: secretKey)
let configuration = AWSServiceConfiguration(region:AWSRegionType.APSoutheast2, credentialsProvider:credentialsProvider)
AWSServiceManager.default().defaultServiceConfiguration = configuration
let S3BucketName = "bucketname"
let uploadRequest = AWSS3TransferManagerUploadRequest()!
uploadRequest.body = self.getImageURLWithName(imageName:imageName)
uploadRequest.key = "\(imageName)"
uploadRequest.bucket = S3BucketName
uploadRequest.contentType = "image/jpeg"
//You can specify private or public here
uploadRequest.acl = .private
let transferManager = AWSS3TransferManager.default()
transferManager.upload(uploadRequest).continueWith { [weak self] (task) -> Any? in
ProgressIndicatorHelper.hideGlobalHUD()
if let error = task.error {
print("Upload failed with error: (\(error.localizedDescription))")
completion(false)
}
if task.result != nil {
let url = AWSS3.default().configuration.endpoint.url
let publicURL = url?.appendingPathComponent(uploadRequest.bucket!).appendingPathComponent(uploadRequest.key!)
if let absoluteString = publicURL?.absoluteString {
print("Uploaded to:\(absoluteString)")
completion(true)
}
}
return nil
}
}
For getting image from Path following code I have used:
func getImageURLWithName(imageName:String) -> URL {
var sourceImageURL: URL!
let fileManager = FileManager.default
if let documentDirectory = fileManager.urls(for: .documentDirectory,
in: .userDomainMask).first {
var sourceFolderURL:URL!
sourceFolderURL = documentDirectory.appendingPathComponent("YourTempFolder")
sourceImageURL = sourceFolderURL.appendingPathComponent(imageName)
}
return sourceImageURL
}
Hope this helps.
Moreover: Right now I don't think you can directly upload image from memory.
I searched for it. Following are links for same:
https://github.com/aws-amplify/aws-sdk-ios/issues/42
How to upload a UIImage to S3 with AWS iOS SDK v2
Let me know if you find any error.
Maybe it's a policy issue?
Try attaching this policy to your bucket (bucket policies)
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:*"
],
"Resource": [
"arn:aws:s3:::mybucketname/*"
]
}
]
}
I feel like I am missing something major as I don't receive any errors or null values, but anytime I try to retrieve my image it returns "" because it doesn't exist?
This is how I am passing the image data:
URLSession.shared.dataTask(with: url! as URL, completionHandler:{ (data, response, error) in
//if download error
if error != nil{
print(error!)
return
}
guard let imageData = UIImage(data: data!) else { return }
DispatchQueue.main.async{
self.imgPortrait.image = imageData
ImagePortrait().saveImageDocumentDirectory(image: imageData)
}
The data is displayed on imgPortrait completely fine. Here are the rest of the functions where: /\(userUID)/\(CharacterSelection.sharedInstance.getActiveCharacterName()) is optional. When it goes to retrieve the image and when it saves it I can confirm the paths are exactly the same. I feel like it's how I am saving the image with createFile, but I am unsure.
func saveImageDocumentDirectory(image: UIImage){
if let userUID = Auth.auth().currentUser?.uid{
let fileManager = FileManager.default
let paths = (getDirectoryPath() as NSString).appendingPathComponent("/\(userUID)/\(CharacterSelection.sharedInstance.getActiveCharacterName())/characterPortrait.png")
createDirectory(name: (getDirectoryPath() as NSString) as String)
let imageData = UIImagePNGRepresentation(image)
fileManager.createFile(atPath: paths as String, contents: imageData, attributes: nil)
}
}
func getDirectoryPath() -> String {
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
let documentsDirectory = paths[0]
return documentsDirectory
}
func getImage() -> String{
if let userUID = Auth.auth().currentUser?.uid{
let fileManager = FileManager.default
let imagePath = (self.getDirectoryPath() as NSString).appendingPathComponent("/\(userUID)/\(CharacterSelection.sharedInstance.getActiveCharacterName())/characterPortrait.png")
if fileManager.fileExists(atPath: imagePath){
return imagePath
}else{
print("No Image")
return ""
}
}
else{
return ""
}
}
func createDirectory(name: String){
let fileManager = FileManager.default
let paths = (getDirectoryPath() as NSString).appendingPathComponent(name)
if !fileManager.fileExists(atPath: paths){
try! fileManager.createDirectory(atPath: paths, withIntermediateDirectories: true, attributes: nil)
}else{
print("Directory is already created.")
}
}
Thanks in advance!
Well after a few hours I figured it out. Looks like the directory wasn't being created. Solved it by:
func saveImageDocumentDirectory(image: UIImage){
if let userUID = Auth.auth().currentUser?.uid{
let fileURL = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true).appendingPathComponent("\(userUID)_\(CharacterSelection.sharedInstance.getActiveCharacterName())_characterPortrait.png")
do {
try UIImagePNGRepresentation(image)?.write(to: fileURL, options: .atomic)
} catch {
print(error)
}
}
}
func getImage() -> UIImage{
if let userUID = Auth.auth().currentUser?.uid{
let nsDocumentDirectory = FileManager.SearchPathDirectory.documentDirectory
let nsUserDomainMask = FileManager.SearchPathDomainMask.userDomainMask
let paths = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory, nsUserDomainMask, true)
if let dirPath = paths.first
{
let imageURL = URL(fileURLWithPath: dirPath).appendingPathComponent("\(userUID)_\(CharacterSelection.sharedInstance.getActiveCharacterName())_characterPortrait.png")
if let image = UIImage(contentsOfFile: imageURL.path){
return image
}
else{
print("Image isn't found.")
return UIImage(named: "default_portrait.png")!
}
}
else{
print("Image isn't found.")
return UIImage(named: "default_portrait.png")!
}
}
else{
print("Image isn't found.")
return UIImage(named: "default_portrait.png")!
}
}
I'm trying to upload an image to a bucket. The connection is made, the upload apparently starts but does not progress. The permissions on the server I consider to be correct, because an android app is able to upload.
In my appdelegate I have this:
let credentialsProvider = AWSCognitoCredentialsProvider(regionType: AWSRegionType.USEast1, identityPoolId: "us-east-1:XXXXXX-XXXX-XXXX-XXXX-XXXX”, unauthRoleArn: "arn:aws:iam::XXXXX:role/Cognito_mybucketUnauth_Role", authRoleArn: "arn:aws:iam::XXXXX:role/Cognito_mybucketAuth_Role", identityProviderManager: nil)
let configuration = AWSServiceConfiguration(region: AWSRegionType.USEast1, credentialsProvider: credentialsProvider)
AWSServiceManager.defaultServiceManager().defaultServiceConfiguration = configuration
And this to get the image and upload
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]){
//getting details of image
let uploadFileURL = info[UIImagePickerControllerReferenceURL] as! NSURL
let imageName = uploadFileURL.lastPathComponent
let documentDirectory = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true).first! as String
// getting local path
let localPath = (documentDirectory as NSString).stringByAppendingPathComponent(imageName!)
//getting actual image
let image = info[UIImagePickerControllerOriginalImage] as! UIImage
let data = UIImagePNGRepresentation(image)
data!.writeToFile(localPath, atomically: true)
let imageData = NSData(contentsOfFile: localPath)!
imageURL = NSURL(fileURLWithPath: localPath)
CampoImagem.image = image
picker.dismissViewControllerAnimated(true, completion: nil)
uploadImage()
}
func uploadImage(){
//defining bucket and upload file name
let S3BucketName: String = “mybucket"
let S3UploadKeyName: String = "profile/testImage.jpg"
let expression = AWSS3TransferUtilityUploadExpression()
/*expression.uploadProgress = {(task: AWSS3TransferUtilityTask, bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64) in
dispatch_async(dispatch_get_main_queue(), {
let progress = Float(totalBytesSent) / Float(totalBytesExpectedToSend)
print("Progress is: \(progress)")
})
}*/
self.uploadCompletionHandler = { (task, error) -> Void in
dispatch_async(dispatch_get_main_queue(), {
if ((error) != nil){
print("Failed with error")
print("Error: \(error!)");
}
else{
print("Sucess")
}
})
}
let transferUtility = AWSS3TransferUtility.defaultS3TransferUtility()
transferUtility.uploadFile(imageURL, bucket: S3BucketName, key: S3UploadKeyName, contentType: "image/jpeg", expression: expression, completionHander: uploadCompletionHandler).continueWithBlock { (task) -> AnyObject! in
if let error = task.error {
print("Error: \(error.localizedDescription)")
}
if let exception = task.exception {
print("Exception: \(exception.description)")
}
if let _ = task.result {
print("Upload Starting!")
}
return nil;
}
}
Print: Upload Starting!
I suspect it's something when ID and permission to complete the upload with aws, but I think if it was the upload would not start, correct?
How can I solve this?
Please check this code you can also check by adding credentials in this demo project
https://github.com/awslabs/aws-sdk-ios-samples/blob/master/S3TransferUtility-Sample/Swift/S3BackgroundTransferSampleSwift/FirstViewController.swift
In my app I am storing an image in local storage and I am saving the path of that image in my database. How can I load the image from that path?
Here is the code I am using in order to save the image:
let myimage : UIImage = UIImage(data: data)!
let fileManager = NSFileManager.defaultManager()
let urls = fileManager.URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)
let documentDirectory = urls[0] as NSURL
print(documentDirectory)
let currentDate = NSDate()
let dateFormatter = NSDateFormatter()
dateFormatter.dateStyle = .NoStyle
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let convertedDate = dateFormatter.stringFromDate(currentDate)
let imageURL = documentDirectory.URLByAppendingPathComponent(convertedDate)
imageUrlPath = imageURL.absoluteString
print(imageUrlPath)
UIImageJPEGRepresentation(myimage,1.0)!.writeToFile(imageUrlPath, atomically: true)
And this is the path where my image stored
file:///var/mobile/Containers/Data/Application/B2A1EE50-D800-4BB0-B475-6C7F210C913C/Documents/2016-06-01%2021:49:32
This is how i tried to retrieve the image but it's not displaying anything.
let image : String = person?.valueForKey("image_local_path") as! String
print(person!.valueForKey("image_local_path")! as! String)
cell.img_message_music.image = UIImage(contentsOfFile: image)
Folder /B2A1EE50- ... changes every time you run application.
../Application/B2A1EE50-D800-4BB0-B475-6C7F210C913C/Documents/..
Which works for me is to store fileName and get documents folder.
Swift 5
Create getter for directory folder
var documentsUrl: URL {
return FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
}
Save image :
private func save(image: UIImage) -> String? {
let fileName = "FileName"
let fileURL = documentsUrl.appendingPathComponent(fileName)
if let imageData = image.jpegData(compressionQuality: 1.0) {
try? imageData.write(to: fileURL, options: .atomic)
return fileName // ----> Save fileName
}
print("Error saving image")
return nil
}
Load image :
private func load(fileName: String) -> UIImage? {
let fileURL = documentsUrl.appendingPathComponent(fileName)
do {
let imageData = try Data(contentsOf: fileURL)
return UIImage(data: imageData)
} catch {
print("Error loading image : \(error)")
}
return nil
}
Also you can try this.
Check if your path exist
if NSFileManager.defaultManager().fileExistsAtPath(imageUrlPath) {}
Create an URL to your path
let url = NSURL(string: imageUrlPath)
Create data to you URL
let data = NSData(contentsOfURL: url!)
Bind the url to your imageView
imageView.image = UIImage(data: data!)
Final code:
if NSFileManager.defaultManager().fileExistsAtPath(imageUrlPath) {
let url = NSURL(string: imageUrlPath)
let data = NSData(contentsOfURL: url!)
imageView.image = UIImage(data: data!)
}
This code works for me
func getImageFromDir(_ imageName: String) -> UIImage? {
if let documentsUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {
let fileURL = documentsUrl.appendingPathComponent(imageName)
do {
let imageData = try Data(contentsOf: fileURL)
return UIImage(data: imageData)
} catch {
print("Not able to load image")
}
}
return nil
}
Swift 4:
if FileManager.default.fileExists(atPath: imageUrlPath) {
let url = NSURL(string: imageUrlPath)
let data = NSData(contentsOf: url! as URL)
chapterImage.image = UIImage(data: data! as Data)
}
Replace absoluteString with path
let myimage : UIImage = UIImage(data: data)!
let fileManager = NSFileManager.defaultManager()
let urls = fileManager.URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)
let documentDirectory = urls[0] as NSURL
print(documentDirectory)
let currentDate = NSDate()
let dateFormatter = NSDateFormatter()
dateFormatter.dateStyle = .NoStyle
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let convertedDate = dateFormatter.stringFromDate(currentDate)
let imageURL = documentDirectory.URLByAppendingPathComponent(convertedDate)
imageUrlPath = imageURL.path
print(imageUrlPath)
UIImageJPEGRepresentation(myimage,1.0)!.writeToFile(imageUrlPath, atomically: true)
This sample code may save someone some typing,
write an UIImage to disk in your own directory:
IM = UIImage, your image. for example, IM = someUIView.image or from the camera
let newPhotoFileName = randomNameString() + ".jpeg"
let imagePath = checkedImageDirectoryStringPath() + "/" + newPhotoFileName
let imData = UIImageJPEGRepresentation(IM, 0.20)
FileManager.default.createFile(atPath: imagePath, contents: imData, attributes: nil)
print("saved at filename \(newPhotoFileName)")
later to read that image ...
.. and convert it back to a UIImage as in a UIImageView
NAME = that filename, like jahgfdfs.jpg
let p = checkedImageDirectoryStringPath() + "/" + NAME
devCheckExists(fullPath: p)
var imageData: Data? = nil
do {
let u = URL(fileURLWithPath: p)
imageData = try Data(contentsOf: u)
}
catch {
print("catastrophe loading file?? \(error)")
return
}
// and then to "make that an image again"...
imageData != nil {
picture.image = UIImage(data: imageData!)
print("that seemed to work")
}
else {
print("the imageData is nil?")
}
// or for example...
Alamofire.upload(
multipartFormData: { (multipartFormData) in
multipartFormData.append(imageData!,
withName: "file", fileName: "", mimeType: "image/jpeg")
...
Here are the extremely handy functions used above...
func checkedImageDirectoryStringPath()->String {
// create/check OUR OWN IMAGE DIRECTORY for use of this app.
let paths = NSSearchPathForDirectoriesInDomains(
.documentDirectory, .userDomainMask, true)
if paths.count < 1 {
print("some sort of disaster finding the our Image Directory - giving up")
return "x"
// any return will lead to disaster, so just do that
// (it will then gracefully fail when you "try" to write etc)
}
let docDirPath: String = paths.first!
let ourDirectoryPath = docDirPath.appending("/YourCompanyName")
// so simply makes a directory called "YourCompanyName"
// which will be there for all time, for your use
var ocb: ObjCBool = true
let exists = FileManager.default.fileExists(
atPath: ourDirectoryPath, isDirectory: &ocb)
if !exists {
do {
try FileManager.default.createDirectory(
atPath: ourDirectoryPath,
withIntermediateDirectories: false,
attributes: nil)
print("we did create our Image Directory, for the first time.")
// never need to again
return ourDirectoryPath
}
catch {
print(error.localizedDescription)
print("disaster trying to make our Image Directory?")
return "x"
// any return will lead to disaster, so just do that
}
}
else {
// already exists, as usual.
return ourDirectoryPath
}
}
and
func randomNameString(length: Int = 7)->String{
enum s {
static let c = Array("abcdefghjklmnpqrstuvwxyz12345789".characters)
static let k = UInt32(c.count)
}
var result = [Character](repeating: "a", count: length)
for i in 0..<length {
let r = Int(arc4random_uniform(s.k))
result[i] = s.c[r]
}
return String(result)
}
and
func devCheckExists(fullPath: String) {
var ocb: ObjCBool = false
let itExists = FileManager.default.fileExists(atPath: fullPath, isDirectory: &ocb)
if !itExists {
// alert developer. processes will fail at next step
print("\n\nDOES NOT EXIST\n\(fullPath)\n\n")
}
}
This is working for me and I think is a fast and clean way to do it.
Swift 5.0
let fileManager = NSFileManager.defaultManager()
let urls = fileManager.URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)
let documentDirectory = urls[0] as NSURL
print(documentDirectory)
let currentDate = NSDate()
let dateFormatter = NSDateFormatter()
dateFormatter.dateStyle = .NoStyle
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let convertedDate = dateFormatter.stringFromDate(currentDate)
let imageURL = documentDirectory.URLByAppendingPathComponent(convertedDate)
let imageData = try? Data(contentsOf: imageUrl)
let image = UIImage(data: imageData!)
Where "imageUrl" is the value of your imageURL from documents folder. And "image" is the resulting image you can use anywhere you need.
1.cell.image.sd_setShowActivityIndicatorView(true)
2.cell.image.sd_setIndicatorStyle(.gray)
3.cell.image.image = UIImage(contentsOfFile: urlString!)