Downloading image from Amazon S3 (using AWS mobile hub helper) - ios

I'm trying to download an image called "aaa.jpeg" in my s3 bucket using AWSMobileHubHelper. I found this function on their documentation site.
func downloadContent(content: AWSContent, pinOnCompletion: Bool) {
content.downloadWithDownloadType( .Always, pinOnCompletion: pinOnCompletion, progressBlock: {(content: AWSContent?, progress: NSProgress?) -> Void in
// Handle progress feedback
}, completionHandler: {(content: AWSContent?, data: NSData?, error: NSError?) -> Void in
if let error = error {
print("Failed to download a content from a server.)")
// Handle error here
return
}
// Handle successful download here
if let image = UIImage(data: data!){
self.imageView = image
}
})
}
Once the download is successful (it Did, There is no error message), I'm trying to assign the image to an imageView.
I can tell that the data has been downloaded successfully. I can print the data and see a familiar binary structure of an image. But for some reasons I can't assign the UIImage to the imageView. Because I can't convert the data to a UIImage.
I just want to know if this is the proper way to download image from s3 or am I missing something. Does "data" in the completion block carry the downloaded image? I can't seem to find any documentations on this.
Is this the correct function to use to download from S3?

Yes, the data contains the actual image data. You can put the downloaded data in an UIImageViewController and it should open up fine. Also, this is demonstrated in a Sample App which can be downloaded from the Mobile Hub Console.

Related

How to know if the file I'm uploading to firebase is done uploading?

