Unable to form a Circular Image in Swift - swift

I have used the following code in my view controller to display the image either from a camera or from the photo library in the circular form. But, I am not getting the desired result as there image is not filling up the entire circle. I have showed my code and the screenshot of the resulting image below. Appreciate your help! Thanks!
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var image1: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
image1.makeRounded()
}
}
//MARK:- Image Picker
extension ViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
//This is the tap gesture added on my UIImageView.
#IBAction func didTapOnImageView(sender: UITapGestureRecognizer) {
//call Alert function
showAlert()
}
//Show alert to selected the media source type.
private func showAlert() {
let alert = UIAlertController(title: "Image Selection", message: "From where you want to pick this image?", preferredStyle: .actionSheet)
alert.addAction(UIAlertAction(title: "Camera", style: .default, handler: {(action: UIAlertAction) in
self.getImage(fromSourceType: .camera)
}))
alert.addAction(UIAlertAction(title: "Photo Album", style: .default, handler: {(action: UIAlertAction) in
self.getImage(fromSourceType: .photoLibrary)
}))
alert.addAction(UIAlertAction(title: "Cancel", style: .destructive, handler: nil))
present(alert, animated: true, completion: nil)
}
//get image from source type
private func getImage(fromSourceType sourceType: UIImagePickerController.SourceType) {
//Check is source type available
if UIImagePickerController.isSourceTypeAvailable(sourceType) {
let imagePickerController = UIImagePickerController()
imagePickerController.delegate = self
imagePickerController.sourceType = sourceType
present(imagePickerController, animated: true, completion: nil)
}
}
//MARK:- UIImagePickerViewDelegate.
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
dismiss(animated: true) { [weak self] in
guard let image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage else { return }
//Setting image to your image view
self?.image1.image = image
}
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
picker.dismiss(animated: true)
}
}
extension UIImageView {
func makeRounded() {
layer.borderWidth = 1
layer.masksToBounds = false
layer.borderColor = UIColor.black.cgColor
layer.cornerRadius = frame.height / 2
clipsToBounds = true
}
}

It because your image is not square
You need to change your imageView content mode to aspect fill in the xib or storyboard
or you can do it by code too
imageView.contentMode = .scaleAspectFill

extension UIImageView {
func makeRounded() {
self.layer.borderWidth = 1
self.layer.masksToBounds = false
self.layer.borderColor = UIColor.black.cgColor
self.layer.cornerRadius = self.frame.height / 2
self.clipsToBounds = true
self.contentMode = .scaleAspectFill
}
}

Related

I wanna control crop area in ImagePicker

After selecting the image from the gallery, I can crop it as a still frame to crop it. I don't want this. I want to be able to change the crop size. I want to be able to change the crop area like in the second gif. How can I do this without resorting to a 3rd party library ?
Image Picker Manager:
class ImagePickerManager: NSObject, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
var picker = UIImagePickerController();
var alert = UIAlertController(title: "Fotoğraf Seç", message: nil, preferredStyle: .actionSheet)
var viewController: UIViewController?
var pickImageCallback : ((UIImage) -> ())?;
override init(){
super.init()
let cameraAction = UIAlertAction(title: "Kamerayı Aç", style: .default){
UIAlertAction in
self.openCamera()
}
let galleryAction = UIAlertAction(title: "Galeriden Seç", style: .default){
UIAlertAction in
self.openGallery()
}
let cancelAction = UIAlertAction(title: "İptal", style: .cancel){
UIAlertAction in
}
// Add the actions
picker.allowsEditing = true
picker.delegate = self
alert.addAction(cameraAction)
alert.addAction(galleryAction)
alert.addAction(cancelAction)
}
func pickImage(_ viewController: UIViewController, _ callback: #escaping ((UIImage) -> ())) {
pickImageCallback = callback;
self.viewController = viewController;
alert.popoverPresentationController?.sourceView = self.viewController!.view
viewController.present(alert, animated: true, completion: nil)
}
func openCamera(){
alert.dismiss(animated: true, completion: nil)
if(UIImagePickerController .isSourceTypeAvailable(.camera)){
picker.sourceType = .camera
self.viewController!.present(picker, animated: true, completion: nil)
} else {
let alertController: UIAlertController = {
let controller = UIAlertController(title: "Warning", message: "You don't have camera", preferredStyle: .alert)
let action = UIAlertAction(title: "OK", style: .default)
controller.addAction(action)
return controller
}()
viewController?.present(alertController, animated: true)
}
}
func openGallery(){
alert.dismiss(animated: true, completion: nil)
picker.sourceType = .photoLibrary
self.viewController!.present(picker, animated: true, completion: nil)
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
picker.dismiss(animated: true, completion: nil)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
if let image = info[.editedImage] as? UIImage {
pickImageCallback?(image)
} else if let image = info[.originalImage] as? UIImage {
pickImageCallback?(image)
}
picker.dismiss(animated: true, completion: nil)
}
#objc func imagePickerController(_ picker: UIImagePickerController, pickedImage: UIImage?) {
}
}
My code result:
I want do this:

