I have some code that creates an NSSecureCoding variable called "content" and I want to convert that variable into NSData that can then be made into a UIImage or be sent to a local server. How do I convert this properly? I want this for a Share Extension I am making in my iOS app, so when you press share on a photo, it gets the photo contents and converts it into NSData. Here is my code:
inputItem = extensionContext!.inputItems.first as NSExtensionItem
attachment = inputItem.attachments![0] as NSItemProvider
if (attachment.hasItemConformingToTypeIdentifier(kUTTypeImage as String)){
attachment.loadItemForTypeIdentifier(kUTTypeImage as String,
options: nil,
completionHandler: {(content, error: NSError!) in
//insert code to convert "content"(NSSecureCoding) to NSData variable
})
}
DispatchQueue.global().async {
attachment.loadItem(forTypeIdentifier: kUTTypeImage as String, options: nil, completionHandler: { (item, error) in
if let error = error {
print(error.localizedDescription)
return
}
var image: UIImage?
if item is UIImage {
image = item as? UIImage
}
if item is URL {
let data = try? Data(contentsOf: item as! URL)
image = UIImage(data: data!)!
}
if item is Data {
image = UIImage(data: item as! Data)!
}
if let image = image {
DispatchQueue.main.async {
// image here
}
}
})
}
kinda late but this happened to me today and I solved it like this,
inside the completionHandler:
if let data = content {
self.imageData = UIImage(data: NSData(contentsOfURL: data as! NSURL)!)
}
imageData is UIImage type.
Related
In my project, I show a UITableView, which currently has text describing a show's name and genre loading from a remote JSON file.
That all works. What I want next is to use the URL from the JSON file and load a thumbnail next to each show.
Using a tutorial, I have added a function to download the remote image with a print to test if it's successful.
if let shows_list = json as? NSArray
{
for i in 0 ..< data_list.count
{
if let shows_obj = shows_list[i] as? NSDictionary
{
let show_name = shows_obj["show"] as? String
let show_genre = shows_obj["genre"] as? String
let show_image = shows_obj["thumbnail"] as? String
TableData.append(show_name! + " | " + show_genre!)
let testPictureURL = URL(string: show_image!)!
let session = URLSession(configuration: .default)
// Here's the download task where I'm grabbing the image
let downloadPicTask = session.dataTask(with: testPictureURL) { (data, response, error) in
// The download has finished.
if let e = error {
print("Error downloading cat picture: \(e)")
} else {
// No errors found.
if let res = response as? HTTPURLResponse {
print("Downloaded picture with response code \(res.statusCode)")
if let imageData = data {
// Now I know I have data, so I think I can use UIImage to convert it into an image
let image = UIImage(data: imageData)
} else {
print("Couldn't get image: Image is nil")
}
} else {
print("Couldn't get response code for some reason")
}
}
}
downloadPicTask.resume()
}
There are three items in the JSON array, and I get three printed statements that the picture was download: but the image does not appear.
My theory: since this is a table, maybe I have to add this as an accessory, but there isn't an image accessory subclass.
I am new to Swift -- do you have any ideas about how I should append this uploaded image to the table.
This is probably being caused by the asynchronous behavior of URLSession so when the requested image returns the view is already loaded.
To solve that, you can use a callback, for instance:
func myFunction(completion: (returnedImage -> UIIMage) -> Void){
//...
let downloadPicTask = session.dataTask(with: testPictureURL) { (data, response, error) in
//...
let image = UIImage(data: imageData)
completion(returnedImage: image)
//...
}
downloadPicTask.resume()
}
}
By using a callback, let's say that you have a method called myFunction(completion:), so now when you call the method you can handle whatever comes back from completion:
myFunction { (image) in
DispatchQueue.main.async { cell.imageView.image = image }
}
I am using CoreData for an app. I have set image as BinaryData in data model. But I have fetched image from server as UIImage and it throws error as:
cannot assign value of type 'UIImage?' to type 'NSData?
I searched but couldn't find any resemblance solution for it. Can anyone help me in swift 3?
My code is:
let url1:URL = URL(string:self.appDictionary.value(forKey: "image") as! String)!
let picture = "http://54.243.11.100/storage/images/news/f/"
let strInterval = String(format:"%#%#",picture as CVarArg,url1 as CVarArg) as String as String
let url = URL(string: strInterval as String)
SDWebImageManager.shared().downloadImage(with: url, options: [],progress: nil, completed: {[weak self] (image, error, cached, finished, url) in
if self != nil {
task.imagenews = image //Error:cannot assign value of type 'UIImage?' to type 'NSData?'
}
})
The error message is pretty clear - you cannot assign UIImage object to a variable of NSData type.
To convert UIImage to Swift's Data type, use UIImagePNGRepresentation
var data : Data = UIImagePNGRepresentation(image)
Note that if you're using Swift, you should be using Swift's type Data instead of NSData
You must convert, image into Data (or NSData) to support imagenews data type.
Try this
let url1:URL = URL(string:self.appDictionary.value(forKey: "image") as! String)!
let picture = "http://54.243.11.100/storage/images/news/f/"
let strInterval = String(format:"%#%#",picture as CVarArg,url1 as CVarArg) as String as String
let url = URL(string: strInterval as String)
SDWebImageManager.shared().downloadImage(with: url, options: [],progress: nil, completed: {[weak self] (image, error, cached, finished, url) in
if self != nil {
if let data = img.pngRepresentationData { // If image type is PNG
task.imagenews = data
} else if let data = img.jpegRepresentationData { // If image type is JPG/JPEG
task.imagenews = data
}
}
})
// UIImage extension, helps to convert Image into data
extension UIImage {
var pngRepresentationData: Data? {
return UIImagePNGRepresentation(img)
}
var jpegRepresentationData: Data? {
return UIImageJPEGRepresentation(self, 1.0)
}
}
I'm implementing a share extension that sends images to a server for computation.
In addition to my progress bar issues, I'm not able to use the images from Twitter app. Here is the code I'm using which is working in many other third party apps.
if let inputItem = extensionContext!.inputItems.first as? NSExtensionItem {
if let itemProvider = inputItem.attachments?.first as? NSItemProvider {
if itemProvider.hasItemConformingToTypeIdentifier(kUTTypeImage as String) {
itemProvider.loadItem(forTypeIdentifier: kUTTypeImage as String) { [unowned self] (imageData, error) in
let url = imageData as! URL
self.sendToServer(localUrl: url)
}
}
}
}
The error I have is the following: Could not cast value of type 'NSConcreteData' (0x1a8d45700) to 'NSURL' (0x1a8d36a10) and occurs for this part of the code let url = imageData as! URL.
It seems that the item is of type image. Any idea why that is happening while it works for the other apps?
Thanks for your help.
I managed to fix that by using the following code, which takes into account different ways the photo is passed by the itemProvider.
itemProvider.loadItem(forTypeIdentifier: kUTTypeImage as String){ [unowned self] (data, error) in
let myImage: UIImage?
switch data {
case let image as UIImage:
myImage = image
case let data as Data:
myImage = UIImage(data: data)
case let url as URL:
let imageData = NSData(contentsOf: url.absoluteURL)
myImage = UIImage(data: imageData! as Data)
default:
//There may be other cases...
print("Unexpected data:", type(of: data))
myImage = nil
}
self.sendToServer(imageData: myImage!, imageName: myImageName)
}
My iOS app (Swift 3) needs to important images from other apps using an Action Extension. I'm using the standard Action Extension template code which works just fine for apps like iOS Mail and Photos where the image shared is a URL to a local file. But for certain apps where the image being shared is the actual image data itself, my action extension code isn't getting the image.
for item: Any in self.extensionContext!.inputItems {
let inputItem = item as! NSExtensionItem
for provider: Any in inputItem.attachments! {
let itemProvider = provider as! NSItemProvider
if itemProvider.hasItemConformingToTypeIdentifier(kUTTypeImage as String) { //we'll take any image type: gif, png, jpg, etc
// This is an image. We'll load it, then place it in our image view.
weak var weakImageView = self.imageView
itemProvider.loadItem(forTypeIdentifier: kUTTypeImage as String, options: nil, completionHandler: { (imageURL,
error) in
OperationQueue.main.addOperation {
if let strongImageView = weakImageView {
if let imageURL = imageURL as? NSURL {
strongImageView.image = UIImage(data: NSData(contentsOf: imageURL as URL)! as Data)
let imageData = NSData(contentsOf: imageURL as URL)! as Data
self.gifImageView.image = UIImage.gif(data: imageData)
let width = strongImageView.image?.size.width
let height = strongImageView.image?.size.height
.... my custom logic
}
}
For reference, I reached out to the developer for one of the apps where things aren't working and he shared this code on how he is sharing the image to the Action Extension.
//Here is the relevant code. At this point the scaledImage variable holds a UIImage.
var activityItems = Array<Any?>()
if let pngData = UIImagePNGRepresentation(scaledImage) {
activityItems.append(pngData)
} else {
activityItems.append(scaledImage)
}
//Then a little later it presents the share sheet:
let activityVC = UIActivityViewController(activityItems: activityItems,applicationActivities: [])
self.present(activityVC, animated: true, completion: nil)
Figured it out thanks to this post which explains the challenge quite well https://pspdfkit.com/blog/2017/action-extension/ . In summary, we don't know if the sharing app is giving us a URL to an existing image or just raw image data so we need to modify the out of the box action extension template code to handle both cases.
for item: Any in self.extensionContext!.inputItems {
let inputItem = item as! NSExtensionItem
for provider: Any in inputItem.attachments! {
let itemProvider = provider as! NSItemProvider
if itemProvider.hasItemConformingToTypeIdentifier(kUTTypeImage as String) { //we'll take any image type: gif, png, jpg, etc
// This is an image. We'll load it, then place it in our image view.
weak var weakImageView = self.imageView
itemProvider.loadItem(forTypeIdentifier: kUTTypeImage as String, options: nil, completionHandler: { (imageURL,
error) in
OperationQueue.main.addOperation {
if let strongImageView = weakImageView {
if let imageURL = imageURL as? NSURL {
strongImageView.image = UIImage(data: NSData(contentsOf: imageURL as URL)! as Data)
let imageData = NSData(contentsOf: imageURL as URL)! as Data
self.gifImageView.image = UIImage.gif(data: imageData)
let width = strongImageView.image?.size.width
let height = strongImageView.image?.size.height
.... my custom logic
}
else
guard let imageData = imageURL as? Data else { return } //can we cast to image data?
strongImageView_.image = UIImage(data: imageData_)
//custom logic
}
I want to Load image using JSON parsing in collectionView. I'm getting array of image URLs, but images are not shown on UIImageView. I have used this code after getting JSON array and displaying it in UICollectionView's UIImageView.
if let url = NSURL(string: self.Products[indexPath.row].image) {
if let data = NSData(contentsOfURL: url){
cell.product_image.contentMode = UIViewContentMode.ScaleAspectFit
cell.product_image.image = UIImage(data: data)
}
}
But I am not able to load image, but text is displayed. I have used this code in cellForItemAtIndexPath method.. Can anyone suggest me what am I doing wrong?
func jsonParsingFromURL(){
// 1
let reposURL = NSURL(string: "http://api.room2shop.com/api/product/GetProducts?categoryId=24&filter=2&pageNumber=1")
// 2
if let JSONData = NSData(contentsOfURL: reposURL!) {
// 3
do
{
if let json = try NSJSONSerialization.JSONObjectWithData(JSONData, options: .AllowFragments) as? NSDictionary {
// 4
if let reposArray = json["ProductList"] as? [NSDictionary] {
// 5
for item in reposArray {
Products.append(ProductList(json: item))
}
}
}
}
catch {
print("Error with Json: \(error)")
}
}
}
This is my JSON parsing code
to reflect changes, you need to use
self.collectionView?.reloadData()
EDIT
1- please replace this block with this, and tell me if you get the urls normally, for me I get the urls normally
for item in reposArray
{
//ProductList(json: item)
//Products.append(ProductList(json: item))
//print(item)
print("__________")
print(item["Image"]!)
}
2- i was getting
Transport Security has Blocked a cleartext HTTP
solution was here.
Transport security has blocked a cleartext HTTP
use this
// taking the URL , then request image data, then assigne UIImage(data: responseData)
let imgURL: NSURL = NSURL(string: "www.example.com/image.jpg")!
let request: NSURLRequest = NSURLRequest(URL: imgURL)
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithRequest(request) {
(data,response,error) -> Void in
if ( error == nil && data != nil ) {
func display_image() {
// imageView.post.image = your UIImage
self.imageViewPost.image = UIImage(data: data!)
}
dispatch_async(dispatch_get_main_queue(), display_image)
}
}
task.resume()
// end of loading img
The image is a URL which is not saved locally inside the image.xassets, so you need to parse the URL using the extension given below.
// add the extension
extension UIImageView {
func loadImage(urlString: String) {
let url = URL(string: urlString)!
URLSession.shared.dataTask(with: url, completionHandler: { (data, respones, error) in
if error != nil {
print(error ?? "")
return
}
DispatchQueue.main.async {
self.image = UIImage(data: data!)
}
}).resume()
}
}
// call this statement in your vc (where you polpulate)
yourImageView.loadImage(urlString:yourUrl)