Xcode - how to display image from url - xcode

I am able to display image from the sources, but was wondering how to display image from the URL link:
ccell.avatarImageView.image= [UIImage imageNamed:#"home_new.png"];
Thanks for the help.

Add this outside of the class scope:
import UIKit
extension UIImageView {
func loadurl(url: URL) {
DispatchQueue.global().async { [weak self] in
if let data = try? Data(contentsOf: url) {
if let image = UIImage(data: data) {
DispatchQueue.main.async {
self?.image = image
}
}
}
}
}
}
Then add this to wherever you're trying to load your image:
let urlYourURL = URL (string: #"home_new.png")
avatarImageView.loadurl(url: urlYourURL!)

Download the image as data from URL using NSURLConnection and use below code
let imageView:UIImageView = UIImageView.init(image: UIImage.init(data: **data**, scale: 1.0));

Related

How to conform UIImage to Codable?

Swift 4 has Codable and it's awesome. But UIImage does not conform to it by default. How can we do that?
I tried with singleValueContainer and unkeyedContainer
extension UIImage: Codable {
// 'required' initializer must be declared directly in class 'UIImage' (not in an extension)
public required init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
let data = try container.decode(Data.self)
guard let image = UIImage(data: data) else {
throw MyError.decodingFailed
}
// A non-failable initializer cannot delegate to failable initializer 'init(data:)' written with 'init?'
self.init(data: data)
}
public func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
guard let data = UIImagePNGRepresentation(self) else {
return
}
try container.encode(data)
}
}
I get 2 errors
'required' initializer must be declared directly in class 'UIImage' (not in an extension)
A non-failable initializer cannot delegate to failable initializer 'init(data:)' written with 'init?'
A workaround is to use wrapper. But are there any other ways?
Properly the easiest way is to just make the property Data instead of UIImage like this:
public struct SomeImage: Codable {
public let photo: Data
public init(photo: UIImage) {
self.photo = photo.pngData()!
}
}
Deserialize the image:
UIImage(data: instanceOfSomeImage.photo)!
A solution: roll your own wrapper class conforming to Codable.
One solution, since extensions to UIImage are out, is to wrap the image in a new class you own. Otherwise, your attempt is basically straight on. I saw this done beautifully in a caching framework by Hyper Interactive called, well, Cache.
Though you'll need to visit the library to drill down into the dependencies, you can get the idea from looking at their ImageWrapper class, which is built to be used like so:
let wrapper = ImageWrapper(image: starIconImage)
try? theCache.setObject(wrapper, forKey: "star")
let iconWrapper = try? theCache.object(ofType: ImageWrapper.self, forKey: "star")
let icon = iconWrapper.image
Here is their wrapper class:
// Swift 4.0
public struct ImageWrapper: Codable {
public let image: Image
public enum CodingKeys: String, CodingKey {
case image
}
// Image is a standard UI/NSImage conditional typealias
public init(image: Image) {
self.image = image
}
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let data = try container.decode(Data.self, forKey: CodingKeys.image)
guard let image = Image(data: data) else {
throw StorageError.decodingFailed
}
self.image = image
}
// cache_toData() wraps UIImagePNG/JPEGRepresentation around some conditional logic with some whipped cream and sprinkles.
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
guard let data = image.cache_toData() else {
throw StorageError.encodingFailed
}
try container.encode(data, forKey: CodingKeys.image)
}
}
I'd love to hear what you end up using.
UPDATE: It turns out the OP wrote the code that I referenced (the Swift 4.0 update to Cache) to solve the problem. The code deserves to be up here, of course, but I'll also leave my words unedited for the dramatic irony of it all. :)
You can use very elegant solution using extension for KeyedDecodingContainer and KeyedEncodingContainer classes:
enum ImageEncodingQuality {
case png
case jpeg(quality: CGFloat)
}
extension KeyedEncodingContainer {
mutating func encode(
_ value: UIImage,
forKey key: KeyedEncodingContainer.Key,
quality: ImageEncodingQuality = .png
) throws {
let imageData: Data?
switch quality {
case .png:
imageData = value.pngData()
case .jpeg(let quality):
imageData = value.jpegData(compressionQuality: quality)
}
guard let data = imageData else {
throw EncodingError.invalidValue(
value,
EncodingError.Context(codingPath: [key], debugDescription: "Failed convert UIImage to data")
)
}
try encode(data, forKey: key)
}
}
extension KeyedDecodingContainer {
func decode(
_ type: UIImage.Type,
forKey key: KeyedDecodingContainer.Key
) throws -> UIImage {
let imageData = try decode(Data.self, forKey: key)
if let image = UIImage(data: imageData) {
return image
} else {
throw DecodingError.dataCorrupted(
DecodingError.Context(codingPath: [key], debugDescription: "Failed load UIImage from decoded data")
)
}
}
}
PS: You can use such way to adopt Codable to any class type
One way to pass an UIImage is to convert it to something that conforms to Codable, like String.
To convert the UIImage to String inside func encode(to encoder: Encoder) throws:
let imageData: Data = UIImagePNGRepresentation(image)!
let strBase64 = imageData.base64EncodedString(options: .lineLength64Characters)
try container.encode(strBase64, forKey: .image)
To convert the String back to UIImage inside required init(from decoder: Decoder) throws:
let strBase64: String = try values.decode(String.self, forKey: .image)
let dataDecoded: Data = Data(base64Encoded: strBase64, options: .ignoreUnknownCharacters)!
image = UIImage(data: dataDecoded)
The existing answers all appear to be incorrect. If you compare the deserialized image with the original, you will find they may well not be equal in any sense. This is because the answers are all throwing away the scale information.
You have to encode the image scale as well as its pngData(). Then when you decode the UIImage, combine the data with the scale by calling init(data:scale:).
The best solution is to use a custom property wrapper
the property remains mutable
no code alternations needed, just add the #CodableImage prefix
Usage
class MyClass: Codable {
#CodableImage var backgroundImage1: UIImage?
#CodableImage var backgroundImage2: UIImage?
#CodableImage var backgroundImage3: UIImage?
Add this code to project:
#propertyWrapper
public struct CodableImage: Codable {
var image: UIImage?
public enum CodingKeys: String, CodingKey {
case image
}
public init(image: UIImage?) {
self.image = image
}
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
if let b = try? container.decodeNil(forKey: CodingKeys.image), b {
self.image = nil
} else {
let data = try container.decode(Data.self, forKey: CodingKeys.image)
guard let image = UIImage(data: data) else {
throw DecodingError.dataCorruptedError(forKey: CodingKeys.image, in: container, debugDescription: "Decoding image failed")
}
self.image = image
}
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
if let data = image?.pngData() {
try container.encode(data, forKey: CodingKeys.image)
} else {
try container.encodeNil(forKey: CodingKeys.image)
}
}
public init(wrappedValue: UIImage?) {
self.init(image: wrappedValue)
}
public var wrappedValue: UIImage? {
get { image }
set {
image = newValue
}
}
}
There's also a simple solution using lazy var on the image:
var mainImageData: Data {
didSet { _ = mainImage }
}
lazy var mainImage: UIImage = {
UIImage(data: mainImageData)!
}()
This way, during object initialization and assignment to mainImageData, its didSet will kick in which will then initiate the initialization of the UIImage.
Since UIImage initialization is resource heavy, we couple them together.
Just pay attention that the entire initialization will be on the background thread.
Swift 5.4
// MARK: - ImageWrapper
public struct ImageWrapper: Codable {
// Enums
public enum CodingKeys: String, CodingKey {
case image
}
// Properties
public let image: UIImage
// Inits
public init(image: UIImage) {
self.image = image
}
// Methods
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let data = try container.decode(Data.self, forKey: CodingKeys.image)
if let image = UIImage(data: data) {
self.image = image
} else {
// Error Decode
}
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
if let imageData: Data = image.pngData() {
try container.encode(imageData, forKey: .image)
} else {
// Error Encode
}
}
}

