Search code examples
swiftcore-graphics

Best way to erase on a picture in Swift?


I'm trying to make an app where I can erase the background from a picture that the user imports from "Camera roll".
So i was thinking of hand drawing a UIColor.clearColor on the UIImage. So i tried using Core Graphics to draw on my UIImage.
I tried initially to draw lines by:

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
    if let touch = touches.first {
        lastPoint = touch.locationInView(self)
    }
}

override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
    if let touch = touches.first {
        var newPoint = touch.locationInView(self)
        lines.append(Line(start: lastPoint, end: newPoint))
        lastPoint = newPoint
        self.setNeedsDisplay()
    }
}

override func drawRect(rect: CGRect) {
    imageToSend.drawAtPoint(CGPointZero)
    var context = UIGraphicsGetCurrentContext()
    CGContextBeginPath(context)
    for line in lines {
        CGContextMoveToPoint(context, line.start.x, line.start.y)
        CGContextAddLineToPoint(context, line.end.x, line.end.y)
    }
    CGContextSetStrokeColorWithColor(context, UIColor.redColor().CGColor) //tried with a red color here
    CGContextSetLineWidth(context, 80.0)
    CGContextSetLineCap(context, .Round)
}

The problem is that it was very laggy. The memory usage in Debug Session (of xCode) was very high as well as the CPU Usage.
Running the app on iPhone 6s.
So is there a better way to erase on a picture in Swift?
Another problem is that it creates lines, I would like it to be more smooth. But that's another problem


Solution

  • My assumption was the performance lags were caused by frequent calling of drawRect method - it does really huge work in your code snippet - render image. The idea was to overlay UIImageView containing the image with selection area drawing view, which does the drawing on top of the image view. So it should allow to separate area drawing from image drawing. As a result significantly consuming resources operation (image drawing) should be performed only once.

    I have implemented this, you can check out my sample app here:

    https://github.com/melifaro-/CutImageSampleApp

    enter image description here

    UPDATE

    That's easy to crop an image once you have bezier path corresponding to your image. You just need:

    let croppedCGImage =  CGImageCreateWithImageInRect(image.CGImage!, CGPathGetPathBoundingBox(path.CGPath));
    let croppedImage = UIImage(CGImage: croppedCGImage!)  
    

    I have pushed sample app changes as well. Hope it helps.