UIImage Text Overlay - CGPoint Incorrect; Wrong Image Size?

I'm trying to overlay text on the bottom-left corner of a UIImage. I get the image from the device's camera roll, perform the overlay, then assign it to a UIImageView on a ViewController. The vertical CGPoint is never correct, however, as the height of the image seems to be different than what I'm getting from view.bounds.height. The following is what I've been working with; what change should I make to be able to get the correct CGPoint to assign the overlay label to? Thanks!
Result (should be bottom-left):
class PhotosVC: UIViewController, UINavigationControllerDelegate, UIImagePickerControllerDelegate {
#IBOutlet weak var photoView: UIImageView!
func presentPicker() {
let picker = UIImagePickerController()
picker.delegate = self
let alert = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
alert.addAction(UIAlertAction(title: "Camera", style: .default, handler: {
action in
picker.sourceType = .camera
self.present(picker, animated: true, completion: nil)
}))
alert.addAction(UIAlertAction(title: "Photo Library", style: .default, handler: {
action in
picker.sourceType = .photoLibrary
self.present(picker, animated: true, completion: nil)
}))
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
self.present(alert, animated: true, completion: nil)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
presentPicker()
}
override func viewDidLoad() {
super.viewDidLoad()
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
picker.dismiss(animated: true, completion: nil)
guard let image = info[.originalImage] as? UIImage else {
print("Issue getting photo from imagePickerController")
return }
let CGPointBottomLeft = photoView.bounds.height
print(photoView.bounds.height) // Is 336
let imageWithText = textToImage(drawText: "Overlayed text", inImage: image, atPoint: CGPoint(x: 0, y: CGPointBottomLeft))
self.photoView.image = imageWithText
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
dismiss(animated: true, completion: nil)
}
func textToImage(drawText text: String, inImage image: UIImage, atPoint point: CGPoint) -> UIImage {
let textColor = UIColor.white
let textFont = UIFont(name: "Helvetica Bold", size: 212)! // Only visible if huge
let scale = UIScreen.main.scale
UIGraphicsBeginImageContextWithOptions(image.size, false, scale)
let textFontAttributes = [
NSAttributedString.Key.font: textFont,
NSAttributedString.Key.foregroundColor: textColor,
] as [NSAttributedString.Key : Any]
image.draw(in: CGRect(origin: CGPoint.zero, size: image.size))
let rect = CGRect(origin: point, size: image.size)
text.draw(in: rect, withAttributes: textFontAttributes)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage!
}

Selected image won't change previously displayed image

I've got a simple set up to select an image from either camera or photo library. When I select a new photo, it doesn't change from the original photo that the app loads with.
I'm thinking it has something to do with the hierarchy (not sure if I'm using that in correct terms) of the code. I read my code as the image I select, I then set the variable "originalImage" to the selected image. So that should display right? Well, spoiler, I'm wrong.
import UIKit
class ViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
var originalImage = UIImage(named: "crossSection2.jpg")!
#IBOutlet weak var imageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
imageView.image = originalImage
}
#IBAction func onCameraClicked(_ sender: Any) {
let ac = UIAlertController(title: "Choose Image", message: nil, preferredStyle: .actionSheet)
ac.addAction(UIAlertAction(title: "Camera", style: .default, handler: { (action) in
self.showPicker(sourceType: .camera)
}))
ac.addAction(UIAlertAction(title: "Library", style: .default, handler: { (action) in
self.showPicker(sourceType: .photoLibrary)
}))
ac.addAction(UIAlertAction(title: "Cancel", style: .default, handler: nil))
self.present(ac, animated: true, completion: nil)
}
func showPicker(sourceType: UIImagePickerController.SourceType) {
let picker = UIImagePickerController()
picker.delegate = self
picker.sourceType = sourceType
self.present(picker, animated: true, completion: nil)
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingImage newImage : UIImage, editingInfo: [String : AnyObject]?) {
dismiss(animated: true, completion: nil)
self.originalImage = newImage
self.imageView.image = newImage
}
}
From https://developer.apple.com/documentation/uikit/uiimagepickercontrollerdelegate/1619152-imagepickercontroller
Deprecated Use imagePickerController:didFinishPickingMediaWithInfo:
instead.
so, try changing your code to:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
dismiss(animated: true, completion: nil)
self.originalImage = info[.originalImage] as! UIImage
self.imageView.image = (info[.originalImage] as! UIImage)
}
You need to update your UIImageView, not only "originalImage". Try:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingImage newImage : UIImage, editingInfo: [String : AnyObject]?) {
dismiss(animated: true, completion: nil)
self.originalImage = newImage
self.imageView.image = newImage
}

