Search code examples
ioscore-graphics

Eraser tool for an iOS app


I'm trying to make an eraser tool and I wrote this:

class EraserTool: Tool {
    var context: CGContext?

    fileprivate unowned let delegate: ToolDelegate
    fileprivate unowned let imageView: UIImageView

    fileprivate var currentPoint = CGPoint()

    required init(imageView: UIImageView, delegate: ToolDelegate) {
        self.delegate = delegate
        self.imageView = imageView
    }

    func toucheBegin(at point: CGPoint) {
        guard let image = imageView.image else {
            printErr("can't erase, image nil")

            return
        }

        UIGraphicsBeginImageContext(image.size)
        guard let context = UIGraphicsGetCurrentContext() else {
            printErr("can't get current context")

            return
        }
        context.setBlendMode(.clear)
        context.setLineCap(.round)
        context.setLineWidth(CGFloat(delegate.toolWidthPercent) / imageView.imageScale * 100)
        self.context = context

        delegate.saveImageBeforeEditing()

        currentPoint = point
    }

    func toucheMoved(to point: CGPoint) {
        guard let context = context else {
            printErr("no context")
            return
        }

        imageView.erase(from: currentPoint, to: point, context: context)

        currentPoint = point
    }

    func toucheEnd(at point: CGPoint) {
        guard let context = context else {return}

        imageView.erase(from: currentPoint, to: point, context: context)

        UIGraphicsEndImageContext()
    }
}


extension UIImageView {
    func erase(from startPoint: CGPoint, to endPoint: CGPoint, context: CGContext) {
        guard let image = image else {
            printErr("can't erase, image nil")

            return
        }

        image.draw(at: CGPoint())

        context.beginPath()

        context.move(to: startPoint)
        context.addLine(to: endPoint)

        context.strokePath()

        self.image = UIGraphicsGetImageFromCurrentImageContext()
    }
}

It works fine for small images, but when I run it for larger pictures - it processes very slow. Am I doing something wrong? Are there some ways to improve efficiency?


Solution

  • The only thing I can advise you - reduce the quality / size of your image. That worked for me.

    extension UIImage {
        func resizedToScreenDimensionsCopy() -> UIImage? {
            let screenScale = UIScreen.main.scale
    
            let ratio = (size.width * size.height) / (UIScreen.main.bounds.width * screenScale * UIScreen.main.bounds.height * screenScale * 3)
    
            if ratio < 1 {
                return self
            }
    
            let newImageSize = CGSize(width: size.width / ratio, height: size.height / ratio)
    
            UIGraphicsBeginImageContext(newImageSize)
            defer {
                UIGraphicsEndImageContext()
            }
            draw(in: CGRect(origin: CGPoint(), size: newImageSize))
            return UIGraphicsGetImageFromCurrentImageContext()
        }
    }