How to crop image swift - swift

in my project i have a UIImageView with square format for the image of the user profile, but when i add an image for example from the library, it appears shapeless. I have finded a code to crop the images to square format but i don't understand where to insert it in my code to crop the selected image from library or a new photo. Can you help me?
Here the code:
ImageUtil.swift
import UIKit
class ImageUtil: NSObject {
func cropToSquare(image originalImage: UIImage) -> UIImage {
// Create a copy of the image without the imageOrientation property so it is in its native orientation (landscape)
let contextImage: UIImage = UIImage(CGImage: originalImage.CGImage)!
// Get the size of the contextImage
let contextSize: CGSize = contextImage.size
let posX: CGFloat
let posY: CGFloat
let width: CGFloat
let height: CGFloat
// Check to see which length is the longest and create the offset based on that length, then set the width and height of our rect
if contextSize.width > contextSize.height {
posX = ((contextSize.width - contextSize.height) / 2)
posY = 0
width = contextSize.height
height = contextSize.height
} else {
posX = 0
posY = ((contextSize.height - contextSize.width) / 2)
width = contextSize.width
height = contextSize.width
}
let rect: CGRect = CGRectMake(posX, posY, width, height)
// Create bitmap image from context using the rect
let imageRef: CGImageRef = CGImageCreateWithImageInRect(contextImage.CGImage, rect)
// Create a new image based on the imageRef and rotate back to the original orientation
let image: UIImage = UIImage(CGImage: imageRef, scale: originalImage.scale, orientation: originalImage.imageOrientation)!
return image
}
}
AddController.swift
import UIKit
class AddController: UIViewController, UITextFieldDelegate, CameraManagerDelegate {
#IBOutlet var immagine: UIImageView!
#IBOutlet var fieldNome: UITextField!
var immagineSelezionata : UIImage?
override func viewDidLoad() {
super.viewDidLoad()
navigationController!.navigationBar.barStyle = UIBarStyle.BlackTranslucent
navigationController!.navigationBar.tintColor = UIColor.whiteColor()
navigationController!.navigationBar.barTintColor = UIColor(red: 60/255.0, green: 172/255.0, blue: 183/255.0, alpha: 1.0)
//navigationItem.titleView = UIImageView(image: UIImage(named: "logo"))
//tableView.backgroundColor = UIColor(red: 60/255.0, green: 172/255.0, blue: 183/255.0, alpha: 1.0)
UIApplication.sharedApplication().setStatusBarStyle(UIStatusBarStyle.LightContent, animated: false)
let singleTap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: "selezionaFoto:")
singleTap.numberOfTapsRequired = 1
singleTap.numberOfTouchesRequired = 1
self.immagine.addGestureRecognizer(singleTap)
self.immagine.userInteractionEnabled = true
fieldNome.delegate = self
CameraManager.sharedInstance.delegate = self
var keyboardToolbar = UIToolbar(frame: CGRectMake(0, 0, self.view.bounds.size.width, 44))
keyboardToolbar.barStyle = UIBarStyle.BlackTranslucent
keyboardToolbar.backgroundColor = UIColor(red: 60/255.0, green: 172/255.0, blue: 183/255.0, alpha: 1.0)
keyboardToolbar.tintColor = UIColor.whiteColor()
var flex = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.FlexibleSpace, target: nil, action: nil)
var save = UIBarButtonItem(title: NSLocalizedString("Done", comment: ""),
style: UIBarButtonItemStyle.Done,
target: fieldNome,
action: "resignFirstResponder")
keyboardToolbar.setItems([flex, save], animated: false)
fieldNome.inputAccessoryView = keyboardToolbar
}
func myUIImageViewTapped(recognizer: UITapGestureRecognizer) {
if(recognizer.state == UIGestureRecognizerState.Ended){
println("myUIImageView has been tapped by the user.")
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func annulla(sender: UIBarButtonItem) {
dismissViewControllerAnimated(true, completion: nil)
}
#IBAction func salva(sender: UIBarButtonItem) {
if fieldNome.text.isEmpty
{
return
}
var profilo = ProfiloModel(nomeIn: fieldNome.text,
immagineIn: UIImage(named:"icon-profile")!)
if let img = immagineSelezionata {
profilo.immagine = img
}
//DataManager.sharedInstance.storage.insert(profilo, atIndex: 0)
DataManager.sharedInstance.storage.append(profilo)
DataManager.sharedInstance.salvaArray()
DataManager.sharedInstance.master.tableView.reloadData()
dismissViewControllerAnimated(true, completion: nil)
}
#IBAction func selezionaFoto(sender: UITapGestureRecognizer) {
fieldNome.resignFirstResponder()
func selezionaLibreria(action : UIAlertAction!) {
UIApplication.sharedApplication().setStatusBarStyle(UIStatusBarStyle.Default, animated: true)
CameraManager.sharedInstance.newImageFromLibraryForController(self, editing: false)
}
func scattaFoto(action : UIAlertAction!) {
UIApplication.sharedApplication().setStatusBarStyle(UIStatusBarStyle.Default, animated: true)
var circle = UIImageView(frame: UIScreen.mainScreen().bounds)
circle.image = UIImage(named: "overlay")
CameraManager.sharedInstance.newImageShootForController(self, editing: false, overlay:circle)
}
var myActionSheet = UIAlertController(title: NSLocalizedString("ACTION_IMAGE_TITLE", comment: ""),
message: NSLocalizedString("ACTION_IMAGE_TEXT", comment: ""),
preferredStyle: UIAlertControllerStyle.ActionSheet)
myActionSheet.addAction(UIAlertAction(title: NSLocalizedString("BUTTON_LIBRARY", comment: ""),
style: UIAlertActionStyle.Default,
handler: selezionaLibreria))
myActionSheet.addAction(UIAlertAction(title: NSLocalizedString("BUTTON_SHOOT", comment: ""),
style: UIAlertActionStyle.Default,
handler: scattaFoto))
myActionSheet.addAction(UIAlertAction(title: NSLocalizedString("BUTTON_CANCEL", comment: ""),
style: UIAlertActionStyle.Cancel,
handler: nil))
self.presentViewController(myActionSheet, animated: true, completion: nil)
}
func textFieldShouldReturn(textField: UITextField) -> Bool {
textField.resignFirstResponder() // chiudere la tastiera nei campi di testo
return true
}
func incomingImage(image: UIImage) {
UIApplication.sharedApplication().setStatusBarStyle(UIStatusBarStyle.LightContent, animated: true)
immagine.image = image
immagineSelezionata = image
}
func cancelImageSelection() {
UIApplication.sharedApplication().setStatusBarStyle(UIStatusBarStyle.LightContent, animated: true)
}
}