How do I add an image taken by camera or galery to a button?

I'm using an UIImagePickerController to choose a source to take a picture from. This picture should be set to an UIButton.
I know you can add an UIImage to an UIButton by string, like
someButton.setImage(UIImage(named:...)), but I need to set it by a variable which I create with taking the picture.
#IBOutlet weak var addPictureOutlet: UIButton!
func chooseSource() {
let imagePickerController = UIImagePickerController()
imagePickerController.delegate = self
let kameraAction = UIAlertAction(title: "Kamera",
style: .default) { (action) in
imagePickerController.sourceType = .camera
self.present(imagePickerController, animated: true, completion: nil)
}
let libraryAction = UIAlertAction(title: "Galerie",
style: .default) { (action) in
imagePickerController.sourceType = .photoLibrary
self.present(imagePickerController, animated: true, completion: nil)
}
let cancelAction = UIAlertAction(title: "Cancel",
style: .cancel)
let alert = UIAlertController(title: "Quelle",
message: "Wählen sie eine Quelle für die Klausur.",
preferredStyle: .actionSheet)
alert.addAction(kameraAction)
alert.addAction(libraryAction)
alert.addAction(cancelAction)
self.present(alert, animated: true) {
}
}
#IBAction func addPicture(_ sender: UIButton) {
chooseSource()
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
let image1 = info[UIImagePickerController.InfoKey.originalImage] as! UIImage
addPictureOutlet.setImage(image1, for: .normal)
}
}
I've tried this, but I can't really figure out why it doesn't work, there is no error while compiling or running and the UIImage of the UIButton does not change.
You should use like that. You cannot use a func in an action.
#IBOutlet weak var addPictureOutlet: UIButton!
func chooseSource() {
let imagePickerController = UIImagePickerController()
imagePickerController.delegate = self
let kameraAction = UIAlertAction(title: "Kamera",
style: .default) { (action) in
imagePickerController.sourceType = .camera
self.present(imagePickerController, animated: true, completion: nil)
}
let libraryAction = UIAlertAction(title: "Galerie",
style: .default) { (action) in
imagePickerController.sourceType = .photoLibrary
self.present(imagePickerController, animated: true, completion: nil)
}
let cancelAction = UIAlertAction(title: "Cancel",
style: .cancel)
let alert = UIAlertController(title: "Quelle",
message: "Wählen sie eine Quelle für die Klausur.",
preferredStyle: .actionSheet)
alert.addAction(kameraAction)
alert.addAction(libraryAction)
alert.addAction(cancelAction)
self.present(alert, animated: true) {
}
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
let image1 = info[UIImagePickerController.InfoKey.originalImage] as! UIImage
addPictureOutlet.setImage(image1, for: .normal)
}
#IBAction func addPicture(_ sender: UIButton) {
chooseSource()
}
As you said it is not going into imagePicker method, it seems you have missed delegate to work imagePicker method properly
Add UIImagePickerControllerDelegate and create a variable to assign UIImagePickerController var imagePicker = UIImagePickerController()
and set imagePicker.delegate = self

Swift Unexpectedly found nil while unwrapping an Optional value while pass image to another ViewController

