IOS Swift Flood fill algorithm

I created this extension to "fill the bucket" (fill fill) touch points:

extension UIImageView {

    func bucketFill(startPoint: CGPoint, newColor: UIColor) {
        var newRed, newGreen, newBlue, newAlpha: CUnsignedChar

        let pixelsWide = CGImageGetWidth(self.image!.CGImage)
        let pixelsHigh = CGImageGetHeight(self.image!.CGImage)
        let rect = CGRect(x:0, y:0, width:Int(pixelsWide), height:Int(pixelsHigh))

        let bitmapBytesPerRow = Int(pixelsWide) * 4


        var context = self.image!.createARGBBitmapContext()

        //Clear the context
        CGContextClearRect(context, rect)

        // Draw the image to the bitmap context. Once we draw, the memory
        // allocated for the context for rendering will then contain the
        // raw image data in the specified color space.
        CGContextDrawImage(context, rect, self.image!.CGImage)

        var data = CGBitmapContextGetData(context)
        var dataType = UnsafeMutablePointer<UInt8>(data)

        let newColorRef = CGColorGetComponents(newColor.CGColor)
        if(CGColorGetNumberOfComponents(newColor.CGColor) == 2) {
            newRed = CUnsignedChar(newColorRef[0] * 255) // CUnsignedChar
            newGreen = CUnsignedChar(newColorRef[0] * 255)
            newBlue = CUnsignedChar(newColorRef[0] * 255)
            newAlpha = CUnsignedChar(newColorRef[1])
        } else {
            newRed = CUnsignedChar(newColorRef[0] * 255)
            newGreen = CUnsignedChar(newColorRef[1] * 255)
            newBlue = CUnsignedChar(newColorRef[2] * 255)
            newAlpha = CUnsignedChar(newColorRef[3])
        }
        let newColorStr = ColorRGB(red: newRed, green: newGreen, blue: newBlue)

        var stack = Stack()

        let offset = 4*((Int(pixelsWide) * Int(startPoint.y)) + Int(startPoint.x))
        //let alpha = dataType[offset]
        let startRed: UInt8 = dataType[offset+1]
        let startGreen: UInt8 = dataType[offset+2]
        let startBlue: UInt8 = dataType[offset+3]

        stack.push(startPoint)

        while(!stack.isEmpty()) {

            let point: CGPoint = stack.pop() as! CGPoint

            let offset = 4*((Int(pixelsWide) * Int(point.y)) + Int(point.x))
            let alpha = dataType[offset]
            let red: UInt8 = dataType[offset+1]
            let green: UInt8 = dataType[offset+2]
            let blue: UInt8 = dataType[offset+3]

            if (red == newRed && green == newGreen && blue == newBlue) {
                continue
            }

            if (red.absoluteDifference(startRed) < 4 && green.absoluteDifference(startGreen) < 4 && blue.absoluteDifference(startBlue) < 4) {

                dataType[offset] = 255
                dataType[offset + 1] = newRed
                dataType[offset + 2] = newGreen
                dataType[offset + 3] = newBlue

                if (point.x > 0) {
                    stack.push(CGPoint(x: point.x - 1, y: point.y))
                }

                if (point.x < CGFloat(pixelsWide)) {
                    stack.push(CGPoint(x: point.x + 1, y: point.y))
                }

                if (point.y > 0) {
                    stack.push(CGPoint(x: point.x, y: point.y - 1))
                }

                if (point.y < CGFloat(pixelsHigh)) {
                    stack.push(CGPoint(x: point.x, y: point.y + 1))
                }
            } else {

            }
        }

        let colorSpace = CGColorSpaceCreateDeviceRGB()
        let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.PremultipliedFirst.rawValue)
        let finalContext = CGBitmapContextCreate(data, pixelsWide, pixelsHigh, CLong(8), CLong(bitmapBytesPerRow), colorSpace, bitmapInfo)

        let imageRef = CGBitmapContextCreateImage(finalContext)
        self.image = UIImage(CGImage: imageRef, scale: self.image!.scale,orientation: self.image!.imageOrientation)
    }
}

Now I would like to improve performance. How can I make this algorithm work faster? The UInt8.absoluteDifference extension is my attempt to include almost the same colors in the fill of the fill, and it works, but it can really be improved, and I know this, but I don’t know how to do it.

extension UInt8 {

    func absoluteDifference(subtrahend: UInt8) -> UInt8 {
        if (self > subtrahend) {
            return self - subtrahend;
        } else {
            return subtrahend - self;
        }
    }
}

My Stack Class:

class Stack {
    var count: Int = 0
    var head: Node = Node()

    init() {
    }

    func isEmpty() -> Bool {
        return self.count == 0
    }

    func push(value: Any) {
        if isEmpty() {
            self.head = Node()
        }

        var node = Node(value: value)
        node.next = self.head
        self.head = node
        self.count++
    }

    func pop() -> Any? {
        if isEmpty() {
            return nil
        }

        var node = self.head
        self.head = node.next!
        self.count--

        return node.value
    }
}

thanks for the help

+4
source share

All Articles