I Found a link can help you
CGBitmapContextCreate & CGContextDrawImage
Core Graphics / Quartz 2D offers a lower-level set of APIs that allow for more advanced configuration. Given a CGImage, a temporary bitmap context is used to render the scaled image, using CGBitmapContextCreate() and
CGBitmapContextCreateImage():
let image = UIImage(contentsOfFile: self.URL.absoluteString!).CGImage
let width = CGImageGetWidth(image) / 2.0
let height = CGImageGetHeight(image) / 2.0
let bitsPerComponent = CGImageGetBitsPerComponent(image)
let bytesPerRow = CGImageGetBytesPerRow(image)
let colorSpace = CGImageGetColorSpace(image)
let bitmapInfo = CGImageGetBitmapInfo(image)
let context = CGBitmapContextCreate(nil, width, height,
bitsPerComponent, bytesPerRow, colorSpace, bitmapInfo)
CGContextSetInterpolationQuality(context, kCGInterpolationHigh)
CGContextDrawImage(context, CGRect(origin: CGPointZero, size: CGSize(width: CGFloat(width), height: CGFloat(height))), image)
let scaledImage = UIImage(CGImage: CGBitmapContextCreateImage(context))
CGBitmapContextCreate takes several arguments to construct a context with desired dimensions and amount of memory for each channel within a given colorspace. In the example, these values are fetched from the CGImage. Next, CGContextSetInterpolationQuality allows for the context to interpolate pixels at various levels of fidelity. In this case, kCGInterpolationHigh is passed for best results. CGContextDrawImage allows for the image to be drawn at a given size and position, allowing for the image to be cropped on a particular edge or to fit a set of image features, such as faces. Finally, CGBitmapContextCreateImage creates a CGImage from the context.
Font Image Resizing Techiniques

