UIImageView images is not loading on iOS10 and Xcode 8? - uiimageview

UIImageView images are not loading either with downloading with Alamofire or using URL to convert to a data object and convert data object to a UIImage. My images on UITableViewCells are working but not the UIImageviews standalone in a UIView. It is giving me a blank.
UIImageViews: They are a subview of a UIView which is a subview of a UITableView
Here it is the code that Im using:
let imageURL = URL(string: _imageUrl)
let imageData = try? Data(contentsOf: imageURL!)
imageView.image = UIImage(data: imageData!)
Here is the extension that I'm using with Alamofire:
extension UIImageView {
func donwloadImageFrom(_ imageURL: String, contentMode: UIViewContentMode) {
let stringUrl = URL(string: imageURL)!
Alamofire.request(stringUrl, method: .get).response(completionHandler: { response in
if let imageData = response.data {
DispatchQueue.main.async(execute: {
self.contentMode = contentMode
self.image = UIImage(data: imageData)
})
}
})
}
}

I think the awakeFromNib() function bit changed.
I don't know exact reason but, after adding
layoutIfNeeded()
into awakeFromNib().
Made it works.

Related

Converting from UIImage to a SwiftUI Image results in a blank image of the same size

I am trying to convert a UIImage to a SwiftUI Image using the init(uiImage:) initializer. My UIImage itself is created from a CIImage generated by a CIQRCodeGenerator CIFilter. I am running my code on a Playground in Xcode 11.1 GM seed 1. Here is the entirety of my code:
import SwiftUI
import UIKit
func qrCodeImage(for string: String) -> Image? {
let data = string.data(using: String.Encoding.utf8)
guard let qrFilter = CIFilter(name: "CIQRCodeGenerator") else { return nil }
qrFilter.setValue(data, forKey: "inputMessage")
guard let ciImage = qrFilter.outputImage else { return nil }
let uiImage = UIImage(ciImage: ciImage)
let image = Image(uiImage: uiImage)
return image
}
let image = qrCodeImage(for: "fdsa")
And here is the result:
Even when I transform the image with CGAffineTransform(scaleX: 10, y: 10), the resulting SwiftUI Image at the end is still the same size, but blank.
Following solution provided in: Generating QR Code with SwiftUI shows empty picture
Here is the code:
var ciContext = CIContext()
func qrCodeImage(for string: String) -> Image? {
let data = string.data(using: String.Encoding.utf8)
guard let qrFilter = CIFilter(name: "CIQRCodeGenerator") else { return nil }
qrFilter.setValue(data, forKey: "inputMessage")
guard let ciImage = qrFilter.outputImage else { return nil }
let cgImage = ciContext.createCGImage(ciImage, from: ciImage.extent)
let uiImage = UIImage(cgImage: cgImage!)
let image = Image(uiImage: uiImage)
return image
}
let image = qrCodeImage(for: "fdsa")
Result:
screenshot in swift playground
Can confirm I encounter the same issue with a SwiftUI Image using a UIImage initialized from data. Can verify that the image is loaded when paused in debugging, but it does not display in the SwiftUI Image.
This solution worked for me: explicitly specify the image rendering mode. In my case I added the following: .renderingMode(.original)
#Eugene remark worked for me:
let image = Image(uiImage: uiImage).renderingMode(.original)

Saving UIImageView Locally

Right now I am able to have the user successfully take a picture using the camera and have their picture be uploaded into a imageview. However, if the user leaves that view controller when they eventually return the photo is no longer in that imageview. Is there anyway I am able to save the photo so that once a picture is taken and put into that imageview it is there until the user takes a different picture to replace it?
import UIKit
class ArsenalViewController: UIViewController,
UIImagePickerControllerDelegate, UINavigationControllerDelegate {
#IBOutlet var ball1: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func addPhoto1(_ sender: Any) {
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.camera){
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = UIImagePickerControllerSourceType.camera
imagePicker.allowsEditing = false
self.present(imagePicker, animated: true, completion: nil)
}
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let pickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage {
ball1.contentMode = .scaleToFill
ball1.image = pickedImage
}
picker.dismiss(animated: true, completion: nil)
}
First you need to save the image data somewhere (i.e. UserDefaults, Core Data, a database) and then retrieve it. UserDefaults is easy, try this:
//Encoding
let imageData:NSData = UIImageJPEGRepresentation(pickedImage!)! as NSData
//Saved image
UserDefaults.standard.set(imageData, forKey: "savedImage")
//Decode
if let data = UserDefaults.standard.object(forKey: "savedImage") as! NSData{
myImageView.image = UIImage(data: data as Data)
}
Encoding and saving image should happen right after updating your image and decoding should be done once the view has loaded all of its elements (viewDidAppear method).
After encoding and saving the image once, you can decode it anytime, even if the user left the VC and came back.

set image color of a template image

