Reputation: 194
I have image in UIImageView where user can draw specific selection on image and I want to cut or extract specific area from that image with the help of path drawn on image.
Source Image:
head selected: tail selected:
I have follow this Image background removal, but I want to make selection on image and extract selection.
here is my code:
class RemoveBackgroundViewController: UIViewController {
var theDrawingView: DrawingImageView = DrawingImageView(frame: .zero)
var imgView = UIImageView()
var drawView = DrawView()
override func viewDidLoad() {
super.viewDidLoad()
guard let img = UIImage(named: "IMG_4725") else {
fatalError("Could not load image!!!")
}
view.backgroundColor = .white
imgView.backgroundColor = .yellow
imgView.image = img
imgView.contentMode = .scaleAspectFit
theDrawingView.contentMode = .scaleAspectFit
theDrawingView.image = img
let btn = UIButton()
btn.setTitle("Apply Mask", for: [])
btn.setTitleColor(.white, for: .normal)
btn.setTitleColor(.gray, for: .highlighted)
btn.backgroundColor = .red
let btn1 = UIButton()
btn1.setTitle("extract", for: [])
btn1.setTitleColor(.white, for: .normal)
btn1.setTitleColor(.gray, for: .highlighted)
btn1.backgroundColor = .red
let btn2 = UIButton()
btn2.setTitle("cancel", for: [])
btn2.setTitleColor(.white, for: .normal)
btn2.setTitleColor(.gray, for: .highlighted)
btn2.backgroundColor = .red
[btn2, btn1, btn, theDrawingView, imgView, drawView].forEach {
$0.translatesAutoresizingMaskIntoConstraints = false
view.addSubview($0)
}
drawView.isHidden = true
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
// center the drawing image view, with 20-pts on each side
// sized proportionally to the loaded image
// theDrawingView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
theDrawingView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
// theDrawingView.centerXAnchor.constraint(equalTo: g.centerXAnchor),
theDrawingView.centerYAnchor.constraint(equalTo: g.centerYAnchor),
theDrawingView.widthAnchor.constraint(equalToConstant: 250),
theDrawingView.heightAnchor.constraint(equalTo: theDrawingView.widthAnchor, multiplier: 1.0),
// constrain button above the image
btn.bottomAnchor.constraint(equalTo: theDrawingView.topAnchor, constant: -8.0),
btn.centerXAnchor.constraint(equalTo: g.centerXAnchor),
btn.widthAnchor.constraint(equalToConstant: 160.0),
// constrain btn1 above the btn
btn1.bottomAnchor.constraint(equalTo: btn.topAnchor, constant: -8.0),
btn1.centerXAnchor.constraint(equalTo: g.centerXAnchor),
btn1.widthAnchor.constraint(equalToConstant: 160.0),
// constrain btn1 above the btn
btn2.bottomAnchor.constraint(equalTo: btn1.topAnchor, constant: -8.0),
btn2.centerXAnchor.constraint(equalTo: g.centerXAnchor),
btn2.widthAnchor.constraint(equalToConstant: 160.0),
imgView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -8.0),
imgView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 8.0),
imgView.heightAnchor.constraint(equalToConstant: 250),
imgView.widthAnchor.constraint(equalToConstant: 250),
// drawView.leadingAnchor.constraint(equalTo: theDrawingView.leadingAnchor),
// drawView.topAnchor.constraint(equalTo: theDrawingView.topAnchor),
// drawView.trailingAnchor.constraint(equalTo: theDrawingView.trailingAnchor),
// drawView.bottomAnchor.constraint(equalTo: theDrawingView.bottomAnchor),
])
btn.addTarget(self, action: #selector(self.toggleActivity(_:)), for: .touchUpInside)
btn1.addTarget(self, action: #selector(self.cropActivity(_:)), for: .touchUpInside)
btn2.addTarget(self, action: #selector(self.cancelActivity(_:)), for: .touchUpInside)
}
@objc func cropActivity(_ sender: Any) {
if let imag = theDrawingView.cropImage() {
imgView.image = imag
} else {
print("\n...Ooops...\n")
}
// drawView.maskPreview(previewView: imgView)
}
@objc func cancelActivity(_ sender: Any) {
self.dismiss(animated: true, completion: nil)
}
@objc func toggleActivity(_ sender: Any) {
guard let btn = sender as? UIButton else { return }
if theDrawingView.isDrawing {
theDrawingView.applyMask() //sPath: drawView.bezierPath)
btn.setTitle("Draw More", for: [])
} else {
theDrawingView.drawMore()
btn.setTitle("Apply Mask", for: [])
}
}
}
class DrawingImageView: UIImageView {
var path = UIBezierPath()
var previousTouchPoint = CGPoint.zero
var shapeLayer = CAShapeLayer()
var isDrawing: Bool = true
var isClear: Bool = false {
didSet {
updateView()
}
}
override func awakeFromNib() {
super.awakeFromNib()
setupView()
}
override init(frame: CGRect) {
super.init(frame: frame)
setupView()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
func updateView() {
self.shapeLayer.shadowOffset = .init(width: 1, height: 1)
self.shapeLayer.shadowColor = UIColor.black.cgColor
self.shapeLayer.shadowOpacity = 1
self.shapeLayer.lineWidth = 20
self.shapeLayer.lineCap = .round
self.shapeLayer.strokeColor = isClear ? UIColor.clear.cgColor : UIColor.blue.cgColor
self.shapeLayer.opacity = 0.3
self.isUserInteractionEnabled = true
}
func setupView() {
self.layer.addSublayer(shapeLayer)
updateView()
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesBegan(touches, with: event)
if !isDrawing { return }
if let location = touches.first?.location(in: self){
previousTouchPoint = location
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesMoved(touches, with: event)
if !isDrawing { return }
if let location = touches.first?.location(in: self) {
path.move(to: location)
path.addLine(to: previousTouchPoint)
previousTouchPoint = location
shapeLayer.path = path.cgPath
}
}
func applyMask(sPath: UIBezierPath? = nil) -> Void {
shapeLayer.opacity = 1.0
// use it as a mask
layer.mask = shapeLayer
isDrawing = false
}
func drawMore() -> Void {
// remove the mask
layer.mask = nil
// set opacity back to 0.3
shapeLayer.opacity = 0.3
// add shapeLayer back as sublayer
self.layer.addSublayer(shapeLayer)
isDrawing = true
}
func cropImage() -> UIImage? {
shapeLayer.fillColor = UIColor.black.cgColor
layer.mask = shapeLayer
layer.masksToBounds = true
UIGraphicsBeginImageContextWithOptions(bounds.size, false, 1)
layer.render(in: UIGraphicsGetCurrentContext()!)
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
}
var bezierPath = UIBezierPath()
override func setNeedsLayout() {
bezierPath.reversing()
let shapeLayer = CAShapeLayer()
shapeLayer.frame = self.bounds
shapeLayer.path = bezierPath.cgPath
self.layer.mask = shapeLayer
self.layer.masksToBounds = true
}
}
Input: Output:
let vc = RemoveBackgroundViewController()
vc .modalPresentationStyle = .overFullScreen
self.present(vc, animated: true, completion: nil)
Upvotes: 1
Views: 162
Reputation: 194
Finally, I found a library ZImageCropper, which is quiet helpful to select desired part of image with random shape or selection on image.
Thanks
Upvotes: 0