Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Draw a line that acts like an eraser Swift3

Tags:

swift

swift3

I'm making a simple drawing program drawing some lines in a UIView (canvas in the code below). This works fine.

Now I want to be able to rub out these lines like an eraser.

I don't just want to draw white over it because there is a background image behind the canvas view which the user can change, so drawing the background image into the view also wouldn't work because they can change it half way through drawing.

How can I draw a path that acts like an eraser on all the existing paths?

Here's my current drawing code

func drawLine(fromPoint start: CGPoint, toPoint end:CGPoint, color: UIColor, width: CGFloat, canvas: UIView) 
{
    let line = CAShapeLayer()
    let linePath = UIBezierPath()

    linePath.move(to: start)
    linePath.addLine(to: end)

    line.path = linePath.cgPath
    line.strokeColor = color.cgColor
    line.lineWidth = width
    line.lineJoin = kCALineJoinRound

    canvas.layer.addSublayer(line)
}

Thanks!

like image 960
Jonathan Plackett Avatar asked Sep 02 '25 18:09

Jonathan Plackett


2 Answers

OK I've figured this out. instead of using CAShapeLayers to create the path it needs to be drawn in the graphics context. Here is the code I'm using now. canvas is now a UIImageView instead of a UIView.

func drawLine(fromPoint start: CGPoint, toPoint end:CGPoint, color: UIColor, width: CGFloat)
{
    //get the current graphics context based on the frame of the view I want to draw in.
    UIGraphicsBeginImageContextWithOptions(canvas.frame.size, false, 0.0);

    //draw the current image (all the lines drawn so far) into the view so we aren't just drawing new lines each time and losing the old ones
    canvas.image?.draw(in: canvas.bounds)
    //FYI - canvas is defined at the top of the class as a UIImageView

    //get the current graphics context
    if let context = UIGraphicsGetCurrentContext()
    {
        //set line color and other properties
        context.setLineWidth(width)
        context.setStrokeColor(color.cgColor)
        context.setLineCap(CGLineCap.round)

        //add the line itself
        context.move(to: start)
        context.addLine(to: end)

        //this is a check to see if the last component of the color is 0 which means the color is transparent, if it is, we use CGBlendMode.clear which acts like an eraser. you could have a toggle for this instead if you like but I decided to set the color to one without alpha as the way of setting the eraser.
        if(currentColor.cgColor.components?.count == 4 && currentColor.cgColor.components?.last == 0)
        {
            context.setBlendMode(CGBlendMode.clear)
        }
        else
        {
            context.setBlendMode(CGBlendMode.normal)
        }


        //stroke the path so it actually appears
        context.strokePath()

        //set the canvas image to the new image we just created
        canvas.image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

    }


}
like image 58
Jonathan Plackett Avatar answered Sep 04 '25 12:09

Jonathan Plackett


you can use stroke with mode CGBlendMode.clear for erase and CGBlendMode.normal for Drawing

linePath.stroke(with: CGBlendMode.clear, alpha: 1.0)
like image 37
Abdelahad Darwish Avatar answered Sep 04 '25 11:09

Abdelahad Darwish