I have an image like this:
(Rendered as a template image)
I tried this code:
#IBOutlet weak var imgAdd: NSImageView!
imgAdd.layer?.backgroundColor = CGColor.white
Which only changes the background color of course.
Is there a way to change the color of this image programmatically?
So far I've tried the code below which doesn't work. (The image color doesn't change.)
func tintedImage(_ image: NSImage, tint: NSColor) -> NSImage {
guard let tinted = image.copy() as? NSImage else { return image }
tinted.lockFocus()
tint.set()
let imageRect = NSRect(origin: NSZeroPoint, size: image.size)
NSRectFillUsingOperation(imageRect, .sourceAtop)
tinted.unlockFocus()
return tinted
}
imgDok.image = tintedImage(NSImage(named: "myImage")!, tint: NSColor.red)
Swift 4
Updated answer for Swift 4
Please note, this NSImage extension is based on #Ghost108 and #Taehyung_Cho's answers, so a larger credit goes to them.
extension NSImage {
func tint(color: NSColor) -> NSImage {
let image = self.copy() as! NSImage
image.lockFocus()
color.set()
let imageRect = NSRect(origin: NSZeroPoint, size: image.size)
imageRect.fill(using: .sourceAtop)
image.unlockFocus()
return image
}
}
Swift 4 version
extension NSImage {
func image(withTintColor tintColor: NSColor) -> NSImage {
guard isTemplate else { return self }
guard let copiedImage = self.copy() as? NSImage else { return self }
copiedImage.lockFocus()
tintColor.set()
let imageBounds = NSMakeRect(0, 0, copiedImage.size.width, copiedImage.size.height)
imageBounds.fill(using: .sourceAtop)
copiedImage.unlockFocus()
copiedImage.isTemplate = false
return copiedImage
}
}
I found the solution with everyone's help:
(Swift 3)
func tintedImage(_ image: NSImage, tint: NSColor) -> NSImage {
guard let tinted = image.copy() as? NSImage else { return image }
tinted.lockFocus()
tint.set()
let imageRect = NSRect(origin: NSZeroPoint, size: image.size)
NSRectFillUsingOperation(imageRect, .sourceAtop)
tinted.unlockFocus()
return tinted
}
imgDok.image = tintedImage(NSImage(named: "myImage")!, tint: NSColor.red)
Important: in interface builder I had to set the "render as" setting of the image to "Default".
The other solutions don't work when the user wants to change between light and dark mode, this method solves that:
extension NSImage {
func tint(color: NSColor) -> NSImage {
return NSImage(size: size, flipped: false) { (rect) -> Bool in
color.set()
rect.fill()
self.draw(in: rect, from: NSRect(origin: .zero, size: self.size), operation: .destinationIn, fraction: 1.0)
return true
}
}
}
Be aware that if you use .withAlphaComponent(0.5) on an NSColor instance, that color loses support for switching between light/dark mode. I recommend using color assets to avoid that issue.
Had to modify #Ghost108's answer little bit for Xcode 9.2.
NSRectFillUsingOperation(imageRect, .sourceAtop)
to
imageRect.fill(using: .sourceAtop)
Thanks.
Since your image is inside an NSImageView, the following should work fine (available since macOS 10.14):
let image = NSImage(named: "myImage")!
image.isTemplate = true
let imageView = NSImageView(image: image)
imageView.contentTintColor = .green
The solution is to apply "contentTintColor" to your NSImageView instead of the NSImage.
See: Documentation
no need to copt:
extension NSImage {
func tint(with color: NSColor) -> NSImage {
self.lockFocus()
color.set()
let srcSpacePortionRect = NSRect(origin: CGPoint(), size: self.size)
srcSpacePortionRect.fill(using: .sourceAtop)
self.unlockFocus()
return self
}
}
Since you can't use the UIImage functions, you can try using CoreImage (CI). I don't know if there is an easier version but this one will work fore sure!
First you create the CIImage
let image = CIImage(data: inputImage.tiffRepresentation!)
Now you can apply all kinds of filters and other stuff to the image, it's a really powerful tool.
The documentation for CI: https://developer.apple.com/documentation/coreimage
The Filter List: https://developer.apple.com/library/content/documentation/GraphicsImaging/Reference/CoreImageFilterReference/index.html
Here is a simple filter example, you basically initialise a filter and then set the values for it, output it and repeat.
let yourFilterName = CIFilter(name: "FilterName")
yourFilterName!.setValue(SomeInputImage, forKey: kCIInputImageKey)
yourFilterName!.setValue(10, forKey: kCIInputRadiusKey)
let yourFilterName = yourFilterName!.outputImage
Now you can just convert the output back as NSImage.
let cgimg = context.createCGImage(yourFilterName!, from: yourFilterName!.extent)
let processedImage = NSImage(cgImage: cgimg!, size: NSSize(width: 0, height: 0))
Try this code it helps.
Swift 3
let theImageView = UIImageView(image: UIImage(named:"foo")!.withRenderingMode(.alwaysTemplate))
theImageView.tintColor = UIColor.red

UITextKit and exclusionPaths: undependable indent when editing

I have a problem with UITextKit using exclusionPaths: when I place an image inside a TextView, that I’m editing, first everything looks fine:
But when the „Done“-Button is tapped, it will look like this, the ident is wrong:
This is the class to store the informations for the image
class ImageClass {
var image: UIImage!
var imageView: UIImageView
var imageName: String!
var active:Bool
var exclusivePath: UIBezierPath!
init(image: UIImage!, imageName: String!) {
self.image = image
imageView = UIImageView(image: image!)
self.imageName = imageName
self.active = false
self.exclusivePath = nil
}
}
The user chooses the image in a UICollectionView that fires a delegate, when the image was selected. (imageViewObjects is an array, where I can put objects of ImageClass, so I can use mutiple images)
// MARK: - SelectImageDelegate
func selectedImage(name:String) {
let image = UIImage(named: name)
let imageViewObject = ImageClass(image: image, imageName: name)
self.imageViewObjects.append(imageViewObject)
imageViewObject.imageView.frame = CGRectMake(4, 7, width!, height!)
// define the exlusionPaths
let bezierPath = self.exclusionPathForImageView(imageViewObject.imageView)
imageViewObject.exclusivePath = bezierPath
self.updateExclusionPaths()
self.textView.addSubview(imageViewObject.imageView)
}
// set UIBezierPath for the UIImageView
func exclusionPathForImageView(imageView: UIImageView) -> UIBezierPath {
let bezierPath = UIBezierPath(rect:
CGRectMake(imageView.frame.origin.x, imageView.frame.origin.y,
imageView.frame.width, imageView.frame.height))
return bezierPath
}
func updateExclusionPaths() {
textView.textContainer.exclusionPaths = []
for imageViewObject in self.imageViewObjects {
textView.textContainer.exclusionPaths.append(imageViewObject.exclusivePath)
}
}
The context of bezierPath is ok.
When „Done“ is tapped, I stop the editing
let doneBarButton = UIBarButtonItem(title: "Done", style: .Done, target: view, action: Selector("endEditing:"))
In textViewDidEndEditing() now I do nothing.
I also tried it with a UIButton for the image. Similar result.
Any tip for a solution? plz help me!!!!
found a workaround:
func textViewShouldEndEditing(textView: UITextView) -> Bool {
textView.editable = false
}
and I had to add to set textView.editable = true, i.e. in viewDidLoad()
let tapGesture = UITapGestureRecognizer(target: self, action: "resetEditable")
tapGesture.numberOfTapsRequired = 1
self.textView.addGestureRecognizer(tapGesture)
func resetEditable() {
textView.editable = true
textView.becomeFirstResponder()
}

Swift - saving and retrieving images from userDefaults

I'm trying to save images retrieved from Parse.com like this:
let userImageFile = object["Image"] as PFFile
userImageFile.getDataInBackgroundWithBlock {
(imageData: NSData!, error: NSError!) -> Void in
if error == nil {
image = UIImage(data:imageData)
let imageToSave:NSData = UIImagePNGRepresentation(image)
self.saveImage(intRandomNumb, retImage: imageToSave)
}
}
where the saveImage-function looks like this:
func saveImage(imagepath:Int, retImage:NSData){
println("image is being saved")
let defaults = NSUserDefaults.standardUserDefaults()
let imagePathName = "\(imagepath)"
defaults.setObject(retImage, forKey: imagePathName)
}
and later, I'm trying to display this image like this:
var point = gestureRecognizer.locationInView(self.tv)
if let indexPath = self.tv.indexPathForRowAtPoint(point)
{
let data = mainList[indexPath.row] as SecondModel
let fileRef = data.fileReference
let intFileRef = Int(fileRef)
println(intFileRef)
let defaults = NSUserDefaults.standardUserDefaults()
let usedKeyName = "\(intFileRef)"
if let photo = defaults.objectForKey(usedKeyName) as? UIImage {
println("Image created")
let photo = defaults.objectForKey(usedKeyName) as UIImage
var imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height))
imageView.image = photo
self.view.addSubview(imageView)
}
and the "Image created" never gets printed which means the retrieving somehow doesn't work.
I'm not quite sure if you're able to save images to the userdefaults like I've done here, but that was the best I could come up with, and I couldn't find any previous questions like this for Swift.
Any suggestions on how to proceed would be appreciated.
SOLUTION: The problem was that I tried to load the image directly as a UIImage. I also had to convert the NSData to a UIImage, this all happens in the last section of the code displayed above. Finally my code looks like this:
if let photo = defaults.objectForKey("\(intFileRef)") as? NSData {
println("Image created")
let photo = defaults.objectForKey("\(intFileRef)") as NSData
let imageToView:UIImage = UIImage(data: photo)
var imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: self.view.frame.width, height: self.view.frame.height))
imageView.image = imageToView
self.view.addSubview(imageView)
}
I hope this can help others struggling with something similar to this.
Swift 3
Hey, try this beautiful code here:
Convert your UIImage to Data.
PNG:
yourDataImagePNG = UIImagePNGRepresentation(yourUIImageHere)
JPEG :
yourDataImageJPG = UIImage(data: yourUIImageHere,scale:1.0)
Save in UserDefaults.
UserDefaults().set(yourDataImagePNG, forKey: "image")
Recover from:
UserDefaults.standard.object(forKey: "image") as! Data
I hope to help!
It seems like you do not call defaults.synchronize() so it's not written to the defaults file.

Resources