Reputation: 73
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!
Upvotes: 7
Views: 12231
Reputation: 579
Rounded UIImage with border:
extension UIImage {
func roundedWithStroke(width: CGFloat = 3) -> UIImage {
let imageLayer = CALayer()
let targetSize = CGSize(width: 29, height: 29)
imageLayer.frame = CGRect(x: 0, y: 0, width: targetSize.width, height: targetSize.height)
imageLayer.contents = cgImage
imageLayer.masksToBounds = true
imageLayer.cornerRadius = targetSize.width / 2
imageLayer.borderWidth = width
imageLayer.borderColor = UIColor.mainAccent.cgColor
UIGraphicsBeginImageContextWithOptions(targetSize, false, scale)
imageLayer.render(in: UIGraphicsGetCurrentContext()!)
let roundedImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return roundedImage ?? UIImage()
}
}
You can modify extension method to pass parameters that you need.
Upvotes: 5
Reputation: 4066
Swift 3:
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
if let image = info[UIImagePickerControllerEditedImage] as? UIImage {
let borderWidth: CGFloat = 2.0
UIGraphicsBeginImageContextWithOptions(myImageButton.frame.size, false, 0)
let path = UIBezierPath(roundedRect: myImageButton.bounds.insetBy(dx: borderWidth / 2, dy: borderWidth / 2), cornerRadius: 40.0)
let context = UIGraphicsGetCurrentContext()
context!.saveGState()
path.addClip()
image.draw(in: myImageButton.bounds)
UIColor.gray.setStroke()
path.lineWidth = borderWidth
path.stroke()
let roundedImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
myImageButton.setImage(roundedImage, for: .normal)
}
}
Upvotes: 0
Reputation: 37300
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)
}
Upvotes: 4
Reputation: 38728
The basic operations you need to perform are:
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.
Upvotes: 9
Reputation: 41246
What you are currently doing is changing the presentation of the image, without changing the image itself. You'll need to create a bitmap context (see UIGraphicsBeginImageContextWithOptions
); set up a round rect clipping region (CGContextEOClip
); draw your image into the context; and, finally, get a UIImage from the context (UIGraphicsGetImageFromCurrentImageContext
)
Upvotes: 1