从 UIView 蒙版中剪切 UIImage
Cut UIImage from UIView Mask
我有一个 UIView
在特定点具有特定半径的透明 maskLayer
。除此之外,我还有一个 UIImageView
和 UIPanGesture
& UIPinchGesture
.
现在我可以拖动或缩放 UIImageView
使其适合 UIView
遮罩部分。完成后,我需要从 UIImageView
获得关于透明部分的 UIImage
。
不知道怎么实现。
下面是在具有指定掩码 CGRect
和半径的 UIView
上创建叠加层的代码。
func createOverlay(frame: CGRect,
xOffset: CGFloat,
yOffset: CGFloat,
radius: CGFloat) -> UIView {
// Step 1
let overlayView = UIView(frame: frame)
overlayView.backgroundColor = UIColor.groupTableViewBackground.withAlphaComponent(0.8)
// Step 2
let path = CGMutablePath()
beizerPath = UIBezierPath(arcCenter: CGPoint(x: xOffset, y: yOffset + radius), radius: radius, startAngle: 0.0, endAngle: 2.0 * .pi, clockwise: false)
path.addArc(center: CGPoint(x: xOffset, y: yOffset),
radius: radius,
startAngle: 0.0,
endAngle: 2.0 * .pi,
clockwise: false)
path.addRect(CGRect(origin: .zero, size: overlayView.frame.size))
// Step 3
let maskLayer = CAShapeLayer()
maskLayer.backgroundColor = UIColor.black.cgColor
maskLayer.path = path
maskLayer.fillRule = .evenOdd
// Step 4
overlayView.layer.mask = maskLayer
overlayView.clipsToBounds = true
return overlayView
}
这里我收藏了UIBezierPath
以备不时之需!
然后,我尝试在 UIImage
上剪裁 UIBezierPath
,但这是 rect 的问题。因为,UIImageView
可以拖动和缩放所以它是 CGRect
变化。下面是我用来创建剪辑的代码。
extension UIImage {
func imageByApplyingClippingBezierPath(_ path: UIBezierPath) -> UIImage {
// Mask image using path
let maskedImage = imageByApplyingMaskingBezierPath(path)
// Crop image to frame of path
let croppedImage = UIImage(cgImage: maskedImage.cgImage!.cropping(to: path.bounds)!)
return croppedImage
}
func imageByApplyingMaskingBezierPath(_ path: UIBezierPath) -> UIImage {
// Define graphic context (canvas) to paint on
UIGraphicsBeginImageContext(size)
let context = UIGraphicsGetCurrentContext()!
context.saveGState()
// Set the clipping mask
path.addClip()
draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
let maskedImage = UIGraphicsGetImageFromCurrentImageContext()!
// Restore previous drawing context
context.restoreGState()
UIGraphicsEndImageContext()
return maskedImage
}
}
其他解决方案,我想拍摄完整视图的快照,然后从中删除 CGRect
。但我认为这不是正确的做法!
如果可能,最简单的方法是创建圆形视图并创建该视图的快照。检查以下解决方案:
func cutImageCircle(_ image: UIImage?, inFrame imageFrame: CGRect, contentMode: UIView.ContentMode = .scaleAspectFill, circle: (center: CGPoint, radius: CGFloat)) -> UIImage? {
guard let image = image else { return nil }
func generateSnapshotImage(ofView view: UIView, scale: CGFloat = 0.0) -> UIImage? {
UIGraphicsBeginImageContextWithOptions(view.bounds.size, false, scale)
defer { UIGraphicsEndImageContext() }
view.drawHierarchy(in: view.bounds, afterScreenUpdates: true)
return UIGraphicsGetImageFromCurrentImageContext()
}
let imageViewPanel = UIView(frame: CGRect(x: 0.0, y: 0.0, width: circle.radius*2.0, height: circle.radius*2.0))
imageViewPanel.clipsToBounds = true
imageViewPanel.layer.cornerRadius = circle.radius
let imageView = UIImageView(frame: {
var frame = imageFrame
frame.origin.x -= circle.center.x-circle.radius
frame.origin.y -= circle.center.y-circle.radius
return frame
}())
imageView.contentMode = contentMode
imageView.image = image
imageViewPanel.addSubview(imageView)
let cutImage = generateSnapshotImage(ofView: imageViewPanel, scale: 1.0)
return cutImage
}
您只需要计算圆心的位置和大小即可。我在其中添加了调整框架的选项,因此您可以控制输出图像的大小。这样您就可以提高拍摄图像的质量。
我有一个 UIView
在特定点具有特定半径的透明 maskLayer
。除此之外,我还有一个 UIImageView
和 UIPanGesture
& UIPinchGesture
.
现在我可以拖动或缩放 UIImageView
使其适合 UIView
遮罩部分。完成后,我需要从 UIImageView
获得关于透明部分的 UIImage
。
不知道怎么实现。
下面是在具有指定掩码 CGRect
和半径的 UIView
上创建叠加层的代码。
func createOverlay(frame: CGRect,
xOffset: CGFloat,
yOffset: CGFloat,
radius: CGFloat) -> UIView {
// Step 1
let overlayView = UIView(frame: frame)
overlayView.backgroundColor = UIColor.groupTableViewBackground.withAlphaComponent(0.8)
// Step 2
let path = CGMutablePath()
beizerPath = UIBezierPath(arcCenter: CGPoint(x: xOffset, y: yOffset + radius), radius: radius, startAngle: 0.0, endAngle: 2.0 * .pi, clockwise: false)
path.addArc(center: CGPoint(x: xOffset, y: yOffset),
radius: radius,
startAngle: 0.0,
endAngle: 2.0 * .pi,
clockwise: false)
path.addRect(CGRect(origin: .zero, size: overlayView.frame.size))
// Step 3
let maskLayer = CAShapeLayer()
maskLayer.backgroundColor = UIColor.black.cgColor
maskLayer.path = path
maskLayer.fillRule = .evenOdd
// Step 4
overlayView.layer.mask = maskLayer
overlayView.clipsToBounds = true
return overlayView
}
这里我收藏了UIBezierPath
以备不时之需!
然后,我尝试在 UIImage
上剪裁 UIBezierPath
,但这是 rect 的问题。因为,UIImageView
可以拖动和缩放所以它是 CGRect
变化。下面是我用来创建剪辑的代码。
extension UIImage {
func imageByApplyingClippingBezierPath(_ path: UIBezierPath) -> UIImage {
// Mask image using path
let maskedImage = imageByApplyingMaskingBezierPath(path)
// Crop image to frame of path
let croppedImage = UIImage(cgImage: maskedImage.cgImage!.cropping(to: path.bounds)!)
return croppedImage
}
func imageByApplyingMaskingBezierPath(_ path: UIBezierPath) -> UIImage {
// Define graphic context (canvas) to paint on
UIGraphicsBeginImageContext(size)
let context = UIGraphicsGetCurrentContext()!
context.saveGState()
// Set the clipping mask
path.addClip()
draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
let maskedImage = UIGraphicsGetImageFromCurrentImageContext()!
// Restore previous drawing context
context.restoreGState()
UIGraphicsEndImageContext()
return maskedImage
}
}
其他解决方案,我想拍摄完整视图的快照,然后从中删除 CGRect
。但我认为这不是正确的做法!
如果可能,最简单的方法是创建圆形视图并创建该视图的快照。检查以下解决方案:
func cutImageCircle(_ image: UIImage?, inFrame imageFrame: CGRect, contentMode: UIView.ContentMode = .scaleAspectFill, circle: (center: CGPoint, radius: CGFloat)) -> UIImage? {
guard let image = image else { return nil }
func generateSnapshotImage(ofView view: UIView, scale: CGFloat = 0.0) -> UIImage? {
UIGraphicsBeginImageContextWithOptions(view.bounds.size, false, scale)
defer { UIGraphicsEndImageContext() }
view.drawHierarchy(in: view.bounds, afterScreenUpdates: true)
return UIGraphicsGetImageFromCurrentImageContext()
}
let imageViewPanel = UIView(frame: CGRect(x: 0.0, y: 0.0, width: circle.radius*2.0, height: circle.radius*2.0))
imageViewPanel.clipsToBounds = true
imageViewPanel.layer.cornerRadius = circle.radius
let imageView = UIImageView(frame: {
var frame = imageFrame
frame.origin.x -= circle.center.x-circle.radius
frame.origin.y -= circle.center.y-circle.radius
return frame
}())
imageView.contentMode = contentMode
imageView.image = image
imageViewPanel.addSubview(imageView)
let cutImage = generateSnapshotImage(ofView: imageViewPanel, scale: 1.0)
return cutImage
}
您只需要计算圆心的位置和大小即可。我在其中添加了调整框架的选项,因此您可以控制输出图像的大小。这样您就可以提高拍摄图像的质量。