Quartz2D之截取图片指定区域

/ 0

1

有些时候我们需要处理拍照后的图片截取操作,比如在上传用户头像的时候,用户上传的图片可能是很长的一张图片,但这样最后显示的头像就不会太完美。我们需要在用户上传头像的时候,有一个可以截取图片的功能。

需求分析

从上图直观看出,随着用户的触摸移动,会创建一个透明遮罩来表示需要截取的区域,然后截取了区域里的图片。因为我这里demo只是为了掩饰,imageView和控制器view约束尺寸一样了,会有放大效果,裁剪图片是正确的。

实现步骤

随着用户触摸移动,根据这个我们可以使用pan手势来实现,手势会有状态,我们这里可以记录开始触摸时的点,触摸中改变的点,触摸结束时的点。然后根据这些点,可以很容易的计算出我们需要裁剪的区域。

黑色透明区域,只是一个普通的,黑色透明的view,在用户移动手指时,动态计算截取区域并设置这个view的frame值。当松手的时候,裁剪图片并清除view的frame值即可。

代码实现

@IBOutlet weak var imageView: UIImageView!
private var startPoint = CGPointZero

override func viewDidLoad() {
    super.viewDidLoad()
    
    // 给当前控制器view添加一个pan手势
    let panGesture = UIPanGestureRecognizer(target: self, action: #selector(didPan(_:)))
    view.addGestureRecognizer(panGesture)
}

@objc private func didPan(pan: UIPanGestureRecognizer) {
    
    let endPoint = pan.locationInView(view)
    let clipRect = CGRect(origin: startPoint, size: CGSize(width: endPoint.x - startPoint.x, height: endPoint.y - startPoint.y))
    
    if pan.state == .Began {
        startPoint = pan.locationInView(view)
    } else if pan.state == .Changed {
        clipRectView.frame = clipRect
    } else if pan.state == .Ended {
        
        // 开启位图上下文,并裁剪指定区域
        UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, false, 0)
        let ctx = UIGraphicsGetCurrentContext()!
        let rectPath = UIBezierPath(rect: clipRect)
        rectPath.addClip()
        imageView.layer.renderInContext(ctx)
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        
        // 再次开启位图上下文,绘制裁剪后的图片
        UIGraphicsBeginImageContextWithOptions(clipRect.size, false, 0)
        image.drawAtPoint(CGPoint(x: -startPoint.x, y: -startPoint.y))
        let newImage = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        
        imageView.image = newImage
        clipRectView.frame = CGRectZero
    }
}

/// 裁剪区域黑色透明遮罩
private lazy var clipRectView: UIView = {
    let clipRectView = UIView()
    clipRectView.backgroundColor = UIColor(white: 0, alpha: 0.5)
    self.view.addSubview(clipRectView)
    return clipRectView
}()

最终newImage就是我们需要的图片,demo下载:clipPhotoDemo