See Image-Cropper.
Excerpt:
func btnCropAndSaveClicked(sender: UIButton!) {
print("save btn clicked")
let scale = 1 / scrollView.zoomScale
let visibleRect = CGRect(
x: (scrollView.contentOffset.x + scrollView.contentInset.left) * scale,
y: (scrollView.contentOffset.y + scrollView.contentInset.top) * scale,
width: CROP_WINDOW_WIDTH * scale,
height: CROP_WINDOW_HEIGHT * scale)
let imageRef: CGImageRef? = CGImageCreateWithImageInRect(processedImage.CGImage, visibleRect)!
let croppedImage:UIImage = UIImage(CGImage: imageRef!)
UIImageWriteToSavedPhotosAlbum(croppedImage, nil, nil, nil)
showResultMessage()
}
That code allows you to zoom in and out the selected picture, move it around and crop the desired area of that picture. It's simple to implement, everything is done on the ViewController. Hope this solves your problem.

Related

in 1 function take 2 screenshots of different size images

I want my swift code below to take 2 screenshots. One screen shot should be the entire view from the top to 20 percent and the other from 20 percent to 100 percent of the height. I created a image that displays what exactly I am looking for. The images should have different ratios. I dont really know what else to add.
var drawbox = Canvas()
#objc func image(_ image: UIImage, didFinishSavingWithError error: Error?, contextInfo: UnsafeRawPointer) {
if let error = error {
// we got back an error!
let ac = UIAlertController(title: "Save error", message: error.localizedDescription, preferredStyle: .alert)
ac.addAction(UIAlertAction(title: "OK", style: .default))
present(ac, animated: true)
} else {
let ac = UIAlertController(title: "Saved!", message: "Your altered image has been saved to your photos.", preferredStyle: .alert)
ac.addAction(UIAlertAction(title: "OK", style: .default))
present(ac, animated: true)
}
}
#objc func saving(){
let vex = self.view.screenshot(for: drawbox.frame, clipToBounds: true)
UIImageWriteToSavedPhotosAlbum(vex, self, #selector(image(_:didFinishSavingWithError:contextInfo:)), nil)
}
extension UIView {
/// Takes a screenshot of a UIView, with an option to clip to view bounds and place a waterwark image
/// - Parameter rect: offset and size of the screenshot to take
/// - Parameter clipToBounds: Bool to check where self.bounds and rect intersect and adjust size so there is no empty space
/// - Parameter watermark: UIImage of the watermark to place on top
func screenshot(for rect: CGRect, clipToBounds: Bool = true, with watermark: UIImage? = nil) -> UIImage {
var imageRect = rect
if clipToBounds {
imageRect = bounds.intersection(rect)
}
return UIGraphicsImageRenderer(bounds: imageRect).image { _ in
drawHierarchy(in: CGRect(origin: .zero, size: bounds.size), afterScreenUpdates: true)
watermark?.draw(in: CGRect(origin: imageRect.origin, size: CGSize(width: 32, height: 32))) // update origin to place watermark where you want, with this update it will place it in top left or screenshot.
}
}
}
you can split the image after saving it I use this function to split the image into two half you can change the ratio
extension UIImage {
func topHalf(pers:CGFloat)-> UIImage? {
guard let image = cgImage?
.cropping(to: CGRect(origin: .zero,
size: CGSize(width: size.width * scale,
height: (size.height * scale) * pers )))
else { return nil }
return UIImage(cgImage: image, scale: 1, orientation: imageOrientation)
}
func bottomHalf(pers:CGFloat)-> UIImage? {
let scaledHight = (size.height * scale)
guard let image = cgImage?
.cropping(to: CGRect(origin: CGPoint(x: 0,
y: scaledHight - (scaledHight * pers).rounded()),
size: CGSize(width: size.width * scale,
height: scaledHight)))
else {
print("Null")
return nil }
return UIImage(cgImage: image)
}
func save(_ name: String) {
// let path: String = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first!
let path = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
let url = URL(fileURLWithPath: path.path).appendingPathComponent(name)
try! self.pngData()?.write(to: url)
print("saved image at \(url)")
}
}
you can use it like this
let vex = self.view.screenshot(for: self.view.frame, clipToBounds: true)
vex .save("full.png")
let top = vex.topHalf(pers: 0.2)
top?.save("Top.png")
let bottom = vex.bottomHalf(pers: 0.8)
bottom?.save("bottom.png")

