0

I am freehand drawing a UIBezierPath but now I want to be able to erase the lines I previously drawn. Does anyone have any suggestions on how to do that?

@objc private func didPanWhiteboard(_ gesture: UIPanGestureRecognizer) {
    let location = gesture.location(in: drawCanvasView)
    
    switch gesture.state {
        case .began:
            path = UIBezierPath()
            path.move(to: location)
            strokeLayer = CAShapeLayer()
            drawCanvasView.layer.addSublayer(strokeLayer)
            path.stroke(with: shouldErase ? .clear : .normal, alpha: 1.0)
            strokeLayer.strokeColor = toolColor.cgColor
            strokeLayer.fillColor = UIColor.clear.cgColor
            strokeLayer.lineWidth = toolWidth
            strokeLayer.path = path?.cgPath
        case .changed:
            path.addLine(to: location)
            strokeLayer.path = path.cgPath
        case .cancelled, .ended: drawLayers.append(strokeLayer)
        default: break
    }
}

this is how I draw the lines and so far for erasing I tried:

path.stroke(with: shouldErase ? .clear : .normal, alpha: 1.0)

but it dosen't seem to do anything when shouldErase is true.

EDIT: this is what I'd like to achieve:

https://i.stack.imgur.com/gMXsE.jpg

Feel free to suggest any kind of approach.

Lobont Andrei
  • 80
  • 1
  • 8
  • 4
    With setting clear on the stroke, aren't you just adding a transparent line, so it's normal that it doesn't create the effect you want? In case of erasing, what about using a mask when it's the case, that would hide the other drawing, or if you have a color background on your drawing, just use the background color instead of .clear. – Larme Jan 08 '22 at 14:09
  • 1
    This was from a while back, but you might find it helpful: https://stackoverflow.com/a/57415125/6257435 – DonMag Jan 08 '22 at 14:36
  • @Larme what you mean by using a mask to hide? – Lobont Andrei Jan 08 '22 at 16:49
  • @LobontAndrei I tink Larme means that you should just paint white or whatever your background color is on top of the existing path. So using `path.stroke(with: shouldErase ? .white : .normal, alpha: 1.0)` might fix your problem. – marosoaie Jan 10 '22 at 09:53
  • The idea is that I don't have a background color, I have an image in the back. Check the example video. – Lobont Andrei Jan 10 '22 at 09:57
  • 1
    @LobontAndrei - did you review the link from my comment? – DonMag Jan 10 '22 at 13:39

1 Answers1

2

I managed to solve this using CGContext.

@objc private func didPanWhiteboard(_ gesture: UIPanGestureRecognizer) {
    switch gesture.state {
        case .began:
            drawingState = .began
            lastPoint = gesture.location(in: drawingBoardImageView)
        case .changed:
            drawingState = .moved
            let currentPoint = gesture.location(in: drawingBoardImageView)
            drawLineFrom(fromPoint: lastPoint, toPoint: currentPoint)
            lastPoint = currentPoint
        case .cancelled, .ended:
            drawingState = .ended
            drawLineFrom(fromPoint: lastPoint, toPoint: lastPoint)
        default: break
    }
}


private func drawLineFrom(fromPoint: CGPoint, toPoint: CGPoint) {
    UIGraphicsBeginImageContext(drawingBoardImageView.frame.size)
    let context = UIGraphicsGetCurrentContext()
    tempImageView.image?.draw(in: CGRect(x: 0, y: 0, width: drawingBoardImageView.frame.size.width, height: drawingBoardImageView.frame.size.height))
    context?.move(to: fromPoint)
    context?.addLine(to: toPoint)
    context?.setLineCap(brush.lineCap)
    context?.setAlpha(brush.opacity)
    context?.setLineWidth(brush.width)
    context?.setStrokeColor(brush.color.cgColor)
    if shouldErase {
        context?.setBlendMode(.clear)
    } else {
        context?.setBlendMode(.normal)
    }
    context?.strokePath()
    guard let image = UIGraphicsGetImageFromCurrentImageContext() else { return }
    if drawingState == .ended {
        drawingUndoManager.registerForUndo(image)
    }
    tempImageView.image = image
    tempImageView.alpha = 1.0
    UIGraphicsEndImageContext()
}
Lobont Andrei
  • 80
  • 1
  • 8