0

I'm trying to apply the next code to colorize an image taken from the gallery:

func zoeFilter() -> UIImage? {
        let brownColor = UIColor (red: 128/255, green: 0, blue: 0, alpha: 1)
        let colorRect = CGRect (origin: .zero, size: self.size)

        let renderer = UIGraphicsImageRenderer (bounds: colorRect)

        let brownColoredImage = renderer.image { ctx in
            ctx.cgContext.setFillColor(greyColor.cgColor)
            ctx.fill(colorRect)
        }

        let outBrown0Image = renderer.image { ctx in
            ctx.cgContext.setFillColor(UIColor.white.cgColor)
            ctx.fill(colorRect)
            self.draw(in: colorRect, blendMode: .normal, alpha: 1)
            brownColoredImage.draw(in: colorRect, blendMode: .colorDodge, alpha: 1)
        }

        let outBrownImage = renderer.image { ctx in
            self.draw(in: colorRect, blendMode: .normal, alpha: 1)
            outBrown0Image.draw(in: colorRect, blendMode: .multiply, alpha: 1)
        }

        return outBrownImage
    }

But it takes around 14 seconds processing the image which is not pretty good to user experience...

Do you know how can I get the same result but accelerating the image processing?

Do you have any tip?

Thanks in advance!

FINAL SOLUTION

func zoeFilter() -> UIImage? {
        let inImage = CIImage (image: self)

        let SRGBImage = inImage?.applyingFilter("CILinearToSRGBToneCurve")

        let brownColor = CIColor (red: 128/255, green: 0, blue: 0, alpha: 1)
        let colorRect = CGRect (origin: .zero, size: self.size)

        dynamic let colorFilter = CIFilter(name: "CIConstantColorGenerator")
        dynamic let colorizeFilter = CIFilter (name: "CIColorDodgeBlendMode")
        dynamic let multiplyFilter = CIFilter (name: "CIMultiplyBlendMode")

        colorFilter?.setValue(brownColor, forKey: kCIInputColorKey)
        let brownSolidImage = colorFilter?.outputImage?.cropped(to: colorRect)

        colorizeFilter?.setValue(SRGBImage, forKey: kCIInputBackgroundImageKey)
        colorizeFilter?.setValue(brownSolidImage, forKey: kCIInputImageKey)
        let outBrown0Image = colorizeFilter?.outputImage

        multiplyFilter?.setValue(SRGBImage, forKey: kCIInputBackgroundImageKey)
        multiplyFilter?.setValue(outBrown0Image, forKey: kCIInputImageKey)
        let outBrownImage = multiplyFilter?.outputImage

        let linearImage = outBrownImage?.applyingFilter("CISRGBToneCurveToLinear")

        let cgImage = CIContext().createCGImage(linearImage!, from: linearImage!.extent)
        return UIImage (cgImage: cgImage!)
    }
0

1 Answer 1

1

The easiest thing to try is to collapse those 3 renderer.image { ... } calls into a single call. You should be able to just move the contents of the second 2 calls into the first. This should make a huge performance difference.

Beyond that, do you really need to do this on a full sized image from the camera roll? If not, adjust the size you set on the renderer before doing all of the unneeded rendering.

Generally when you are trying to do filtering like this in a high performance way, you would use CoreImage. With that you can process images at very high speed. Like 60 fps for filtering live video.

I'd start with looking at Apple's built in filter list: https://developer.apple.com/library/archive/documentation/GraphicsImaging/Reference/CoreImageFilterReference/index.html

Here is a pretty good example of how to use a filter: https://www.hackingwithswift.com/articles/204/how-to-use-core-image-filters-the-type-safe-way

If you find that you can't combine the built in filters to get your effect(s), you can always write pretty simple Metal backed filters of your own: https://flexmonkey.blogspot.com/2016/01/metal-kernel-functions-as-core-image.html

Sign up to request clarification or add additional context in comments.

2 Comments

You're right! I was focus using UIGraphics and the key has been changing to CoreImage. I've edited just posting the final code based on your answer. Thank you very much!
Glad I could help!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.