UIProgressView setProgress issue

I've encountered an issue using a UIProgressView where low values (1% - about 10%) look off. You can see with the example above that 97% looks accurate while 2% does not.
Here's the code for setting colors:
self.progressView.trackTintColor = UIColor.green.withAlphaComponent(0.3)
self.progressView.tintColor = UIColor.green.withAlphaComponent(1.0)
But, if I comment out the trackTintColor or the tintColor, then the 2% looks correct. Why when using these together does it cause this issue? Just an Xcode bug? Has anyone resolved this before?
I've experienced the same issue in my project. For me it's fixed by using progressTintColor instead of tintColor.
progressView.progressTintColor = UIColor.green.withAlphaComponent(1.0)
progressView.trackTintColor = UIColor.green.withAlphaComponent(0.3)
you need to create color image
SWIFT 3 Example:
class ViewController: UIViewController {
#IBOutlet weak var progressView: UIProgressView!
#IBAction func lessButton(_ sender: UIButton) {
let percentage = 20
let invertedValue = Float(100 - percentage) / 100
progressView.setProgress(invertedValue, animated: true)
}
#IBAction func moreButton(_ sender: UIButton) {
let percentage = 80
let invertedValue = Float(100 - percentage) / 100
progressView.setProgress(invertedValue, animated: true)
}
override func viewDidLoad() {
super.viewDidLoad()
//create gradient view the size of the progress view
let gradientView = GradientView(frame: progressView.bounds)
//convert gradient view to image , flip horizontally and assign as the track image
progressView.trackImage = UIImage(view: gradientView).withHorizontallyFlippedOrientation()
//invert the progress view
progressView.transform = CGAffineTransform(scaleX: -1.0, y: -1.0)
progressView.progressTintColor = UIColor.black
progressView.progress = 1
}
}
extension UIImage{
convenience init(view: UIView) {
UIGraphicsBeginImageContext(view.frame.size)
view.layer.render(in: UIGraphicsGetCurrentContext()!)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
self.init(cgImage: (image?.cgImage)!)
}
}
#IBDesignable
class GradientView: UIView {
private var gradientLayer = CAGradientLayer()
private var vertical: Bool = false
override func draw(_ rect: CGRect) {
super.draw(rect)
// Drawing code
//fill view with gradient layer
gradientLayer.frame = self.bounds
//style and insert layer if not already inserted
if gradientLayer.superlayer == nil {
gradientLayer.startPoint = CGPoint(x: 0, y: 0)
gradientLayer.endPoint = vertical ? CGPoint(x: 0, y: 1) : CGPoint(x: 1, y: 0)
gradientLayer.colors = [UIColor.green.cgColor, UIColor.red.cgColor]
gradientLayer.locations = [0.0, 1.0]
self.layer.insertSublayer(gradientLayer, at: 0)
}
}
}

ScreenShot issue in ARKit in swift

i have application that uses ARSCNView. i'm trying to take a screenshot on click of a button and saved that image in the gallery. But when i take a screenshot it does not show the content on that screen. Just show that image, i have some labels on it but it does not show that in an image. This is my code,
#IBAction func captureImage(_ sender: Any) {
image = sceneView.snapshot()
UIImageWriteToSavedPhotosAlbum(image!, nil, nil, nil)
}
How can i show that labels and buttons on ARSCView in a screenshot?
snapshot() will only take screenshot of Scene.
To take screenshot of Scene with Labels and Buttons use below method:
func snapshot(of rect: CGRect? = nil) -> UIImage? {
UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, self.view.isOpaque, 0)
self.view.drawHierarchy(in: self.view.bounds, afterScreenUpdates: true)
let fullImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
guard let image = fullImage, let rect = rect else { return fullImage }
let scale = image.scale
let scaledRect = CGRect(x: rect.origin.x * scale, y: rect.origin.y * scale, width: rect.size.width * scale, height: rect.size.height * scale)
guard let cgImage = image.cgImage?.cropping(to: scaledRect) else { return nil }
return UIImage(cgImage: cgImage, scale: scale, orientation: .up)
}
To Take Screenshot:
#IBAction func takeScreenShotTapped(_ sender: Any) {
let screenShot = snapshot(of: CGRect(x: 80, y: 80, width: 100, height: 100))
}
If you want to take screenshot of fullscreen then just call snapshot().
Hope this will help you :)