Swift 3: UICollectionView download video snapshot. UI is freezed while trying to download snapshot

I'm trying to download video preview base on remote video URL. In my project, the server cannot return snapshot image of the videos, that's why I have to do it manually.
In table view, I have code like this in cellForItemAt to get video preview
DataManager.sharedInstance.getCachedImage(url: movie.url!, handler: { (image) in
cell.ivCover.image = image
})
and my getCachedImage function in DataManager:
func getCachedImage(url: String, handler: #escaping(_ result:UIImage) -> Void){
DispatchQueue.global().async {
let userDefaults = UserDefaults.standard
if let imageData = userDefaults.object(forKey: url){
if let finalImg = UIImage(data: imageData as! Data){
DispatchQueue.main.async {
handler(finalImg)
}
print("USING CACHED IMG")
}else{
DispatchQueue.main.async {
handler(#imageLiteral(resourceName: "cover"))
}
print("Cannot parse cached data to image. Use default")
}
}else{
let asset = AVURLAsset(url: URL(string: url)!)
let generate = AVAssetImageGenerator(asset: asset)
generate.appliesPreferredTrackTransform = true
var thumbTime = asset.duration
thumbTime.value = 1
var imgRef:CGImage?
do{
print("Downloading thum from url: \(url)")
imgRef = try generate.copyCGImage(at: thumbTime, actualTime: nil)
}catch let error{
print("Error download thum: \(error.localizedDescription)")
}
var finalImg:UIImage
if let _ = imgRef{
finalImg = UIImage(cgImage: imgRef!)
userDefaults.set(UIImagePNGRepresentation(finalImg), forKey: url)
}else{
finalImg = #imageLiteral(resourceName: "cover")
print("Download thumnail failed. Use default")
}
DispatchQueue.main.async {
handler(finalImg)
}
}
}
}
The problem is that, sometimes I scroll the Collection view, UI is freezed, sometimes it's not. Please note that this video is on REMOTE SERVER, NOT local video.
I've spent days to figure out the issue but still not able to find out what went wrong. Please help!
Or is there any existing library I can use?
import UIKit
import Photos
class ImportViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func myButton(_ sender: Any) {
let videoURL = "https://youerdomin.com/file.mp4"
print("1")
DispatchQueue.global(qos: .background).async {
print("2")
if let url = URL(string: videoURL), let urlData = NSData(contentsOf: url) {
print("3")
let documentsPath =
NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0];
let filePath="\(documentsPath)/tempFile.mp4"
DispatchQueue.main.async {
print("4")
urlData.write(toFile: filePath, atomically: true)
PHPhotoLibrary.shared().performChanges({
print("5")
PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: URL(fileURLWithPath: filePath))
}) { completed, error in
print("6")
if completed {
print("Video is saved!")
}else{
print("7: ",filePath)
}
}
}
}else{
print("8")
}
}
}
}