I'm using firebase with swift.
Below is my code to upload an image from an image picker, and to store the download url of the image.
the point of my code is to store the download url after uploading the image. So I'm trying to find a way to wait for the upload process to finish in order to proceed.
_ = imageRef.putData(data, metadata: nil, completion: {(metadata,error) in
guard let metadata = metadata
else{
print(error)
return
}
})
imageRef.downloadURL { (URL, error) -> Void in
if (error != nil) {
// Handle any errors
} else {
// Get the download URL for 'images/stars.jpg'
let UrlString = URL?.absoluteString}
That's what the completion handler is for. You're already passing a completion handler to putData, which will be invoked when the upload is finished. You should check the error object to make sure it completed successfully.
This is documented, along with a code sample. You can see in the sample that the download URL is fetched from inside the completion handler, only if there is no error.

Retrieve images from a DJI Drone with EXIF data

I'm using the DJISDK in iOS to download pictures from the aircraft.
I'm using the downloadSelectedFiles method from PlaybackManager class.
Here is my process callback:
process: { (data, error) in
if data != nil{
if self.downloadedImageData != nil{
self.downloadedImageData!.append(data!)
}else{
self.downloadedImageData = data!
}
}
}
And this is filecompletition callback:
fileCompletion: {
self.downloadedFilesCount += 1
let image = UIImage(data: self.downloadedImageData!)
if let img = image {
self.downloadedImagesArray?.append(img)
}
self.downloadedImageData = nil
}
I'm correctly retrieving the image but without the EXIF data. How can I get that info and add it to the image?
I already downloaded and tried the iOS-MediaManagerDemo and it's the same thing, downloads the image but without the exif data but the official DJI Go app retrieves all the info so there´s must be some way to do it.
There's also a similar issue in their forums regarding empty metadata and downloadSelectedFilesWithPreparation. The user that created the post
also found a solution:
I solved the problem by not converting the NSData into any format instead saved the NSData directly. Using PHAssets and temporary file to store the NSData as PHAssets only accepts data from URL.
Try using fetchFileDataWithOffset:updateQueue:updateBlock (it will be called fetchFileData(with:updateQueue:updateBlock) in Swift)
[...] fetching the media data will return all data for a video or image
Sample code (objc): here

Error Domain=NSCocoaErrorDomain Code=256 "The file “images” couldn’t be opened." UserInfo={NSURL=http://

func loadCell(personObj:Person){
self.lblTitle.text = personObj.title
self.lblDesc.text = personObj.desc
print("ImgUrlInCell:", personObj.imageUrl)
do {
self.imgPicture.image = try UIImage(data:NSData(contentsOf:NSURL(string: personObj.imageUrl) as! URL) as Data)
} catch {
print("Error:",error)
}
}
Firstly, I've parsed data from API and put it in object and then insert it into database. At the time of displaying data I fetched them from database and list them in Tableview.
If there is an internet connection everything is working fine
If there is no internet connection image url doesn't work, It prints error 6 times. (I have 10 images in database or API)
Also, There are 10 image url displaying in console in ImgUrlInCell:
Please someone help me with this issue. What have I wronged.
You are using TableView and in TableView as per screen size and Cell size, it will show max cell in your screens so it may be possible that in your case its loading 6 cells data and all 6 cells have load image method so its throwing error 6 times.
To load Images lazily there are many famous libraries which will manage single time download and cache that image.
SDWebImage is one of the best libraries fits for your problem.
Link : SDWebImage
And follow below code to get Image from the server.
Swift:
import SDWebImage
imageView.sd_setImage(with: URL(string: "http://www.example.com/path/to/image.jpg"), placeholderImage: UIImage(named: "placeholder.png"))
Put an above line of code in your loadCell method with your imageURL.
Please check Internet connection by using Apple Reachability classes and load your image if the Internet connection is there.
Edit:
For Locally storing image you can use below function of SDWebImage Downloader and cache your image before showing it to the user.
SDWebImageManager.shared().imageDownloader?.downloadImage(with: NSURL(string: strURL) as URL!, options: SDWebImageDownloaderOptions.continueInBackground, progress: {
(receivedSize, ExpectedSize, imageURL) in
print("receive:",receivedSize,"Expected:",ExpectedSize,"Image URL:",imageURL ?? "No URL")
}, completed: {
(image, data, error, finished) in
print("Image Data:",data ?? "No Data")
// Do your stuff to store downloaded image
})
Link : Reachability Sample
Hope this will helps.

how can I get the data of cached images SDWebImage

I'm using SDWebImage library to cache web images in my UICollectionView:
cell.packItemImage.sd_setImage(with: URL(string: smileImageUrl[indexPath.row]))
but I want to save the cached images locally in a file instead of downloading them again
FileManager.default.createFile(atPath: newPath, contents: Data(contentsOf: URL(string: snapchildvalue[Constants.smiles.smileImageUrl] as! String)!), attributes: nil)
is there a way to get the data of cached images
SDWebImage caches downloaded images automatically by default. You can use SDImageCache to retrieve images from the cache. There is a memory cache for the current app session, which will be quicker, and there is the disk cache. Example usage:
if let image = SDImageCache.shared().imageFromDiskCache(forKey: imageURL.absoluteString) {
//use image
}
if let image = SDImageCache.shared().imageFromMemoryCache(forKey: imageURL.absoluteString) {
//use image
}
Also make sure you import SDWebImage in your file. (If you're using Swift/Carthage, it will be import WebImage
SDWebimage chaches image once it is downloaded from a url. Basically it saves image against a url and next time if an image is available for a URL. It will simply get that image from cache. So the below method will be called instantly if the image is already downloaded to device.
imgView.sd_setImage(with: URL(string:url), completed: { (image, error, type, url) in
imgView.image = image
//Do any thing with image here. This will be called instantly after image is downloaded to cache. E.g. if you want to save image (Which is not required for a simple image fetch,
//you can use FileManager.default.createFile(atPath: newPath, contents: UIImagePNGRepresentation(image), attributes: nil)
})
Still if you want to save that image somewhere else or modify it or whatever, you can do it in the completion block above.
SDWebImage already have this kind of caching file locally
Create a SDImageCache with namespace of your choice
Try get the image with imageCache.queryDiskCache
If the image exist, set it to your imageview, if not, use sd_setImage to get the image then save it to the local cache with SDImageCache.shared().store
The key usually to be the image url string
Something like this, might not be correct syntax:
imageCache.queryDiskCache(forKey: urlForImageString().absoluteString, done: {(_ image: UIImage, _ cacheType: SDImageCacheType) -> Void in
if image {
self.imageView.image = image
}
else {
self.imageView.sd_setImage(withURL: urlForImageString(), placeholderImage: UIImage(named: "placeholder")!, completed: {(_ image: UIImage, _ error: Error, _ cacheType: SDImageCacheType, _ imageURL: URL) -> Void in
SDImageCache.shared().store(image, forKey: urlForImageString().absoluteString)
})
}
})

Downloading Images Asynchronously in Sequence

I am trying to download images but it is crucial that the images I download are in a specific order. I am using the following code to download the image:
func downloadImage(url: NSURL, completionHandler: (response: UIImage) -> ()){
print("Started downloading \"\(url.URLByDeletingPathExtension!.lastPathComponent!)\".")
manager.getDataFromUrl(url) { (data, response, error) in
dispatch_async(dispatch_get_main_queue()) { () -> Void in
guard let data = data where error == nil else { return }
print("Finished downloading \"\(url.URLByDeletingPathExtension!.lastPathComponent!)\".")
completionHandler(response: UIImage(data: data)!)
}
}
}
and I am using this code to call downloadImage
self.downloadImage(NSURL(string: self.url)!, completionHandler: { response in
dispatch_async(dispatch_get_main_queue()) {
self.images.append(response)
}
})
The problem is that the images start downloading in the correct order however the response isn't (this is obviously because the size of the images are different and one comes in faster). So what is happening is that all images start downloading, and whichever comes first appends to the images : [UIImage] array. How can I make it so that the images in the images array is in order?
I've also tried to remove the main block when calling downloadImage function
self.downloadImage(NSURL(string: self.url)!, completionHandler: { response in
self.images.append(response)
})
You cannot control the download order in the sense that all the requests to the same server will be pipelined no matter what the order you create the URL objects in. Also, some URLs may be cached while others may need to go to the remote server. What you need to do is maintain a mutable array or dictionary that contains the url to actual data mapping, then wait until all the urls have been completely downloaded and then iterate in a known order.
The simplest method is that you can save every image in Dictionary with their url after downloading. Like var imageData = [String: NSData](). Later you can sort it or use it by keys(url).

Resources