UIImage rotates after being cropped

I have a class setup that allows users to add an image from their library, crop it and save it.
The code is set up so that if the retrieved image is portrait, a portrait shaped border appears to all them to align before cropping and if Landscape, a landscaped border appears.
If the image selected is a regular shaped image, all works well. However, if the image retrieved is portrait and not of a regular ratio (meaning closer to a square shape while not actually being square), the image rotates after being cropped. It seems as thought the system is treating it like a landscape image.
Here is an example of before and after crop. Even if I zoom in and make the image cover the entire screen, it rotates the image:
import Foundation
import UIKit
class SelectImageViewController: UIViewController, UIImagePickerControllerDelegate,UINavigationControllerDelegate,UIScrollViewDelegate{
#IBOutlet weak var imageView: UIImageView!
#IBOutlet weak var imageConstraintTop: NSLayoutConstraint!
#IBOutlet weak var imageConstraintRight: NSLayoutConstraint!
#IBOutlet weak var imageConstraintLeft: NSLayoutConstraint!
#IBOutlet weak var imageConstraintBottom: NSLayoutConstraint!
var lastZoomScale: CGFloat = -1
var imageName: String = ""
var userPhotoUUID = UUID().uuidString
let userDefault = UserDefaults.standard
var userDatabase: UserDatabase = UserDatabase()
let picker = UIImagePickerController()
#IBOutlet var scrollView: UIScrollView!{
didSet{
scrollView.delegate = self
scrollView.minimumZoomScale = 1.0
scrollView.maximumZoomScale = 5.0
}
}
#IBOutlet weak var ratioSelector: UISegmentedControl!
#IBOutlet var cropAreaViewL: CropAreaViewL!
var cropAreaL:CGRect{
get{
let factor = imageView.image!.size.width/view.frame.width
let scale = 1/scrollView.zoomScale
let imageFrame = imageView.imageFrame()
let x = (scrollView.contentOffset.x + cropAreaViewL.frame.origin.x - imageFrame.origin.x) * scale * factor
let y = (scrollView.contentOffset.y + cropAreaViewL.frame.origin.y - imageFrame.origin.y) * scale * factor
let width = cropAreaViewL.frame.size.width * scale * factor
let height = cropAreaViewL.frame.size.height * scale * factor
return CGRect(x: x, y: y, width: width, height: height)
}
}
#IBOutlet var cropAreaViewP: CropAreaViewP!
var cropAreaP:CGRect{
get{
let factor = imageView.image!.size.height/view.frame.height
let scale = 1/scrollView.zoomScale
let imageFrame = imageView.imageFrame()
let x = (scrollView.contentOffset.x + cropAreaViewP.frame.origin.x - imageFrame.origin.x) * scale * factor
let y = (scrollView.contentOffset.y + cropAreaViewP.frame.origin.y - imageFrame.origin.y) * scale * factor
let width = cropAreaViewP.frame.size.width * scale * factor
let height = cropAreaViewP.frame.size.height * scale * factor
return CGRect(x: x, y: y, width: width, height: height)
}
}
fileprivate var speciePhotos: Array<SpeciePhotoModel> = [SpeciePhotoModel]()
func randomNumber(range: ClosedRange<Int> = 30000...99998) -> Int {
let min = range.lowerBound
let max = range.upperBound
return Int(arc4random_uniform(UInt32(1 + max - min))) + min
}
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "+", style: .plain, target: self, action: #selector(SelectImageViewController.add(_:)))
let id = randomNumber()
userDefault.set(id, forKey: "photoID")
self.cropAreaViewP.isHidden = true
self.cropAreaViewL.isHidden = true
self.cropAreaViewL.layer.borderColor = (UIColor.red).cgColor
self.cropAreaViewL.layer.borderWidth = 1.0
self.cropAreaViewP.layer.borderColor = (UIColor.red).cgColor
self.cropAreaViewP.layer.borderWidth = 1.0
self.add.layer.cornerRadius = 6.0
self.ratioSelector.layer.cornerRadius = 6.0
self.tabBarController?.tabBar.isHidden = true
self.add.isHidden = true
self.ratioSelector.isHidden = true
updateZoom()
}
func updateConstraints() {
if let image = imageView.image {
let imageWidth = image.size.width
let imageHeight = image.size.height
let viewWidth = scrollView.bounds.size.width
let viewHeight = scrollView.bounds.size.height
// center image if it is smaller than the scroll view
var hPadding = (viewWidth - scrollView.zoomScale * imageWidth) / 2
if hPadding < 0 { hPadding = 0 }
var vPadding = (viewHeight - scrollView.zoomScale * imageHeight) / 2
if vPadding < 0 { vPadding = 0 }
imageConstraintLeft.constant = hPadding
imageConstraintRight.constant = hPadding
imageConstraintTop.constant = vPadding
imageConstraintBottom.constant = vPadding
view.layoutIfNeeded()
}
}
fileprivate func updateZoom() {
if let image = imageView.image {
var minZoom = min(scrollView.bounds.size.width / image.size.width,
scrollView.bounds.size.height / image.size.height)
if minZoom > 1 { minZoom = 1 }
scrollView.minimumZoomScale = 0.3 * minZoom
// Force scrollViewDidZoom fire if zoom did not change
if minZoom == lastZoomScale { minZoom += 0.000001 }
scrollView.zoomScale = minZoom
lastZoomScale = minZoom
}
}
#IBAction func ratioSelector(_ sender: AnyObject) {
switch ratioSelector.selectedSegmentIndex
{
case 0:// Landscape
self.cropAreaViewP.isHidden = true
self.cropAreaViewL.isHidden = false
case 1: // Portrait
self.cropAreaViewL.isHidden = true
self.cropAreaViewP.isHidden = false
default:
break;
}
}
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
dismiss(animated: true, completion: nil)
}
#IBOutlet weak var add : UIButton!
#IBAction func add(_ sender: UIButton) {
imageView.image = nil
let picker = UIImagePickerController()
picker.delegate = self
picker.sourceType = .photoLibrary
picker.allowsEditing = false
self.present(picker, animated: true, completion: nil)
self.ratioSelector.isHidden = false
self.add.isHidden = false
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Crop", style: .plain, target: self, action: #selector(SelectImageViewController.crop(_:)))
}
#IBAction func change(_ sender: UIButton) {
imageView.image = nil
let picker = UIImagePickerController()
picker.delegate = self
picker.sourceType = .photoLibrary
picker.allowsEditing = false
self.present(picker, animated: true, completion: nil)
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Crop", style: .plain, target: self, action: #selector(SelectImageViewController.crop(_:)))
}
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
let chosenImage = info[UIImagePickerControllerOriginalImage] as! UIImage
if chosenImage.size.height > chosenImage.size.width
{
self.cropAreaViewL.isHidden = true
self.cropAreaViewP.isHidden = false
self.ratioSelector.selectedSegmentIndex = 1
imageView.image = chosenImage
}
else
{
self.cropAreaViewP.isHidden = true
self.cropAreaViewL.isHidden = false
self.ratioSelector.selectedSegmentIndex = 0
imageView.image = chosenImage
}
self.dismiss(animated: true, completion: nil)
}
#IBAction func crop(_ sender: UIButton) {
if cropAreaViewP.isHidden == true {
self.cropAreaViewL.layer.borderColor = (UIColor.clear).cgColor
let croppedCGImage = imageView.image?.cgImage?.cropping(to: cropAreaL)
let croppedImage = UIImage(cgImage: croppedCGImage!)
imageView.image = croppedImage
scrollView.zoomScale = 1
} else {
self.cropAreaViewP.layer.borderColor = (UIColor.clear).cgColor
let croppedCGImage = imageView.image?.cgImage?.cropping(to: cropAreaP)
let croppedImage = UIImage(cgImage: croppedCGImage!)
imageView.image = croppedImage
scrollView.zoomScale = 1
}
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Next", style: .plain, target: self, action: #selector(SelectImageViewController.saveButtonAction(_:)))
}
}
extension UIImageView{
func imageFrame()->CGRect{
let imageViewSize = self.frame.size
guard let imageSize = self.image?.size else{return CGRect.zero}
let imageRatio = imageSize.width / imageSize.height
let imageViewRatio = imageViewSize.width / imageViewSize.height
if imageRatio < imageViewRatio { // Portrait
let scaleFactor = imageViewSize.height / imageSize.height
let width = imageSize.width * scaleFactor
let topLeftX = (imageViewSize.width - width) * 0.5
return CGRect(x: topLeftX, y: 0, width: width, height: imageViewSize.height)
}else{ // Landscape
let scaleFactor = imageViewSize.width / imageSize.width
let height = imageSize.height * scaleFactor
let topLeftY = (imageViewSize.height - height) * 0.5
return CGRect(x: 0, y: topLeftY, width: imageViewSize.width, height: height)
}
}
}
class CropAreaViewL: UIView {
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
return false
}
}
class CropAreaViewP: UIView {
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
return false
}
}
Any help would be huge.
You can use max method to make sure you don't get a value lower than zero:
let vPadding = max((viewHeight - scrollView.zoomScale * imageHeight) / 2, 0)
If you need to make your image squared you can do it as follow:
extension UIImage {
var isPortrait: Bool { return size.height > size.width }
var isLandscape: Bool { return size.width > size.height }
var breadth: CGFloat { return min(size.width, size.height) }
var breadthSize: CGSize { return CGSize(width: breadth, height: breadth) }
var squared: UIImage? {
guard let cgImage = cgImage?.cropping(to:
CGRect(origin: CGPoint(x: isLandscape ? floor((size.width-size.height)/2) : 0, y: isPortrait ? floor((size.height-size.width)/2) : 0),
size: breadthSize)) else { return nil }
return UIImage(cgImage: cgImage)
}
}
To fix the orientation issue you need to redraw your image you can use the flatten property from this answer.
Playground:
let profilePicture = UIImage(data: try! Data(contentsOf: URL(string:"https://i.stack.imgur.com/Xs4RX.jpg")!))!
if let squared = profilePicture.squared {
squared
}

