从 UIImage 上的手绘线创建新的 UIImage - Swift
Create new UIImage from freehand drawn line over UIImage - Swift
这是我的第一个问题,所以如果我有任何不清楚的地方,请原谅。
我希望能够根据现有 UIImage1 上手绘形状的内容创建一个新的 UIImage2,以显示在现有 UIImage1 上。
视觉示例:UIImage1 是一张城市天际线照片。用户应该能够在摩天大楼周围绘制轮廓并创建一个新的 UIImage2,它将堆叠在 UIImage1 上显示,并能够编辑 UIImage 2(大小、颜色等)。
在 UIImage 上画线并不太难,但我还没有弄清楚如何在徒手绘制的形状中捕获 UIImage 的内容,从而创建一个单独的 UIImage。
非常感谢任何帮助。
如果要从屏蔽路径创建图像,您可以:
- 根据用户手势创建
UIBezierPath
;
- 将该贝塞尔曲线路径用作图像视图上的
CAShapeLayer
;
- 当用户手势完成后,删除那个形状层,但创建新的形状层并将其用作遮罩;和
- 使用
UIGraphicsImageRenderer
和 drawHierarchy
从蒙版图像视图创建图像以渲染图像中应捕获的任何内容。
例如:
class ViewController: UIViewController {
@IBOutlet weak var imageView: UIImageView!
private var path: UIBezierPath?
private var strokeLayer: CAShapeLayer?
@IBAction func didHandlePan(_ gesture: UIPanGestureRecognizer) {
let location = gesture.location(in: imageView)
switch gesture.state {
case .began:
path = UIBezierPath()
path?.move(to: location)
strokeLayer = CAShapeLayer()
imageView.layer.addSublayer(strokeLayer!)
strokeLayer?.strokeColor = #colorLiteral(red: 1, green: 0.1491314173, blue: 0, alpha: 1).cgColor
strokeLayer?.fillColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 0).cgColor
strokeLayer?.lineWidth = 5
strokeLayer?.path = path?.cgPath
case .changed:
path?.addLine(to: location)
strokeLayer?.path = path?.cgPath
case .cancelled, .ended:
// remove stroke from image view
strokeLayer?.removeFromSuperlayer()
strokeLayer = nil
// mask the image view
let mask = CAShapeLayer()
mask.fillColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1).cgColor
mask.strokeColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 0).cgColor
mask.lineWidth = 0
mask.path = path?.cgPath
imageView.layer.mask = mask
// get cropped image
let image = imageView?.snapshot
imageView.layer.mask = nil
// perhaps use that image?
imageView.image = image
default: break
}
}
}
顺便说一句,要从视图(屏蔽或其他方式)创建 UIImage
,您可以使用:
extension UIView {
var snapshot: UIImage {
UIGraphicsImageRenderer(bounds: bounds).image { _ in
drawHierarchy(in: bounds, afterScreenUpdates: true)
}
}
}
这会产生如下内容:
这是我的第一个问题,所以如果我有任何不清楚的地方,请原谅。
我希望能够根据现有 UIImage1 上手绘形状的内容创建一个新的 UIImage2,以显示在现有 UIImage1 上。
视觉示例:UIImage1 是一张城市天际线照片。用户应该能够在摩天大楼周围绘制轮廓并创建一个新的 UIImage2,它将堆叠在 UIImage1 上显示,并能够编辑 UIImage 2(大小、颜色等)。
在 UIImage 上画线并不太难,但我还没有弄清楚如何在徒手绘制的形状中捕获 UIImage 的内容,从而创建一个单独的 UIImage。
非常感谢任何帮助。
如果要从屏蔽路径创建图像,您可以:
- 根据用户手势创建
UIBezierPath
; - 将该贝塞尔曲线路径用作图像视图上的
CAShapeLayer
; - 当用户手势完成后,删除那个形状层,但创建新的形状层并将其用作遮罩;和
- 使用
UIGraphicsImageRenderer
和drawHierarchy
从蒙版图像视图创建图像以渲染图像中应捕获的任何内容。
例如:
class ViewController: UIViewController {
@IBOutlet weak var imageView: UIImageView!
private var path: UIBezierPath?
private var strokeLayer: CAShapeLayer?
@IBAction func didHandlePan(_ gesture: UIPanGestureRecognizer) {
let location = gesture.location(in: imageView)
switch gesture.state {
case .began:
path = UIBezierPath()
path?.move(to: location)
strokeLayer = CAShapeLayer()
imageView.layer.addSublayer(strokeLayer!)
strokeLayer?.strokeColor = #colorLiteral(red: 1, green: 0.1491314173, blue: 0, alpha: 1).cgColor
strokeLayer?.fillColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 0).cgColor
strokeLayer?.lineWidth = 5
strokeLayer?.path = path?.cgPath
case .changed:
path?.addLine(to: location)
strokeLayer?.path = path?.cgPath
case .cancelled, .ended:
// remove stroke from image view
strokeLayer?.removeFromSuperlayer()
strokeLayer = nil
// mask the image view
let mask = CAShapeLayer()
mask.fillColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1).cgColor
mask.strokeColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 0).cgColor
mask.lineWidth = 0
mask.path = path?.cgPath
imageView.layer.mask = mask
// get cropped image
let image = imageView?.snapshot
imageView.layer.mask = nil
// perhaps use that image?
imageView.image = image
default: break
}
}
}
顺便说一句,要从视图(屏蔽或其他方式)创建 UIImage
,您可以使用:
extension UIView {
var snapshot: UIImage {
UIGraphicsImageRenderer(bounds: bounds).image { _ in
drawHierarchy(in: bounds, afterScreenUpdates: true)
}
}
}
这会产生如下内容: