'How can I apply a filters to ONE image?

I'm beginner in Swift and make an app "Photo Editor". I have a problem. I need to apply a some filters to ONE image. I have four sliders(sepia, contrast, brightness, saturation ) and one image. I want to apply all this filters to my image.

I try to change my logic in code, but I have the same problem

@objc func sliderValueDidChange(sender: UISlider!) 

    if sender.tag == 0 {
            let originalCIImage = CIImage(image: self.image!)
            let value = sender.value
            self.sepiaLabelValue.text = String(Int(value*100))
            if  let sepiaCIImage = sepiaFilter(originalCIImage!, intensity: Double(value)) {
                filteredImage = sepiaCIImage
                self.imageView.image = UIImage(ciImage: sepiaCIImage)
            }

        } else if sender.tag == 1 {
            let originalCIImage = CIImage(image: self.image!)
            let value = sender.value
            self.brightnessValue.text = String(Int(value*100))
            if let brightnessCIImage = brightnessFilter(originalCIImage!, intensity: Double(value)) {
                filteredImage = brightnessCIImage
                self.imageView.image = UIImage(ciImage:brightnessCIImage)
            }

        } else if sender.tag == 2 {
            let originalCIImage = CIImage(image: self.image!)
            let value = sender.value
            self.contrastLabel.text = String(Int(value*100))
            let contrastCIImage = contrastFilter(originalCIImage!, intensity: Double(value))
            self.imageView.image = UIImage(ciImage:contrastCIImage!)

        } else if sender.tag == 3 {
            let originalCIImage = CIImage(image: self.image!)
            let value = sender.value
            self.saturationValue.text = String(Int(value*100))
            let saturationCIImage = saturationFilter(originalCIImage!, intensity: Double(value))
            self.imageView.image = UIImage(ciImage:saturationCIImage!)
        }
}


func sepiaFilter(_ input: CIImage, intensity: Double) -> CIImage?
    {
        let sepiaFilter = CIFilter(name:"CISepiaTone")
        sepiaFilter?.setValue(input, forKey: kCIInputImageKey)
        sepiaFilter?.setValue(intensity, forKey: kCIInputIntensityKey)
        return sepiaFilter?.outputImage
    }

    func brightnessFilter(_ input: CIImage, intensity: Double) -> CIImage? {
        let brightnessFilter = CIFilter(name: "CIColorControls")
        brightnessFilter?.setValue(input, forKey: kCIInputImageKey)
        brightnessFilter?.setValue(intensity, forKey: kCIInputBrightnessKey)
        return brightnessFilter?.outputImage
    }

    func contrastFilter(_ input: CIImage, intensity: Double) -> CIImage? {
        let contrastFilter = CIFilter(name: "CIColorControls")
        contrastFilter?.setValue(input, forKey: kCIInputImageKey)
        contrastFilter?.setValue(intensity, forKey: kCIInputContrastKey)
        return contrastFilter?.outputImage
    }

    func saturationFilter(_ input: CIImage, intensity: Double) -> CIImage? {
        let saturationFilter = CIFilter(name: "CIColorControls")
        saturationFilter?.setValue(input, forKey: kCIInputImageKey)
        saturationFilter?.setValue(intensity, forKey: kCIInputSaturationKey)
        return saturationFilter?.outputImage
    }

When I apply first filter and then next filter, the value of first filter is established to begin state. How can I apply all filters to my image?



Solution 1:[1]

As Gigi said, the trick is to always apply both filters to the image when a value changed. This should do the trick:

let colorControlsFilter = CIFilter(name: "CIColorControls")!
let sepiaFilter = CIFilter(name:"CISepiaTone")!


@objc func sliderValueDidChange(sender: UISlider!) {
    switch sender.tag {
    case 0: 
        let value = sender.value
        self.sepiaLabelValue.text = String(Int(value*100))
        self.sepiaFilter.setValue(value, forKey: kCIInputIntensityKey)
    case 1:
        let value = sender.value
        self.brightnessValue.text = String(Int(value*100))
        self.colorControlsFilter.setValue(value, forKey: kCIInputBrightnessKey)
    case 2:
        let value = sender.value
        self.contrastLabel.text = String(Int(value*100))
        self.colorControlsFilter.setValue(value, forKey: kCIInputContrastKey)
    case 3:
        let value = sender.value
        self.saturationValue.text = String(Int(value*100))
        self.colorControlsFilter.setValue(value, forKey: kCIInputSaturationKey)
    default: pass
    }

    self.updateImage()
}

func updateImage() {
    let originalCIImage = CIImage(image: self.image!)
    // first apply color controls (contrast, brightness, saturation), then sepia
    self.colorControlsFilter.setValue(originalCIImage, forKey: kCIInputImageKey)
    self.sepiaFilter.setValue(self.colorControlsFilter.outputImage, forKey: kCIInputImageKey)
    self.imageView.image = UIImage(ciImage: self.sepiaFilter.outputImage!)
} 

Solution 2:[2]

let context = CIContext(options: nil)      
  if let currentFilter = CIFilter(name: "CISepiaTone") {
                    let beginImage = CIImage(image: image!)
                    currentFilter.setValue(beginImage, forKey: kCIInputImageKey)
                    
                    
                    if let output = currentFilter.outputImage {
                        if let cgimg = context.createCGImage(output, from: output.extent) {
                            filteredImage = UIImage(cgImage: cgimg)
                        }
               }
        }

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Frank Schlegel
Solution 2 Balasingam Sanjeevan