Search code examples
iosswiftxcodecifiltercolormatrix

Brightness, saturation and contrast with ColorMatrix in Swift


I'm trying to re-write my Android app in Swift to launch for iOS and I've reached a wall...

The Android app is about image processing based on a summation of ColorMatrix... i.e. the next matrix to make a grey scale image:

float[] bwMatrix = {
                0f, 1f, 0f, 0f, 0f,
                0f, 1f, 0f, 0f, 0f,
                0f, 1f, 0f, 0f, 0f,
                0f, 0f, 0f, 1f, 0f,
                0f, 0f, 0f, 0f, 1f};

Now, trying to apply same concept with Swift my code is as follows:

import UIKit

dynamic var colorMatrix : CIFilter?

class editionViewController: UIViewController {

    @IBOutlet weak var editionImageView: UIImageView!

    override func viewDidLoad() {
        super.viewDidLoad()

        let fileManager = FileManager.default
        let imagePath = (self.getDirectoryPath() as NSURL).appendingPathComponent("editionImg0.png")
        let urlString: String = imagePath!.absoluteString
        if fileManager.fileExists(atPath: urlString) {
            let originalImage = UIImage (contentsOfFile: urlString)
            let liaImage = originalImage?.liaFilter()
            editionImageView.image = liaImage
        }
    }

    func getDirectoryPath() -> NSURL {
        let path = (NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString).appendingPathComponent("tempImages")
        let url = NSURL (string: path)
        return url!
    }
}

extension UIImage {
    //Lia filter
    func liaFilter() -> UIImage? {
        let inImage = CIImage(image: self)
        colorMatrix?.setDefaults()
        colorMatrix?.setValue(inImage, forKey: "inputImage")
        colorMatrix?.setValue(CIVector(x: 0, y: 1, z: 0, w: 0), forKey: "inputRvector")
        colorMatrix?.setValue(CIVector(x: 0, y: 1, z: 0, w: 0), forKey: "inputGvector")
        colorMatrix?.setValue(CIVector(x: 0, y: 1, z: 0, w: 0), forKey: "inputBvector")
        colorMatrix?.setValue(CIVector(x: 0, y: 0, z: 0, w: 1), forKey: "inputAvector")
        let outCIImage = (colorMatrix?.outputImage)
        return UIImage (ciImage: outCIImage!) //HERE is the crash
        /*
        if let outCIImage = colorMatrix?.outputImage {
            return UIImage (ciImage: outCIImage)
        }
        return nil
        */
    }
}

But app always crash with the next error:

enter image description here

Thank you in advance!


Solution

  • The colorMatrix property is nil because you never initialized it properly.

    Delete dynamic var colorMatrix: CIFilter? from your controller and use the code below.

    class editionViewController: UIViewController {
    
        @IBOutlet weak var editionImageView: UIImageView!
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            if let image = UIImage(named: "myImage.png") {
                editionImageView.image = image.liaFilter()
            }
        }
    }
    
    extension UIImage {
        //Lia filter
        func liaFilter() -> UIImage {
            let inImage = CIImage(image: self)
    
            let rgbVector = CIVector(x: 0, y: 1, z: 0, w: 0)
            let aVector = CIVector(x: 0, y: 0, z: 0, w: 1)
    
            dynamic let colorMatrix = CIFilter(name: "CIColorMatrix")
    
            if colorMatrix != nil {
                colorMatrix?.setDefaults()
                colorMatrix?.setValue(inImage, forKey: kCIInputImageKey)
                colorMatrix?.setValue(rgbVector, forKey: "inputRVector")
                colorMatrix?.setValue(rgbVector, forKey: "inputGVector")
                colorMatrix?.setValue(rgbVector, forKey: "inputBVector")
                colorMatrix?.setValue(aVector, forKey: "inputAVector")
    
                if let output = colorMatrix?.outputImage, let cgImage = CIContext().createCGImage(output, from: output.extent) {
                    return UIImage(cgImage: cgImage)
                }
            }
    
            return self
        }
    }
    

    I fixed your UIImage extension method.

    I put the initializer for CIFilter in the Extension method so you don't have to hold a reference for it.

    image if project

    ViewController

    enter image description here

    Hope this help.