Swift2 retrieving images from Firebase

I am trying to read/display an image from Firebase. I am first encoding the image and then posting this encoded String to Firebase. This runs fine. When I try and decode the encoded string from Firebase and convert it to an image, I am getting a nil value exception.
This is how I am saving the image to Firebase
var base64String: NSString!
func imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage, editingInfo: [String : AnyObject]?) {
self.dismissViewControllerAnimated(true, completion: nil)
imageToPost.image = image
var uploadImage = image as! UIImage
var imageData = UIImagePNGRepresentation(uploadImage)!
self.base64String = imageData.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.Encoding64CharacterLineLength)
let ref = Firebase(url: "https://XXX.firebaseio.com")
var quoteString = ["string": self.base64String]
var usersRef = ref.childByAppendingPath("goalImages")
var users = ["image": quoteString]
usersRef.setValue(users)
displayAlert("Image Posted", message: "Your image has been successfully posted!")
}
This is how I am trying to read the image from Firebase
// ViewController.swift
import UIKit
import Firebase
class ViewController: UIViewController {
#IBOutlet weak var image: UIImageView!
var base64String: NSString!
#IBAction func buttonClicked(sender: AnyObject) {
sender.setTitle("\(sender.tag)", forState: UIControlState.Normal)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let ref = Firebase(url: "https://XXX.firebaseio.com/goalImages/image/string")
ref.observeEventType(.Value, withBlock: { snapshot in
self.base64String = snapshot.value as! NSString
let decodedData = NSData(base64EncodedString: self.base64String as String, options: NSDataBase64DecodingOptions())
//Next line is giving the error
var decodedImage = UIImage(data: decodedData!)
self.image.image = decodedImage
}, withCancelBlock: { error in
print(error.description)
})
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
The error says: "fatal error: unexpectedly found nil while unwrapping an Optional value"; decodedData is nil. Could someone explain what is going wrong.
Instead of
let decodedData = NSData(base64EncodedString: self.base64String as String,
options: NSDataBase64DecodingOptions())
try adding IgnoreUnknownCharacters
NSDataBase64DecodingOptions.IgnoreUnknownCharacters
Use Example: Encode a jpg, store and read from firebase
encode and write our favorite starship
if let image = NSImage(named:"Enterprise.jpeg") {
let imageData = image.TIFFRepresentation
let base64String = imageData!.base64EncodedStringWithOptions(.Encoding64CharacterLineLength)
let imageRef = myRootRef.childByAppendingPath("image_path")
imageRef.setValue(base64String)
read and decode
imageRef.observeEventType(.Value, withBlock: { snapshot in
let base64EncodedString = snapshot.value
let imageData = NSData(base64EncodedString: base64EncodedString as! String,
options: NSDataBase64DecodingOptions.IgnoreUnknownCharacters)
let decodedImage = NSImage(data:imageData!)
self.myImageView.image = decodedImage
}, withCancelBlock: { error in
print(error.description)
})
EDIT 2019_05_17
Update to Swift 5 and Firebase 6
func writeImage() {
if let image = NSImage(named:"Enterprise.jpg") {
let imageData = image.tiffRepresentation
if let base64String = imageData?.base64EncodedString() {
let imageRef = self.ref.child("image_path")
imageRef.setValue(base64String)
}
}
}
func readImage() {
let imageRef = self.ref.child("image_path")
imageRef.observeSingleEvent(of: .value, with: { snapshot in
let base64EncodedString = snapshot.value as! String
let imageData = Data(base64Encoded: base64EncodedString, options: Data.Base64DecodingOptions.ignoreUnknownCharacters)!
let decodedImage = NSImage(data: imageData)
self.myImageView.image = decodedImage
})
}
Firebase Engineer here:
I highly recommend using the new Firebase Storage API for uploading images to Firebase. It's simple to use, low cost, and backed by Google Cloud Storage for huge scale.
You can upload from NSData or an NSURL pointing to a local file (I'll show NSData, but the principle is the same):
// Data in memory
let data: NSData = ...
// Create a reference to the file you want to upload
let riversRef = storageRef.child("images/rivers.jpg")
// Upload the file to the path "images/rivers.jpg"
let uploadTask = riversRef.putData(data, metadata: nil) { metadata, error in
if (error != nil) {
// Uh-oh, an error occurred!
} else {
// Metadata contains file metadata such as size, content-type, and download URL.
let downloadURL = metadata!.downloadURL
// This can be stored in the Firebase Realtime Database
// It can also be used by image loading libraries like SDWebImage
}
}
You can even pause and resume uploads, and you can easily monitor uploads for progress:
// Upload data
let uploadTask = storageRef.putData(...)
// Add a progress observer to an upload task
uploadTask.observeStatus(.Progress) { snapshot in
// Upload reported progress
if let progress = snapshot.progress {
let percentComplete = 100.0 * Double(progress.completedUnitCount) / Double(progress.totalUnitCount)
}
}

how to download an image in OS X using swift language

I have created a button for OSX in Swift language. I wish that button should download an image in my Mac.
What code should I use for downloading that image?
Following is the code that I used:
#IBAction func buttonPressed(sender: NSButton) {
buttonPresses+=1
theLabel.stringValue = "You've pressed the button \n \(buttonPresses) times!"
theButton.title = "Download\(buttonPresses)"
}
Alamofire is an easy way to download an image:
Alamofire.request(.GET, url).response() { request, response, data, error in
var image: UIImage?
if nil == error {
if let imageData = data as? NSData {
image = UIImage(data: imageData)
}
}
self.imageView.image = image
}

Downloading Image Swift

I want to download an image from Facebook and store it to my cache, which I call over HTTPS. If I just use HTTP everything works fine, but if I change it to HTTPS it does not work anymore.
Here is my code:
// Grab the artworkUrl key to get an image URL for thumbnail
var urlString: NSString = rowData["cover"] as NSString
// Check our image cache for the existing key. This is just a dictionary of UIImages
var image: UIImage? = self.imageCache.valueForKey(urlString) as? UIImage
if( !image? ) {
// If the image does not exist, we need to download it
var imgURL: NSURL = NSURL(string: urlString)
// Download an NSData representation of the image at the URL
var request: NSURLRequest = NSURLRequest(URL: imgURL)
var urlConnection: NSURLConnection = NSURLConnection(request: request, delegate: self)
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue(), completionHandler: {(response: NSURLResponse!,data: NSData!,error: NSError!) -> Void in
if !error? {
//var imgData: NSData = NSData(contentsOfURL: imgURL)
image = UIImage(data: data)
// Store the image in to our cache
self.imageCache.setValue(image, forKey: urlString)
cell.image = image
println(self.imageCache)
}
else {
println("Error: \(error.localizedDescription)")
}
})
}
else {
cell.image = image
}
})
The URL I want to use is this:
https://fbcdn-sphotos-d-a.akamaihd.net/hphotos-ak-xpf1/t1.0-9/q71/s720x720/995054_485489274919674_7207866955460529362_n.jpg
The Error is a "Timeout".
With this URL everything works fine:
http://fbcdn-sphotos-d-a.akamaihd.net/hphotos-ak-xpf1/t1.0-9/q71/s720x720/995054_485489274919674_7207866955460529362_n.jpg
Thanks,
Tobias
From what I can tell NSURLConnection sometimes runs into trouble with HTTPS connections. Try adding these two methods to your class (and mark it as NSURLConnectionDelegate) (from this answer):
func connection(connection: NSURLConnection!, canAuthenticateAgainstProtectionSpace protectionSpace: NSURLProtectionSpace!) -> Bool {
return true
}
func connection(connection: NSURLConnection!, didReceiveAuthenticationChallenge challenge: NSURLAuthenticationChallenge!) {
challenge.sender.useCredential(NSURLCredential(forTrust: challenge.protectionSpace.serverTrust), forAuthenticationChallenge: challenge)
}

Resources