How to change UISlider Thumb Appearance when Touch Ends

I am changing the color of a UISlider by calling .thumbTintColor
#IBAction func slider1Master(sender: AnyObject) {
slider1.thumbTintColor = UIColor.orangeColor()}
It works, but I want the color to change back to it's original state when the touch ends (user lifts finger).
Does anyone have any suggestions? Thank you.
You can use "setThumbImage" instead.
Then you have the option of setting an image for a specific state of action.
For the image, just create a rounder image with the color you desire.
//Creating an Image with rounded corners:
extension UIImage {
class func createThumbImage(size: CGFloat, color: UIColor) -> UIImage {
let layerFrame = CGRectMake(0, 0, size, size)
let shapeLayer = CAShapeLayer()
shapeLayer.path = CGPathCreateWithEllipseInRect(layerFrame.insetBy(dx: 1, dy: 1), nil)
shapeLayer.fillColor = color.CGColor
shapeLayer.strokeColor = color.colorWithAlphaComponent(0.65).CGColor
let layer = CALayer.init()
layer.frame = layerFrame
layer.addSublayer(shapeLayer)
return self.imageFromLayer(layer)
}
class func imageFromLayer(layer: CALayer) -> UIImage {
UIGraphicsBeginImageContextWithOptions(layer.frame.size, false, UIScreen.mainScreen().scale)
layer.renderInContext(UIGraphicsGetCurrentContext()!)
let outputImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return outputImage
}
}
//Setting the image for a selected state of UISlider:
func setupSlider() {
let size:CGFloat = 12
let highlightedStateOrangeColorImage = UIImage.createThumbImage(size, color: UIColor.orangeColor())
let defaultStateBlueColorImage = UIImage.createThumbImage(size, color: UIColor.blueColor())
self.slider.setThumbImage(highlightedStateOrangeColorImage, forState: UIControlState.Highlighted)
self.slider.setThumbImage(defaultStateBlueColorImage, forState: UIControlState.Normal)
}
You can safely accept McMatan’s solution as your answer. It is good for several reasons.
the colour changes back to its original state when the user lifts a finger, as you requested
using the extension to create a shape does away with image assets for the UISlider
it could also be used to draw images for circular UIButtons and circular UIViews.
it can also create a shape with colours matching other UISlider design elements (if so desired).
The code below does just that. I used McMatan’s UIImage extension with no changes other than translation to Swift 3. But I have split his function setUpSlider() into two, one for drawing the circular image in its default state, the other for drawing it in its highlighted state.
By accepting McMatan’s solution, you will encourage those who contribute their experience and free time to continue making this forum worthwhile for the rest of us. So please do.
class ViewController: UIViewController {
var slider: UISlider!
let defaultColour = UIColor.blue
let highlightedColour = UIColor.orange
let thumbSize = 20
override func viewDidLoad() {
super.viewDidLoad()
slider = UISlider(frame: CGRect(x: 0, y: 0, width: 200, height: 23))
slider.minimumValue = 0
slider.minimumTrackTintColor = defaultColour
slider.maximumValue = 100
slider.maximumTrackTintColor = highlightedColour
slider.center = view.center
slider.value = slider.maximumValue / 2.0
let highlightedImage = makeHighlightedImage()
let defaultImage = makeDefaultImage()
slider.setThumbImage(highlightedImage, for: UIControlState.highlighted)
slider.setThumbImage(defaultImage, for: UIControlState.normal)
slider.isContinuous = false
view.addSubview(slider)
slider.addTarget(self, action: #selector(sliderValueChanged), for: UIControlEvents.valueChanged)
}
func sliderValueChanged(sender: UISlider){
print(sender.value)
}
func makeHighlightedImage() -> (UIImage) {
let size = CGFloat(thumbSize)
let highlightedStateImage = UIImage.createThumbImage(size: size, color: highlightedColour)
return (highlightedStateImage)
}
func makeDefaultImage() -> (UIImage) {
let size = CGFloat(thumbSize)
let defaultStateImage = UIImage.createThumbImage(size: size, color: defaultColour)
return (defaultStateImage)
}
}
Extension translated to Swift 3
import UIKit
extension UIImage {
class func createThumbImage(size: CGFloat, color: UIColor) -> UIImage {
let layerFrame = CGRect(x: 0, y: 0, width: size, height: size)
let shapeLayer = CAShapeLayer()
shapeLayer.path = CGPath(ellipseIn: layerFrame.insetBy(dx: 1, dy: 1), transform: nil)
shapeLayer.fillColor = color.cgColor
shapeLayer.strokeColor = color.withAlphaComponent(0.65).cgColor
let layer = CALayer.init()
layer.frame = layerFrame
layer.addSublayer(shapeLayer)
return self.imageFromLayer(layer: layer)
}
class func imageFromLayer(layer: CALayer) -> UIImage {
UIGraphicsBeginImageContextWithOptions(layer.frame.size, false, UIScreen.main.scale)
layer.render(in: UIGraphicsGetCurrentContext()!)
let outputImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return outputImage!
}
}
I came up with an answer similar to MCMatan's but without the need for a UIImage extension:
func setThumbnailImage(for slider: UISlider, thumbnailHeight: CGFloat, thumbnailColor: UIColor) {
let cornerRadius: CGFloat = 25
let rect = CGRect(x: 0, y: 0, width: thumbnailHeight, height: thumbnailHeight)
let size = CGSize(width: thumbnailHeight, height: thumbnailHeight)
UIGraphicsBeginImageContextWithOptions(size, false, 0)
// this is what makes it round
UIBezierPath(roundedRect: rect, cornerRadius: cornerRadius).addClip()
thumbnailColor.setFill()
UIRectFill(rect)
if let newImage = UIGraphicsGetImageFromCurrentImageContext() {
slider.setThumbImage(nil, for: .normal)
slider.setThumbImage(newImage, for: .normal)
}
UIGraphicsEndImageContext()
}
To use:
override func viewDidLoad() {
super.viewDidLoad()
setThumbnailImage(for: yourSlider, thumbnailHeight: 20.0, thumbnailColor: UIColor.red)
}
or
func someActionJustFinishedNowUpdateThumbnail() {
setThumbnailImage(for: yourSlider, thumbnailHeight: 40.0, thumbnailColor: UIColor.blue)
}
or
func setThumbnailToSliderHeight() {
let sliderHeight = yourSlider.frame.size.height
setThumbnailImage(for: yourSlider, thumbnailHeight: sliderHeight, thumbnailColor: UIColor.purple)
}