I want to convert a bas64 string to an image. Here's the code I currently have.
let sData = success as! String
let str = String(utf8String: sData.cString(using: String.Encoding.utf8)!)
let decodedData = NSData(base64Encoded: str!, options: NSData.Base64DecodingOptions(rawValue: 0) )
let image = UIImage(data: decodedData! as Data)
if let decodedData = Data(base64Encoded: (yourBase64Dasta as? String)! , options: .ignoreUnknownCharacters) {
imgThumb = UIImage(data: decodedData)
}
this is currently working code in my swift 4 project so you can use it :)
Here's an extension you can use to easily initialize an image from a base43 string:
extension UIImage {
convenience init?(base64 str: String) {
guard let url = URL(string: str),
let data = try? Foundation.Data(contentsOf: url),
UIImage(data: data) != nil else { return nil }
self.init(data: data)!
}
}
Then you can do:
let image = UIImage(base64: "string from your server goes here")
Related
I want to get a thumbnail image for videos from Rumble.
When getting images from Youtube I just do like this:
https://img.youtube.com/vi/f3ZccBBjmQg/0.jpg
Want to same from Rumble video url-
https://rumble.com/vxhedt-80000-matches-chain-reaction-domino-effect.html?mref=7ju1&mc=4w36m
I checked the rumble webpage of the link you provided. I am not sure if there is a smarter/faster way but here is a way to get the thumbnailUrl from their html code.
func getThumbnailFromRumble() {
let url = URL(string:"https://rumble.com/vxhedt-80000-matches-chain-reaction-domino-effect.html?mref=7ju1&mc=4w36m")!
URLSession.shared.dataTask(with: url){ data, response, error in
guard error == nil else { return }
guard let httpURLResponse = response as? HTTPURLResponse,
httpURLResponse.statusCode == 200,
let data = data else {
return
}
let str = String(data: data, encoding: .utf8) // get the htm response as string
let prefix = "\"thumbnailUrl\":"
let suffix = ",\"uploadDate\""
let matches = str?.match("(\(prefix)(...*)\(suffix))")
if let thumbnailUrlMatch = matches?.first?.first {
let thumbnailUrl = thumbnailUrlMatch
.replacingOccurrences(of: prefix, with: "") // remove prefix from urlstring
.replacingOccurrences(of: suffix, with: "") // remove suffix from urlstring
.replacingOccurrences(of: "\"", with: "") // remove escaping characters from urlstring
if let url = URL(string: thumbnailUrl),
let data = try? Data(contentsOf: url) {
let uiImage = UIImage(data: data)
// use the uiimage
}
}
}.resume()
}
I use this extension to get the necessary string part from the html response
extension String {
func match(_ regex: String) -> [[String]] {
let nsString = self as NSString
return (try? NSRegularExpression(pattern: regex, options: []))?.matches(in: self, options: [], range: NSMakeRange(0, nsString.length)).map { match in
(0..<match.numberOfRanges).map { match.range(at: $0).location == NSNotFound ? "" : nsString.substring(with: match.range(at: $0)) }
} ?? []
}
}
Feel free to improve the code.
I am using firebase to save and load my images. I have created a new view in Xcode and am using the same code I have been using to load profile images. Yet, this is now throwing an error saying that the url string is nil. The image url data disappears after "DispatchQueue.global().async". What could be causing this and how could I track this? Very strange how this code works for other views yet for this new view it is throwing an error.
let businessProfilePicture = dictionary["profPicString"] as! String
if businessProfilePicture.count > 0 {
let url = URL(string: businessProfilePicture)
print(url)
print("printing the url here to check")
DispatchQueue.global().async {
let dataURL = try? Data(contentsOf: url!)
print(dataURL)
print("printing the data url here")
DispatchQueue.main.async {
print(dataURL)
print("Printing Data to check")
let image = UIImage(data: dataURL!)?.potter_circleo
self.businessProfilePicture.contentMode = UIView.ContentMode.scaleAspectFill
self.businessProfilePicture.image = image
}
}
Full Code
func getWorkLocation() {
let uid = Auth.auth().currentUser?.uid
var profPicURL: String = ""
Database.database().reference().child("employees").child(uid!).child("Business").observe(.value, with: { snapshot in
if snapshot.exists() {
let dictionary = snapshot.value as? NSDictionary
self.businessName.text = dictionary?["businessName"] as? String
self.businessStreet.text = dictionary?["businessStreet"] as? String
self.businessCity.text = dictionary?["businessCity"] as? String
profPicURL = dictionary?["profPicString"] as! String
// set image
if profPicURL.count > 0 {
let url = URL(string: profPicURL)
DispatchQueue.global().async {
let data = try? Data(contentsOf: url!)
DispatchQueue.main.async {
let image = UIImage(data: data!)?.potter_circle
self.businessProfilePicture.contentMode = UIView.ContentMode.scaleAspectFill
self.businessProfilePicture.image = image
}
}
} else {
let image = UIImage(named: "profile picture")?.potter_circle
self.businessProfilePicture.contentMode = UIView.ContentMode.scaleAspectFill
self.businessProfilePicture.image = image
}
} else {
self.businessName.text = ""
self.businessStreet.text = "Go to Add Work Location to send request"
self.businessCity.text = ""
self.deleteButton.isEnabled = false
}
})
}
Are you certain that the URL you create from profPicURL is being created properly?
URL(string:) can fail and return nil. If you then go on to implicitly unwrap it in Data(contentsOf: url!) you will crash.
Similarly, try? Data(contentsOf: url) can return nil. If it does, then when you implicitly unwrap it in UIImage(data: data!) you will crash.
As Jacob said in comments, you need to learn more about implicitly unwrapped optionals. To get you started, you might structure your code something like this:
if let url = URL(string: profPicURL) {
DispatchQueue.global().async {
if let data = try? Data(contentsOf: url),
let image = UIImage(data: data)?.potter_circle
{
DispatchQueue.main.async {
self.businessProfilePicture.contentMode = UIView.ContentMode.scaleAspectFill
self.businessProfilePicture.image = image
}
} else {
// raise an an error or set self.businessProfilePicture.image to a generic image or something
}
}
} else {
// raise an an error or set self.businessProfilePicture.image to a generic image or something
}
I am parsing data and checking if an image is in cache. If yes, set it, if not set it to default and send it to cache.
The part that sends it to cache keeps giving nil ???
Any help would be appreciated
Pic_STR = "https://myserver/Pictures/" + Pic + ".jpg"
let url = URL(string: Pic_STR)
if let imageFromCache = imageCache.object(forKey: Pic_STR as AnyObject) as? UIImage {
data.photo = imageFromCache
return
} else {
data.photo = UIImage(named: "Default")
let imageCache = NSCache<NSString, AnyObject>()
URLSession.shared.dataTask(with: url!) { data, response, error in
guard let data = data, error == nil else { return }
let imageToCache = UIImage(data: data)
imageCache.setObject(imageToCache!, forKey: self.Pic_STR as NSString)
//self.image = imageToCache
}.resume()
}
After much experiminting I finally found a solution. I am sure it could be improved, but it works. I would prefer to use an extension, but can't figure out how.
struct imageData {
let image: UIImage?
let name: String?
}
var newImage = UIImage()
var myImages = [imageData]()
let imageString= "https://myserver/Pictures/" + Pic + ".jpg"
let imageURL = URL(string: imageString)
CON2 = false
for pics in myImages {
if pics.name == Pic {
data.photo = pics.image
CON2 = true
}
}
if CON2 == false {
let data2 = try? Data(contentsOf: imageURL!)
if let imageData = data2 {
newImage = UIImage(data: imageData)!
}
let newData = imageData(image: newImage, name: Pic) as imageData
myImages += [newData]
data.photo = newImage
}
I have a encoded string from server which is a image.
Now I want to decode that string to anything(UIImage) you can and set to a UIImageView
Thanks in advance
I'm using the following extension for that:
extension UIImage: {
convenience init?(base64 str: String) {
guard let url = URL(string: str),
let data = try? Foundation.Data(contentsOf: url),
UIImage(data: data) != nil else { return nil }
self.init(data: data)!
}
}
Then you can do:
let image = UIImage(base64: someString)
Note, that for this to work, your base64 string must be formatted as follows: data:image/png;base64,... (or replacing png with jpeg).
If your base64 string does not have this prefix, you can do this:
extension UIImage: {
convenience init?(base64 str: String) {
guard let data = try? Foundation.Data(base64Encoded: str),
UIImage(data: data) != nil else { return nil }
self.init(data: data)!
}
}
Extra Credit
You can reverse the whole thing and convert an image to base64 string:
public enum ImageFormat {
case png
case jpeg
}
public func base64(format: ImageFormat, includingPrefix: Bool = true) -> String? {
var imageData: Foundation.Data?
switch format {
case .png: imageData = self.pngData
case .jpeg: imageData = self.jpegData
}
guard let data = imageData else { return nil }
return "data:image/\((format));base64," + data.base64EncodedString()
}
You can do the following:
let string: String = "YourBase64EncodedImageAsAString"
if let imageData = Data(base64Encoded: string), let image = UIImage(data: imageData) {
//use image
}
func base64ToImage(base64String: String?) -> UIImage{
if (base64String?.isEmpty)! {
return #imageLiteral(resourceName: "no_image_found")
}else {
// Separation part is optional, depends on your Base64String !
let tempImage = base64String?.components(separatedBy: ",")
let dataDecoded : Data = Data(base64Encoded: tempImage![1], options: .ignoreUnknownCharacters)!
let decodedimage = UIImage(data: dataDecoded)
return decodedimage!
}
}
You will pass args to your base64 data.
I have an array of URLs linking to image files, how do I store them into an array of UIImages?
var imagesArray = [UIImage]()
let links = ["http://example.com/image1.jpg","http://example.com/image2.jpg"] as [String]
There must be an easy solution.
If it was one image I could do something like the following:
let url = URL(string: link2image!)!
let imageData = try? Data(contentsOf: url)
let image = UIImage(data: imageData!)!
self.image.append(image)
The easiest solution would be to just iterate through the array and download the images synchronously using Data(contentsOf:), however, this would be quite insufficient due to synchronous execution.
let images = links.flatMap{ link->UIImage? in
guard let url = URL(string: link) else {return nil}
guard let imageData = try? Data(contentsOf: url) else {return nil}
return UIImage(data: imageData)
}
A better solution would be to download the images asynchronously in parallel, I have written a UIImage extension for this using PromiseKit:
extension UIImage {
class func downloadedAsync(fromUrl url: URL)->Promise<UIImage> {
return Promise{ fulfill, reject in
URLSession.shared.dataTask(with: url, completionHandler: { data, response, error in
guard let data = data, error == nil else {
reject(error!); return
}
guard let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
reject(NSError(domain: "Wrong HTTP response code when downloading image asynchronously",code: (response as? HTTPURLResponse)?.statusCode ?? 1000));return
}
guard let mimeType = response?.mimeType, mimeType.hasPrefix("image"), let image = UIImage(data: data) else {
reject(NSError(domain: "No image in response", code: 700)); return
}
fulfill(image)
}).resume()
}
}
}
You call it for an array of links like this:
var imageDownloadTasks = links.flatMap{ link in
guard let url = URL(string: link) else {return nil}
return UIImage.downloadedAsync(fromUrl: url)
}
Then execute the promises:
when(fulfilled: imageDownloadTasks).then{ images in
//use the images, images is of type [UIImage]
}
Maybe you can try Functional programming use: map closure ...
links.map({
if let imageData = try? Data(contentsOf: URL(string: $0)!) {
UIImage(data: imageData)
}
})
But you must know if your links is wrong, it will crash. So, I suggest you make some guard to prevent these crashes. like this...
guard let url = URL(string: $0) else { return nil }