使用 Swift 保存带有圆角和边框的 UIImage
Saving UIImage with rounded corners and border with Swift
我正在使用 imagePickerController 从用户库中挑选图片。我需要在应用程序中保存带有圆角和边框的图片。当我保存图像时,它会保存未更改的图像。我假设我只是在改变视图而不是图像本身。有没有办法将图片保存为视图中可以看到的图片?
@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
感谢您的帮助!
您目前所做的是更改图像的呈现方式,而不更改图像本身。您需要创建一个位图上下文(参见 UIGraphicsBeginImageContextWithOptions
);设置一个圆形的矩形裁剪区域(CGContextEOClip
);将您的图像绘制到上下文中;最后,从上下文中获取 UIImage (UIGraphicsGetImageFromCurrentImageContext
)
您需要执行的基本操作是:
- 裁剪绘图区域以无角绘制图像
- 绘制图像
- 配置描边颜色等
然后描边用于裁剪的路径
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)
}
在上面的代码中,我将路径插入了笔画宽度的一半,因为笔画是沿着路径的中心绘制的,这意味着一个像素将在路径之外结束。
Paul.s的答案是完美的(⬆️),但由于它只捕获了UIImage
相对于UIImageView
的大小,因此会降低图像质量。假设您希望您的图像在框架内保持其纵横比并且您希望边框直接位于其边缘,您可以这样做以保持完整图像的大小以进行保存:
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)
}
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)
}
}
带边框的圆形 UIImage:
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()
}
}
您可以修改扩展方法来传递您需要的参数。
我正在使用 imagePickerController 从用户库中挑选图片。我需要在应用程序中保存带有圆角和边框的图片。当我保存图像时,它会保存未更改的图像。我假设我只是在改变视图而不是图像本身。有没有办法将图片保存为视图中可以看到的图片?
@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
感谢您的帮助!
您目前所做的是更改图像的呈现方式,而不更改图像本身。您需要创建一个位图上下文(参见 UIGraphicsBeginImageContextWithOptions
);设置一个圆形的矩形裁剪区域(CGContextEOClip
);将您的图像绘制到上下文中;最后,从上下文中获取 UIImage (UIGraphicsGetImageFromCurrentImageContext
)
您需要执行的基本操作是:
- 裁剪绘图区域以无角绘制图像
- 绘制图像
- 配置描边颜色等
然后描边用于裁剪的路径
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) }
在上面的代码中,我将路径插入了笔画宽度的一半,因为笔画是沿着路径的中心绘制的,这意味着一个像素将在路径之外结束。
Paul.s的答案是完美的(⬆️),但由于它只捕获了UIImage
相对于UIImageView
的大小,因此会降低图像质量。假设您希望您的图像在框架内保持其纵横比并且您希望边框直接位于其边缘,您可以这样做以保持完整图像的大小以进行保存:
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)
}
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)
}
}
带边框的圆形 UIImage:
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()
}
}
您可以修改扩展方法来传递您需要的参数。