UIImage not loading from AWS S3 url - swift

I'm trying to download an image from a URL but the image doesn't load.
I ported this class from objective-C to swift and this specific part of the code stopped working.
My URL looks like this. Can anybody tell me what am I doing wrong?
https://mydomain-files.s3.amazonaws.com/files/log/773/IMG_20200408_125029.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=mycredentials%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20200413T171303Z&X-Amz-Expires=3600&X-Amz-SignedHeaders=host&X-Amz-Signature=mysignature
cell.previewImageView.sd_setImage(with: url, placeholderImage: UIImage(named: "nodata"), completed: { image, error, cacheType, imageURL in
if image != nil {
cell.previewImageView.image = image
}
})
I have tried using just https://mydomain-files.s3.amazonaws.com/files/log/773/IMG_20200408_125029.jpg this part and it doesn't work either. The image loads fine in Volley for Android and inside the browser.
Error
Error Domain=SDWebImageErrorDomain Code=1001 "Downloaded image has 0 pixels" UserInfo={NSLocalizedDescription=Downloaded image has 0 pixels})
Edit 2:
I have tried adding addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) to the url, it just doesn't work

Obviously, since the image does not load it means that image is nil.
I would advise you to convert your code to the one below and handle errors appropriately:
cell.previewImageView.sd_setImage(with: url, placeholderImage: UIImage(named: "nodata"), completed: { image, error, cacheType, imageURL in
if let error = error {
// Handle errors here
// It may be as simple as forgetting to whitelist S3 url in Info.plist
}
else if image != nil {
cell.previewImageView.image = image
}
})
If there are no errors, check the contents of other variables – they might give you a clue as to what's going wrong.

Related

Image loading taking more time in swift

I am working on an application, where I am loading some images from the server and showing it on table view using Alamofire. But the problem is it is taking so much time to load the image. I want to show the image, like a blurry image until the time image is not loading. Please, someone, help me.
cell.profileImageView?.pin_setImage(from: URL(string: modelArray[indexPath.row]))
This one is the solution using Kingfisher pod. You can set an activity Indicator while image is loaded.
let imageUrl = modelArray[indexPath.row]
//set activity indicator until image is loaded
cell.profileImageView?.kf.indicatorType = .activity
if let url = URL(string: imageUrl) {
let resource = ImageResource(downloadURL: url)
cell.profileImageView?.kf.setImage(with: resource)
}

Re-downloading images with different sizes when using Kingfisher

i have an app that works with API JSON response. Just retrieving a simple array of items. Each item has an url with a high-res image. I'm using Kingfisher to get this images and resize to my ImageView size (that placed on my MainView)
//MainViewController
itemImageMainVC.kf.setImage(
with: URL(string: itemModel.artImage),
options: [
.processor(DownsamplingImageProcessor(size: itemImageMainVC.bounds.size) >> RoundCornerImageProcessor(cornerRadius: 16, targetSize: itemImageMainVC.bounds.size)),
.scaleFactor(UIScreen.main.scale),
.transition(.fade(0.2)),
.cacheOriginalImage
])
Everything is fine here, i've got my images on my MainView inside TableView, and they cached well. BUT! If i try to open and display the same images, but with different sizes on the SecondView, i see the same transition animation on the SecondView, so i guess that they started to download again when they shouldn't.
//SecondViewController
itemImageSecondVC.kf.setImage(
with: URL(string: itemModel.artImage),
options: [
.processor(DownsamplingImageProcessor(size: itemImageSecondVC.bounds.size) >> RoundCornerImageProcessor(cornerRadius: 16, targetSize: itemImageSecondVC.bounds.size)),
.scaleFactor(UIScreen.main.scale),
.transition(.fade(0.2)),
.cacheOriginalImage
])
itemImageMainVC and itemImageSecondVC have different sizes.
What i'm doing wrong? I just want to download/display images on the MainView and instantly show them when i open SecondView, without re-downloading
Lets try to use the cacheKey, it should be the last path component (or event the absoluteUrlString) from your image url or something that is unique.
let resource = ImageResource(downloadURL: url, cacheKey: url.lastPathComponent)
self.imageView.kf.setImage(with: resource, placeholder: UIImage(named: "placeholder-image"), options: nil, progressBlock: nil) { (result) in
switch result {
case .success(_):
// Success case
case .failure(_):
// Failed case
}
}

