Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Saving UIImage with rounded corners and border with Swift

Tags:

ios

swift

uiimage

I am using imagePickerController to pick a picture form the users library. I need to save the picture within the app with rounded corners and a border. When I save the image, it saves the unaltered image. I'm assuming that I am only altering the view not the image itself. Is there a way to save the picture as what can be seen in the view?

@IBOutlet var imageViewer: UIImageView!

func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [NSObject : AnyObject]) {
    var imagePicked = info[UIImagePickerControllerOriginalImage] as UIImage
    imageViewer.layer.cornerRadius = 10.0
    imageViewer.clipsToBounds = true
    imageViewer.layer.frame = CGRectInset(imageViewer.layer.frame, 20, 20)
    imageViewer.layer.borderColor = UIColor.purpleColor().CGColor
    imageViewer.layer.borderWidth = 2.0
    imageViewer.image = imagePicked

Thank you for your help!

like image 327
jcrowson12 Avatar asked Jan 13 '15 20:01

jcrowson12


2 Answers

The basic operations you need to perform are:

  • Clip the drawing area to draw your image into without the corners
  • Draw the image
  • Configure the stroke colour etc
  • Then stroke the path used for clipping

    func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [NSObject : AnyObject]) {
      let borderWidth: CGFloat = 2.0
      let imagePicked = info[UIImagePickerControllerOriginalImage] as UIImage
    
      UIGraphicsBeginImageContextWithOptions(imageViewer.frame.size, false, 0)
    
      let path = UIBezierPath(roundedRect: CGRectInset(imageViewer.bounds, borderWidth / 2, borderWidth / 2), cornerRadius: 10.0)
      let context = UIGraphicsGetCurrentContext()
    
      CGContextSaveGState(context)
      // Clip the drawing area to the path
      path.addClip()
    
      // Draw the image into the context
      imagePicked.drawInRect(imageViewer.bounds)
      CGContextRestoreGState(context)
    
      // Configure the stroke
      UIColor.purpleColor().setStroke()
      path.lineWidth = borderWidth
    
      // Stroke the border
      path.stroke()
    
      roundedImage = UIGraphicsGetImageFromCurrentImageContext();
    
      UIGraphicsEndImageContext();
    
      view.addSubview(UIImageView(image: roundedImage))
    
      picker.dismissViewControllerAnimated(true, completion: nil)
    }
    

In the code above I've inset the path by half of the stroke width because the stroke is drawn along the center of the path, which means that one pixel will end up outside the path.

like image 57
Paul.s Avatar answered Oct 05 '22 22:10

Paul.s


Paul.s's answer is perfect (⬆️), but since it only captures the size of the UIImage relative to the UIImageView, it can reduce image quality. Assuming you want your image to maintains its aspect ratio within the frame and you want the border to lie directly on its edge, you can do this to maintain the size of the full image for saving:

func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [NSObject : AnyObject]) {

    let imagePicked = info[UIImagePickerControllerOriginalImage] as UIImage

    let borderWidth: CGFloat = 2.0
    let cornerRadius:CGFloat = 10.0

    // Create a multiplier to scale up the corner radius and border
    // width you decided on relative to the imageViewer frame such
    // that the corner radius and border width can be converted to
    // the UIImage's scale.
    let multiplier:CGFloat = imagePicked.size.height/imageViewer.frame.size.height > imagePicked.size.width/imageViewer.frame.size.width ?
       imagePicked.size.height/imageViewer.frame.size.height :
       imagePicked.size.width/imageViewer.frame.size.width

    let borderWidthMultiplied:CGFloat = borderWidth * multiplier
    let cornerRadiusMultiplied:CGFloat = cornerRadius * multiplier

    UIGraphicsBeginImageContextWithOptions(imagePicked.size, false, 0)

    let path = UIBezierPath(roundedRect: CGRectInset(CGRectMake(0, 0, imagePicked.size.width, imagePicked.size.height),
       borderWidthMultiplied / 2, borderWidthMultiplied / 2), cornerRadius: cornerRadiusMultiplied)

    let context = UIGraphicsGetCurrentContext()

    CGContextSaveGState(context)
    // Clip the drawing area to the path
    path.addClip()

    // Draw the image into the context
    imagePicked.drawInRect(CGRectMake(0, 0, imagePicked.size.width, imagePicked.size.height))
    CGContextRestoreGState(context)

    // Configure the stroke
    UIColor.blackColor().setStroke()
    path.lineWidth = borderWidthMultiplied

    // Stroke the border
    path.stroke()

    imageViewer.image = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    picker.dismissViewControllerAnimated(true, completion: nil)


}
like image 32
Lyndsey Scott Avatar answered Oct 06 '22 00:10

Lyndsey Scott