I have two VCs. The first one contains an imagePicker from gallery and a callback function that sends and image to the chatLog... I want to send the selected photo to the 2nd VC
if let selectedImage = selectedImageFromPicker {
//self.callback?(selectedImage)
detailImageViewController.aImage = selectedImage
}
I created the 2nd VC as controller for PreviewImage with buttons cancel or accept. I tried to pass the image displayed on the 2nd VC back to 1st VC this way but it shows me:
Fatal error: Unexpectedly found nil while unwrapping an Optional value.
How can I fix that?
var t : EVTPhotoTekingHelper!
#objc func actionSend() {
if aImage != nil{
t.callback?(aImage!)
}
else {
print("nil")
}
dismiss(animated: true, completion: nil)
}
UPDATED:
My 1st VC
typealias PhotoTekingHelperCallBack = (UIImage?) -> ()
class EVTPhotoTekingHelper: NSObject {
// View controller on which AlertViewController and UIImageViewController are present
weak var viewController: UIViewController!
var imagePickerController: UIImagePickerController?
var callback: PhotoTekingHelperCallBack?
var photoTakinHelper: EVTPhotoTekingHelper!
// MARK: - Initialization
init(viewController: UIViewController, callback: #escaping PhotoTekingHelperCallBack) {
self.viewController = viewController
self.callback = callback
super.init()
showPhotoSourceSelection()
}
func showPhotoSourceSelection() {
let alertController = UIAlertController.init(title: nil,
message: "Message?",
preferredStyle: .actionSheet)
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
let photoLibraryAction = UIAlertAction(title: "from library", style: .default) { (action) in
self.showImagePickerController(sourceType: .photoLibrary)
}
alertController.addAction(cancelAction)
alertController.addAction(photoLibraryAction)
if UIImagePickerController.isFlashAvailable(for: .rear) {
let cameraAction = UIAlertAction.init(title: "from camera", style: .default, handler: { (action) in
self.showImagePickerController(sourceType: .camera)
})
alertController.addAction(cameraAction)
}
viewController.present(alertController, animated: true, completion: nil)
}
func showImagePickerController(sourceType: UIImagePickerControllerSourceType) {
imagePickerController = UIImagePickerController.init()
imagePickerController!.sourceType = sourceType
imagePickerController!.delegate = self
viewController.present(imagePickerController!, animated: true, completion: nil)
}
}
Extension from 1st VC
extension EVTPhotoTekingHelper: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
var selectedImageFromPicker: UIImage?
if let editedImage = info[UIImagePickerControllerEditedImage] as? UIImage {
selectedImageFromPicker = editedImage
} else if let originImage = info[UIImagePickerControllerOriginalImage] as? UIImage {
selectedImageFromPicker = originImage
}
let detailImageViewController = EVImagePreviewController()
let ncDetailImageViewController = UINavigationController(rootViewController: detailImageViewController)
if let selectedImage = selectedImageFromPicker {
//self.callback?(selectedImage)
detailImageViewController.aImage = selectedImage
}
viewController.dismiss(animated: false, completion: nil)
viewController.parent?.present(ncDetailImageViewController, animated: true, completion: nil)
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
viewController.dismiss(animated: false, completion: nil)
}
}
My 2nd VC
class EVImagePreviewController: UIViewController, UIScrollViewDelegate {
var t : EVTPhotoTekingHelper!
var aImageView: UIImageView!
var aImage: UIImage!
private var aScrollView: UIScrollView!
override func viewDidAppear(_ animated: Bool) {
aImageView = UIImageView(frame: CGRect(x: 0, y: 75, width: (aImage?.size.width)!, height: (aImage?.size.height)!))
aImageView.contentMode = .scaleAspectFit
aImageView.image = aImage
aScrollView = UIScrollView(frame: CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height))
aScrollView.backgroundColor = .clear
aScrollView.contentSize = CGSize(width: view.frame.size.width, height: view.frame.height)
aScrollView.minimumZoomScale = 0.2
aScrollView.maximumZoomScale = 2.3
aScrollView.clipsToBounds = true
aScrollView.delegate = self
aScrollView.addSubview(aImageView)
view.addSubview(aScrollView)
aImageView.center = CGPoint(x: aScrollView.bounds.midX, y: aScrollView.bounds.midY - 35)
}
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Add", style: .plain, target: self, action: #selector(actionSend))
navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Cancel", style: .plain, target: self, action: #selector(actionBack))
}
// MARK: - IBAction
#objc func actionBack() {
dismiss(animated: false, completion: nil)
}
#objc func actionSend() {
print("\(t)")
if aImage != nil{
t.callback?(aImage!)
}
else {
print("nil")
}
//self.callback?(aImage)
dismiss(animated: true, completion: nil)
}
// MARK: - UIScrollViewDelegate
func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return aImageView
}
func scrollViewDidZoom(_ scrollView: UIScrollView) {
let subView = scrollView.subviews[0]
let offsetX = max((scrollView.bounds.width - scrollView.contentSize.width) * 0.5, 0.0)
let offsetY = max((scrollView.bounds.height - scrollView.contentSize.height) * 0.5, 0.0)
subView.center = CGPoint(x: scrollView.contentSize.width * 0.5 + offsetX, y: scrollView.contentSize.height * 0.5 + offsetY)
}
}
Here you dismiss your first view controller before you present your 2nd one from the parent of your first view controller:
viewController.dismiss(animated: false, completion: nil)
To me so far doesn't make sense. Its not clear where is the callback implementation is.
My guess that the nil exception is not for the UIImage for sure. its somewhere
inside your callback implementation.