NSView to PDF and PNG: Why is the outcome so different?

I am trying to safe an NSView to an PNG.
I start with the NSView and then call dataWithPDF or cacheDisplay for PNG. The code to do both looks like this.
guard view.lockFocusIfCanDraw() else {
assert (false)
return
}
let pdfData = view.dataWithPDF(inside: rect)
guard let imgData = view.bitmapImageRepForCachingDisplay(in: rect) else {
assert(false)
}
view.cacheDisplay(in: rect, to: imgData)
view.unlockFocus()
try pdfData.write(to: pdfName, options: .atomic)
let pngData = imgData.representation(using: .png, properties: [:])
try pngData!.write(to: pngName, options: .atomic)
So far, so good. However, this is the different outcome.
PDF (correct!)
And this is the PNG output. As one can see, the subviews aren't included. The arrows are drawn as part of view
Why is the outcome so different?
Many thanks in advance!
Ok, I found the answer. Thanks to "View Debugging" did I see that the subviews use a layer (self.wantsLayer = true). And layers are not finding their way into the PNG, but into the PDF. Not sure whether this is a bug or a feature. However, now I can fix the PNG output.
Why is the outcome so different?
Trying your code using a different (I obviously don't have your view) view with subviews works as expected and the PNG is fine. So it has to be something to do with your views, but I can make no suggestion as to what. However...
As you've got valid PDF data you can generate your PNG from that using something like:
let captured = NSImage(data:pdfData)
let rep = NSBitmapImageRep(data:(captured?.tiffRepresentation)!)
let pngData = rep?.representation(using: NSPNGFileType, properties:[:])
(that is Swift 3, hence NSPNGFileType rather than .png)
This of course doesn't solve whatever problem you have, it avoids it :-) You should really figure out why your views are failing and treat this as a temporary band aid (assuming it works for you...).
HTH

iOS 11: [ImageManager] Unable to load image data

After update to iOS 11, photo assets now load slowly and I get this message in console:
[ImageManager] Unable to load image data,
/var/mobile/Media/DCIM/103APPLE/IMG_3064.JPG
I use static function to load image:
class func getAssetImage(asset: PHAsset, size: CGSize = CGSize.zero) -> UIImage? {
let manager = PHImageManager.default()
let option = PHImageRequestOptions()
option.isSynchronous = true
var assetImage: UIImage!
var scaleSize = size
if size == CGSize.zero {
scaleSize = CGSize(width: asset.pixelWidth, height: asset.pixelHeight)
}
manager.requestImage(for: asset, targetSize: scaleSize, contentMode: .aspectFit, options: option) { (image, nil) in
if let image = image {
assetImage = image
}
}
if assetImage == nil {
manager.requestImageData(for: asset, options: option, resultHandler: { (data, _, orientation, _) in
if let data = data {
if let image = UIImage.init(data: data) {
assetImage = image
}
}
})
}
return assetImage
}
Request image for asset usually always succeeds, but it prints this message. If I use requestImageData function only, there is no such message, but photos made with Apple camera lose their orientation and I get even more issues while loading big amount of images (I use image slideshow in my app).
Apple always sucks when it comes to updates, maybe someone got a solution how to fix this? It even fails to load an asset, when there is a big list of them in user camera. Switching to requestImageData is not an option for me as it brings nil data frequently now.
I would like to point out, that I call this function only once. It is not used in UITableView etc. I use other code for thumbs with globally initialised manager and options, so assets are definitely not nil or etc.
I call this function only when user clicks at certain thumb.
When gallery has like 5000 photos, maybe connection to assets is just overloaded and later it can't handle request and crashes?
So many questions.
Hey I was having the warning as well and here is what worked for me.
Replacing
CGSize(width: asset.pixelWidth, height: asset.pixelHeight)
by
PHImageManagerMaximumSize in requestImage call
removed the warning log 🎉
Hope this helps,
I had the same problem. Though this did not completely solve it, but it definitely helped.
option.isNetworkAccessAllowed = true
This helps only on the devices where Optimise iPhone Storage option for Photos app has been turned on.
Your code has some serious issues. You are saying .isSynchronous = true without stepping into a background thread to do the fetch. That is illegal and is what is causing the slowness. Plus, you are asking for a targetSize without also saying .resizeMode = .exact, which means you are getting much bigger images than you are asking for.
However, the warning you're seeing is irrelevant and can be ignored. It in no way signals a failure of image delivery; it seems to be just some internal message that has trickled up to the console by mistake.
This seems to be a bug with iOS 11, but I found I could work around by setting synchronous option false. I reworked my code to deal with the async delivery. Probably you can use sync(execute:) for quick fix.
Also, I believe the problem only occurred with photos delivered by iCloud sharing.
You can try method "requestImageData" with following options. This worked for me in iOS 11.2 (both on device and simulator).
let options = PHImageRequestOptions()
options.deliveryMode = .highQualityFormat
options.resizeMode = .exact
options.isSynchronous = true
PHImageManager.default().requestImageData(for: asset, options: options, resultHandler: { (data, dataUTI, orientation, info) in

Swift UIPasteboard not copying PNG

My problem is really odd. In the simulator the .png copies to clipboard fine and I can paste the image in the Contacts app on Simulator. But when I put the app on the phone, the png is not copied to clipboard.
let img = UIImage(named: "myimage")
let data = NSData(data: UIImagePNGRepresentation(img) )
UIPasteboard.generalPasteboard().setData(data, forPasteboardType: "public.png")
That's the code I'm using but like I said it does not copy to the clipboard. I'm using this code within the context of a keyboard, although that shouldn't matter when copying to a clipboard. If anyone has any ideas please let me know. Thanks in advance! Oh this is my first app in Swift and my first iOS app, so I don't have the seasoned experience to know if this is a Swift issue or something I'm just missing. =\
Make sure the code runs fine in your host app (not a keyboard extension app).
For example, check if the read image has the same resolution:
//the Pasteboard is nil if full access is not granted
let pbWrapped: UIPasteboard? = UIPasteboard.generalPasteboard()
if let pb = pbWrapped {
var type = UIPasteboardTypeListImage[0] as! String
if (count(type) > 0) && (image != nil) {
pb.setData(UIImagePNGRepresentation(image), forPasteboardType: type)
var readDataWrapped: NSData? = pb.dataForPasteboardType(type)
if let readData = readDataWrapped {
var readImage = UIImage(data: readData, scale: 2)
println("\(image) == \(pb.image) == \(readImage)")
}
}
}
If the pasteboard object is nil in your keyboard app that means you haven't provided full access to the keyboard: Copying and pasting image into a textbook in simulator
I believe you can use this line to do what you want (not able to test it out right now):
let image = UIImage(named: "myimage.png")
UIPasteboard.generalPasteboard().image = image;
Hopefully that works, I'm a little rusty with UIPasteboard.
There are lots of bugs and issues with the UIPasteboard class, so I'm really not surprised that you're having issues with something that so obviously is supposed to work. The documentation isn't that helpful either, to be honest. But try this; this worked for me on a physical device, and it's different to the above methods that are supposed to work but evidently don't for a bunch of people.
guard let imagePath = NSBundle.mainBundle().pathForResource("OliviaWilde", ofType: "jpg") else
{ return }
guard let imageData = NSData(contentsOfFile: imagePath) else { return }
let pasteboard = UIPasteboard.generalPasteboard()
pasteboard.setData(imageData, forPasteboardType: "public.jpeg")
You can use either "public.jpeg" or "public.png" if the source file is .jpg; it still works. I think it only changes the format of the thing that gets pasted?
Also, did you try adding the file extension in your first line of code where you create the UIImage? That might make it work too.
Evidently use of this class is temperamental, not just in this use case. So even though we're doing same thing, only difference in this code is we're creating the NSData from a path rather than a UIImage. Lol let me know if that works for you.
Ensure that RequestsOpenAccess is set to YES under NSExtension > NSExtensionAttributes in the extension's info.plist